blob: 24c0f7ec03511b31791ad399f43e10e88b20fb6a [file] [log] [blame]
Thomas Gleixner8d7c56d2019-05-20 19:08:10 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
4 * Copyright (C) 1992 Eric Youngdale
5 * Simulate a host adapter with 2 disks attached. Do a lot of checking
6 * to make sure that we are not getting blocks mixed up, and PANIC if
7 * anything out of the ordinary is seen.
8 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9 *
Douglas Gilbert48e3bf12020-04-21 11:14:24 -040010 * Copyright (C) 2001 - 2020 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
Douglas Gilbert30f67482020-07-12 14:29:27 -040012 * For documentation see http://sg.danny.cz/sg/scsi_debug.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 */
14
Tomas Winklerc12879702015-07-28 16:54:20 +030015
16#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/module.h>
19
20#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040022#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/types.h>
25#include <linux/string.h>
26#include <linux/genhd.h>
27#include <linux/fs.h>
28#include <linux/init.h>
29#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/vmalloc.h>
31#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020032#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050034#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040035#include <linux/spinlock.h>
36#include <linux/interrupt.h>
37#include <linux/atomic.h>
38#include <linux/hrtimer.h>
Douglas Gilbert09ba24c2016-05-06 00:40:28 -040039#include <linux/uuid.h>
Christoph Hellwig6ebf1052016-09-11 19:35:39 +020040#include <linux/t10-pi.h>
Christoph Hellwig1442f762020-03-24 08:25:26 +010041#include <linux/msdos_partition.h>
Douglas Gilbert0c4bc912020-04-21 11:14:17 -040042#include <linux/random.h>
Douglas Gilbert87c715d2020-04-21 11:14:18 -040043#include <linux/xarray.h>
Douglas Gilberted9f3e22020-04-21 11:14:22 -040044#include <linux/prefetch.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050045
46#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090047
Martin K. Petersen44d92692009-10-15 14:45:27 -040048#include <asm/unaligned.h>
49
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090050#include <scsi/scsi.h>
51#include <scsi/scsi_cmnd.h>
52#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <scsi/scsi_host.h>
54#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090055#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040056#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040057#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Martin K. Petersenc6a44282009-01-04 03:08:19 -050059#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Douglas Gilbert773642d2016-04-25 12:16:28 -040062/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbert30f67482020-07-12 14:29:27 -040063#define SDEBUG_VERSION "0190" /* format to fit INQUIRY revision field */
64static const char *sdebug_version_date = "20200710";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040065
66#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050068/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040069#define NO_ADDITIONAL_SENSE 0x0
70#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050071#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040073#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050075#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040077#define INVALID_FIELD_IN_PARAM_LIST 0x26
Martin K. Petersen9447b6c2019-02-08 18:37:25 -050078#define WRITE_PROTECTED 0x27
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
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +090097#define UNALIGNED_WRITE_ASCQ 0x4
98#define WRITE_BOUNDARY_ASCQ 0x5
99#define READ_INVDATA_ASCQ 0x6
100#define READ_BOUNDARY_ASCQ 0x7
101#define INSUFF_ZONE_ASCQ 0xe
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500103/* Additional Sense Code Qualifier (ASCQ) */
104#define ACK_NAK_TO 0x3
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106/* Default values for driver parameters */
107#define DEF_NUM_HOST 1
108#define DEF_NUM_TGTS 1
109#define DEF_MAX_LUNS 1
110/* With these defaults, this driver will make 1 host with 1 target
111 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
112 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500113#define DEF_ATO 1
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500114#define DEF_CDB_LEN 10
Douglas Gilbertc2206092016-04-25 12:16:31 -0400115#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Douglas Gilbert9267e0e2020-04-22 19:42:17 +0900116#define DEF_DEV_SIZE_PRE_INIT 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117#define DEF_DEV_SIZE_MB 8
Douglas Gilbert9267e0e2020-04-22 19:42:17 +0900118#define DEF_ZBC_DEV_SIZE_MB 128
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_DIF 0
120#define DEF_DIX 0
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400121#define DEF_PER_HOST_STORE false
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500122#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500124#define DEF_FAKE_RW 0
125#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400126#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500127#define DEF_LBPU 0
128#define DEF_LBPWS 0
129#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600130#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500131#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400132#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500133#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134#define DEF_NUM_PARTS 0
135#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500136#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500137#define DEF_PHYSBLK_EXP 0
Lukas Herbolt86e68282017-01-26 10:00:37 +0100138#define DEF_OPT_XFERLEN_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400139#define DEF_PTYPE TYPE_DISK
Douglas Gilbert0c4bc912020-04-21 11:14:17 -0400140#define DEF_RANDOM false
Martin Pittd9867882012-09-06 12:04:33 +0200141#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400142#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500143#define DEF_SECTOR_SIZE 512
144#define DEF_UNMAP_ALIGNMENT 0
145#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400146#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
147#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500148#define DEF_VIRTUAL_GB 0
149#define DEF_VPD_USE_HOSTNO 1
150#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500151#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400152#define DEF_STATISTICS false
153#define DEF_SUBMIT_QUEUES 1
Douglas Gilbertfc136382020-07-24 11:55:31 -0400154#define DEF_TUR_MS_TO_READY 0
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400155#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400156#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900158/* Default parameters for ZBC drives */
159#define DEF_ZBC_ZONE_SIZE_MB 128
160#define DEF_ZBC_MAX_OPEN_ZONES 8
Damien Le Moalaa8fecf2020-04-22 19:42:19 +0900161#define DEF_ZBC_NR_CONV_ZONES 1
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900162
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400163#define SDEBUG_LUN_0_VAL 0
164
Douglas Gilbert773642d2016-04-25 12:16:28 -0400165/* bit mask values for sdebug_opts */
166#define SDEBUG_OPT_NOISE 1
167#define SDEBUG_OPT_MEDIUM_ERR 2
168#define SDEBUG_OPT_TIMEOUT 4
169#define SDEBUG_OPT_RECOVERED_ERR 8
170#define SDEBUG_OPT_TRANSPORT_ERR 16
171#define SDEBUG_OPT_DIF_ERR 32
172#define SDEBUG_OPT_DIX_ERR 64
173#define SDEBUG_OPT_MAC_TIMEOUT 128
174#define SDEBUG_OPT_SHORT_TRANSFER 0x100
175#define SDEBUG_OPT_Q_NOISE 0x200
176#define SDEBUG_OPT_ALL_TSF 0x400
177#define SDEBUG_OPT_RARE_TSF 0x800
178#define SDEBUG_OPT_N_WCE 0x1000
179#define SDEBUG_OPT_RESET_NOISE 0x2000
180#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800181#define SDEBUG_OPT_HOST_BUSY 0x8000
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400182#define SDEBUG_OPT_CMD_ABORT 0x10000
Douglas Gilbert773642d2016-04-25 12:16:28 -0400183#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
184 SDEBUG_OPT_RESET_NOISE)
185#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
186 SDEBUG_OPT_TRANSPORT_ERR | \
187 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800188 SDEBUG_OPT_SHORT_TRANSFER | \
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400189 SDEBUG_OPT_HOST_BUSY | \
190 SDEBUG_OPT_CMD_ABORT)
Douglas Gilbert3a90a632020-07-12 14:29:26 -0400191#define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
192 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Douglas Gilbertfd321192016-04-25 12:16:33 -0400194/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400195 * priority order. In the subset implemented here lower numbers have higher
196 * priority. The UA numbers should be a sequence starting from 0 with
197 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
198#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
199#define SDEBUG_UA_BUS_RESET 1
200#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500201#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500202#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500203#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
204#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
205#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400206
Douglas Gilbert773642d2016-04-25 12:16:28 -0400207/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 * sector on read commands: */
209#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500210#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Douglas Gilbertc4837392016-05-06 00:40:26 -0400212/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
213 * (for response) per submit queue at one time. Can be reduced by max_queue
214 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
215 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
216 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
217 * but cannot exceed SDEBUG_CANQUEUE .
218 */
219#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
220#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400221#define DEF_CMD_PER_LUN 255
222
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400223/* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
224#define F_D_IN 1 /* Data-in command (e.g. READ) */
225#define F_D_OUT 2 /* Data-out command (e.g. WRITE) */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400226#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
227#define F_D_UNKN 8
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400228#define F_RL_WLUN_OK 0x10 /* allowed with REPORT LUNS W-LUN */
229#define F_SKIP_UA 0x20 /* bypass UAs (e.g. INQUIRY command) */
230#define F_DELAY_OVERR 0x40 /* for commands like INQUIRY */
231#define F_SA_LOW 0x80 /* SA is in cdb byte 1, bits 4 to 0 */
232#define F_SA_HIGH 0x100 /* SA is in cdb bytes 8 and 9 */
233#define F_INV_OP 0x200 /* invalid opcode (not supported) */
234#define F_FAKE_RW 0x400 /* bypass resp_*() when fake_rw set */
235#define F_M_ACCESS 0x800 /* media access, reacts to SSU state */
236#define F_SSU_DELAY 0x1000 /* SSU command delay (long-ish) */
237#define F_SYNC_DELAY 0x2000 /* SYNCHRONIZE CACHE delay */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400238
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400239/* Useful combinations of the above flags */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400240#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
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400249#define SDEB_XA_NOT_IN_USE XA_MARK_1
250
Damien Le Moal64e14ec2020-04-22 19:42:21 +0900251/* Zone types (zbcr05 table 25) */
252enum sdebug_z_type {
253 ZBC_ZONE_TYPE_CNV = 0x1,
254 ZBC_ZONE_TYPE_SWR = 0x2,
255 ZBC_ZONE_TYPE_SWP = 0x3,
256};
257
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900258/* enumeration names taken from table 26, zbcr05 */
259enum sdebug_z_cond {
260 ZBC_NOT_WRITE_POINTER = 0x0,
261 ZC1_EMPTY = 0x1,
262 ZC2_IMPLICIT_OPEN = 0x2,
263 ZC3_EXPLICIT_OPEN = 0x3,
264 ZC4_CLOSED = 0x4,
265 ZC6_READ_ONLY = 0xd,
266 ZC5_FULL = 0xe,
267 ZC7_OFFLINE = 0xf,
268};
269
270struct sdeb_zone_state { /* ZBC: per zone state */
Damien Le Moal64e14ec2020-04-22 19:42:21 +0900271 enum sdebug_z_type z_type;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900272 enum sdebug_z_cond z_cond;
Damien Le Moal64e14ec2020-04-22 19:42:21 +0900273 bool z_non_seq_resource;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900274 unsigned int z_size;
275 sector_t z_start;
276 sector_t z_wp;
277};
Douglas Gilbertfd321192016-04-25 12:16:33 -0400278
279struct sdebug_dev_info {
280 struct list_head dev_list;
281 unsigned int channel;
282 unsigned int target;
283 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200284 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400285 struct sdebug_host_info *sdbg_host;
286 unsigned long uas_bm[1];
287 atomic_t num_in_q;
Douglas Gilbertfc136382020-07-24 11:55:31 -0400288 atomic_t stopped; /* 1: by SSU, 2: device start */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400289 bool used;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900290
291 /* For ZBC devices */
Damien Le Moal64e14ec2020-04-22 19:42:21 +0900292 enum blk_zoned_model zmodel;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900293 unsigned int zsize;
294 unsigned int zsize_shift;
295 unsigned int nr_zones;
Damien Le Moalaa8fecf2020-04-22 19:42:19 +0900296 unsigned int nr_conv_zones;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900297 unsigned int nr_imp_open;
298 unsigned int nr_exp_open;
299 unsigned int nr_closed;
300 unsigned int max_open;
Douglas Gilbertfc136382020-07-24 11:55:31 -0400301 ktime_t create_ts; /* time since bootup that this device was created */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900302 struct sdeb_zone_state *zstate;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400303};
304
305struct sdebug_host_info {
306 struct list_head host_list;
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400307 int si_idx; /* sdeb_store_info (per host) xarray index */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400308 struct Scsi_Host *shost;
309 struct device dev;
310 struct list_head dev_info_list;
311};
312
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400313/* There is an xarray of pointers to this struct's objects, one per host */
314struct sdeb_store_info {
315 rwlock_t macc_lck; /* for atomic media access on this store */
316 u8 *storep; /* user data storage (ram) */
317 struct t10_pi_tuple *dif_storep; /* protection info */
318 void *map_storep; /* provisioning map */
319};
320
Douglas Gilbertfd321192016-04-25 12:16:33 -0400321#define to_sdebug_host(d) \
322 container_of(d, struct sdebug_host_info, dev)
323
Douglas Gilbert10bde982018-01-10 16:57:31 -0500324enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
325 SDEB_DEFER_WQ = 2};
326
Douglas Gilbertfd321192016-04-25 12:16:33 -0400327struct sdebug_defer {
328 struct hrtimer hrt;
329 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400330 int sqa_idx; /* index of sdebug_queue array */
331 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
John Garryc10fa552020-07-09 20:23:20 +0800332 int hc_idx; /* hostwide tag index */
Douglas Gilbertc4837392016-05-06 00:40:26 -0400333 int issuing_cpu;
Douglas Gilbert10bde982018-01-10 16:57:31 -0500334 bool init_hrt;
335 bool init_wq;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400336 bool aborted; /* true when blk_abort_request() already called */
Douglas Gilbert10bde982018-01-10 16:57:31 -0500337 enum sdeb_defer_type defer_t;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400338};
339
340struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400341 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
342 * instance indicates this slot is in use.
343 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400344 struct sdebug_defer *sd_dp;
345 struct scsi_cmnd *a_cmnd;
346};
347
Douglas Gilbertc4837392016-05-06 00:40:26 -0400348struct sdebug_queue {
349 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
350 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
351 spinlock_t qc_lock;
352 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400353};
354
Douglas Gilbertc4837392016-05-06 00:40:26 -0400355static atomic_t sdebug_cmnd_count; /* number of incoming commands */
356static atomic_t sdebug_completions; /* count of deferred completions */
357static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
358static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
Douglas Gilbert3a90a632020-07-12 14:29:26 -0400359static atomic_t sdeb_inject_pending;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400360
Douglas Gilbertfd321192016-04-25 12:16:33 -0400361struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400362 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
363 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400364 u8 opcode; /* if num_attached > 0, preferred */
365 u16 sa; /* service action */
366 u32 flags; /* OR-ed set of SDEB_F_* */
367 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
368 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500369 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
370 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400371};
372
373/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500374enum sdeb_opcode_index {
375 SDEB_I_INVALID_OPCODE = 0,
376 SDEB_I_INQUIRY = 1,
377 SDEB_I_REPORT_LUNS = 2,
378 SDEB_I_REQUEST_SENSE = 3,
379 SDEB_I_TEST_UNIT_READY = 4,
380 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
381 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
382 SDEB_I_LOG_SENSE = 7,
383 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
384 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
385 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
386 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500387 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
388 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500389 SDEB_I_MAINT_IN = 14,
390 SDEB_I_MAINT_OUT = 15,
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400391 SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500392 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500393 SDEB_I_RESERVE = 18, /* 6, 10 */
394 SDEB_I_RELEASE = 19, /* 6, 10 */
395 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
396 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
397 SDEB_I_ATA_PT = 22, /* 12, 16 */
398 SDEB_I_SEND_DIAG = 23,
399 SDEB_I_UNMAP = 24,
Bart Van Asschec2085562019-02-08 13:21:27 -0800400 SDEB_I_WRITE_BUFFER = 25,
401 SDEB_I_WRITE_SAME = 26, /* 10, 16 */
402 SDEB_I_SYNC_CACHE = 27, /* 10, 16 */
403 SDEB_I_COMP_WRITE = 28,
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400404 SDEB_I_PRE_FETCH = 29, /* 10, 16 */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900405 SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */
406 SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */
407 SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500408};
409
Douglas Gilbertc4837392016-05-06 00:40:26 -0400410
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500411static const unsigned char opcode_ind_arr[256] = {
412/* 0x0; 0x0->0x1f: 6 byte cdbs */
413 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
414 0, 0, 0, 0,
415 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
416 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
417 SDEB_I_RELEASE,
418 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
419 SDEB_I_ALLOW_REMOVAL, 0,
420/* 0x20; 0x20->0x3f: 10 byte cdbs */
421 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
422 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400423 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500424 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
425/* 0x40; 0x40->0x5f: 10 byte cdbs */
426 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
427 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
Bart Van Asschec2085562019-02-08 13:21:27 -0800428 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500429 SDEB_I_RELEASE,
430 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400431/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
434 0, SDEB_I_VARIABLE_LEN,
435/* 0x80; 0x80->0x9f: 16 byte cdbs */
436 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400437 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
438 0, 0, 0, SDEB_I_VERIFY,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900439 SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
440 SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500441 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 -0500442/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
443 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
444 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500445 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
446 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500447 0, 0, 0, 0, 0, 0, 0, 0,
448 0, 0, 0, 0, 0, 0, 0, 0,
449/* 0xc0; 0xc0->0xff: vendor specific */
450 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
451 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
452 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
454};
455
Douglas Gilbert80c49562018-02-09 21:36:39 -0500456/*
457 * The following "response" functions return the SCSI mid-level's 4 byte
458 * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
459 * command completion, they can mask their return value with
460 * SDEG_RES_IMMED_MASK .
461 */
462#define SDEG_RES_IMMED_MASK 0x40000000
463
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500464static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
465static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
466static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
467static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
468static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
469static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
470static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
471static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
472static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500473static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500474static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
475static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
476static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
477static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
478static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500479static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
480static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400481static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500482static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
483static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500484static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500485static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert80c49562018-02-09 21:36:39 -0500486static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400487static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900488static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
489static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
490static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
491static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
492static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500493
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400494static int sdebug_do_add_host(bool mk_new_store);
495static int sdebug_add_host_helper(int per_host_idx);
496static void sdebug_do_remove_host(bool the_end);
497static int sdebug_add_store(void);
498static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
499static void sdebug_erase_all_stores(bool apart_from_first);
500
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500501/*
502 * The following are overflow arrays for cdbs that "hit" the same index in
503 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
504 * should be placed in opcode_info_arr[], the others should be placed here.
505 */
506static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500507 {0, 0x1a, 0, F_D_IN, NULL, NULL,
508 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
509};
510
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500511static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500512 {0, 0x15, 0, F_D_OUT, NULL, NULL,
513 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
514};
515
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500516static const struct opcode_info_t read_iarr[] = {
517 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500518 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500519 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500520 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500521 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500522 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500523 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500524 0xc7, 0, 0, 0, 0} },
525};
526
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500527static const struct opcode_info_t write_iarr[] = {
528 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
529 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
530 0, 0, 0, 0, 0, 0} },
531 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
532 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
533 0, 0, 0} },
534 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
535 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
536 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500537};
538
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400539static const struct opcode_info_t verify_iarr[] = {
540 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
541 NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
542 0, 0, 0, 0, 0, 0} },
543};
544
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500545static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500546 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
547 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500548 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500549};
550
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500551static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
552 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500553 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500554 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500555 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
556 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
557 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500558};
559
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500560static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500561 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500562 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500563 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500564 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500565 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500566 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500567};
568
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500569static const struct opcode_info_t write_same_iarr[] = {
570 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500571 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500572 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500573};
574
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500575static const struct opcode_info_t reserve_iarr[] = {
576 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500577 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
578};
579
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500580static const struct opcode_info_t release_iarr[] = {
581 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500582 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
583};
584
Douglas Gilbert80c49562018-02-09 21:36:39 -0500585static const struct opcode_info_t sync_cache_iarr[] = {
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400586 {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500587 {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
588 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */
589};
590
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400591static const struct opcode_info_t pre_fetch_iarr[] = {
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400592 {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400593 {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
594 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */
595};
596
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900597static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400598 {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900599 {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
600 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400601 {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900602 {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
603 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400604 {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900605 {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
606 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */
607};
608
609static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400610 {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900611 {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
612 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
613};
614
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500615
616/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
617 * plus the terminating elements for logic that scans this table such as
618 * REPORT SUPPORTED OPERATION CODES. */
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400619static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500620/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500621 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500622 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500623 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500624 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
625 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
626 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500627 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500628 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
629 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
630 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
631 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500632/* 5 */
633 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
634 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
635 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
636 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
637 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
638 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
639 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500640 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
641 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500642 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500643 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
644 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500645 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
646 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
647 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500648/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500649 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
650 resp_write_dt0, write_iarr, /* WRITE(16) */
651 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500652 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400653 {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500654 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500655 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
656 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
657 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
658 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500659 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
660 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
661 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500662 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
663 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
664 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
665 0xff, 0, 0xc7, 0, 0, 0, 0} },
666/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500667 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
668 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400669 {ARRAY_SIZE(verify_iarr), 0x8f, 0,
670 F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */
671 verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
672 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500673 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
674 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
675 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
676 0xff, 0xff} },
677 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
678 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500679 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
680 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500681 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
682 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500683 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
684 0} },
685/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500686 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
687 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500688 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
689 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
690 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
691 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
692 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
693 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500694 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500695 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500696/* 25 */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500697 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
698 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
699 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500700 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
701 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
702 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
703 0, 0, 0, 0, 0} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400704 {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500705 resp_sync_cache, sync_cache_iarr,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500706 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500707 0, 0, 0, 0} }, /* SYNC_CACHE (10) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500708 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500709 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500710 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400711 {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400712 resp_pre_fetch, pre_fetch_iarr,
713 {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
714 0, 0, 0, 0} }, /* PRE-FETCH (10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500715
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400716/* 30 */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400717 {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900718 resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
719 {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
720 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400721 {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900722 resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
723 {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
724 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
725/* sentinel */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500726 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
727 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
728};
729
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400730static int sdebug_num_hosts;
731static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400732static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500733static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400734static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert9267e0e2020-04-22 19:42:17 +0900735static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400736static int sdebug_dif = DEF_DIF;
737static int sdebug_dix = DEF_DIX;
738static int sdebug_dsense = DEF_D_SENSE;
739static int sdebug_every_nth = DEF_EVERY_NTH;
740static int sdebug_fake_rw = DEF_FAKE_RW;
741static unsigned int sdebug_guard = DEF_GUARD;
John Garryc10fa552020-07-09 20:23:20 +0800742static int sdebug_host_max_queue; /* per host */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400743static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
744static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400745static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Laurence Obermand9da8912018-02-03 13:38:35 -0500746static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
747static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400748static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400749static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400750static int sdebug_no_lun_0 = DEF_NO_LUN_0;
751static int sdebug_no_uld;
752static int sdebug_num_parts = DEF_NUM_PARTS;
753static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
754static int sdebug_opt_blks = DEF_OPT_BLKS;
755static int sdebug_opts = DEF_OPTS;
756static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100757static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400758static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400759static int sdebug_scsi_level = DEF_SCSI_LEVEL;
760static int sdebug_sector_size = DEF_SECTOR_SIZE;
Douglas Gilbertfc136382020-07-24 11:55:31 -0400761static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400762static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
763static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
764static unsigned int sdebug_lbpu = DEF_LBPU;
765static unsigned int sdebug_lbpws = DEF_LBPWS;
766static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
767static unsigned int sdebug_lbprz = DEF_LBPRZ;
768static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
769static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
770static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
771static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
772static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400773static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert0c4bc912020-04-21 11:14:17 -0400774static bool sdebug_random = DEF_RANDOM;
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400775static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400776static bool sdebug_removable = DEF_REMOVABLE;
777static bool sdebug_clustering;
778static bool sdebug_host_lock = DEF_HOST_LOCK;
779static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500780static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400781static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400782static bool have_dif_prot;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400783static bool write_since_sync;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400784static bool sdebug_statistics = DEF_STATISTICS;
Martin K. Petersen9447b6c2019-02-08 18:37:25 -0500785static bool sdebug_wp;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +0900786/* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
787static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
788static char *sdeb_zbc_model_s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Douglas Gilbertad0c7772020-08-21 00:22:49 -0400790enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
791 SAM_LUN_AM_FLAT = 0x1,
792 SAM_LUN_AM_LOGICAL_UNIT = 0x2,
793 SAM_LUN_AM_EXTENDED = 0x3};
794static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
795static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
796
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400797static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798static sector_t sdebug_capacity; /* in sectors */
799
800/* old BIOS stuff, kernel may get rid of them but some mode sense pages
801 may still need them */
802static int sdebug_heads; /* heads per disk */
803static int sdebug_cylinders_per; /* cylinders per surface */
804static int sdebug_sectors_per; /* sectors per cylinder */
805
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806static LIST_HEAD(sdebug_host_list);
807static DEFINE_SPINLOCK(sdebug_host_list_lock);
808
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400809static struct xarray per_store_arr;
810static struct xarray *per_store_ap = &per_store_arr;
811static int sdeb_first_idx = -1; /* invalid index ==> none created */
812static int sdeb_most_recent_idx = -1;
813static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
Martin K. Petersen44d92692009-10-15 14:45:27 -0400815static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400816static int num_aborts;
817static int num_dev_resets;
818static int num_target_resets;
819static int num_bus_resets;
820static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500821static int dix_writes;
822static int dix_reads;
823static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900825/* ZBC global data */
Damien Le Moal64e14ec2020-04-22 19:42:21 +0900826static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */
Damien Le Moal98e0a682020-04-22 19:42:20 +0900827static int sdeb_zbc_zone_size_mb;
Damien Le Moal380603a2020-04-22 19:42:18 +0900828static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
Damien Le Moalaa8fecf2020-04-22 19:42:19 +0900829static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900830
Douglas Gilbertc4837392016-05-06 00:40:26 -0400831static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
832static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834static DEFINE_RWLOCK(atomic_rw);
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400835static DEFINE_RWLOCK(atomic_rw2);
836
837static rwlock_t *ramdisk_lck_a[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400839static char sdebug_proc_name[] = MY_NAME;
840static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842static struct bus_type pseudo_lld_bus;
843
844static struct device_driver sdebug_driverfs_driver = {
845 .name = sdebug_proc_name,
846 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847};
848
849static const int check_condition_result =
850 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
851
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500852static const int illegal_condition_result =
853 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
854
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400855static const int device_qfull_result =
856 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
857
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400858static const int condition_met_result = SAM_STAT_CONDITION_MET;
859
Douglas Gilbertfd321192016-04-25 12:16:33 -0400860
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400861/* Only do the extra work involved in logical block provisioning if one or
862 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
863 * real reads and writes (i.e. not skipping them for speed).
864 */
865static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400866{
867 return 0 == sdebug_fake_rw &&
868 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
869}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400870
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400871static void *lba2fake_store(struct sdeb_store_info *sip,
872 unsigned long long lba)
Akinobu Mita14faa942013-09-18 21:27:24 +0900873{
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400874 struct sdeb_store_info *lsip = sip;
Akinobu Mita14faa942013-09-18 21:27:24 +0900875
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400876 lba = do_div(lba, sdebug_store_sectors);
877 if (!sip || !sip->storep) {
878 WARN_ON_ONCE(true);
879 lsip = xa_load(per_store_ap, 0); /* should never be NULL */
880 }
881 return lsip->storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900882}
883
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400884static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
885 sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900886{
Arnd Bergmann49413112015-11-20 17:38:28 +0100887 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900888
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400889 return sip->dif_storep + sector;
Akinobu Mita14faa942013-09-18 21:27:24 +0900890}
891
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900892static void sdebug_max_tgts_luns(void)
893{
894 struct sdebug_host_info *sdbg_host;
895 struct Scsi_Host *hpnt;
896
897 spin_lock(&sdebug_host_list_lock);
898 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
899 hpnt = sdbg_host->shost;
900 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400901 (sdebug_num_tgts > hpnt->this_id))
902 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900903 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400904 hpnt->max_id = sdebug_num_tgts;
905 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300906 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900907 }
908 spin_unlock(&sdebug_host_list_lock);
909}
910
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500911enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
912
913/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400914static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
915 enum sdeb_cmd_data c_d,
916 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500917{
918 unsigned char *sbuff;
919 u8 sks[4];
920 int sl, asc;
921
922 sbuff = scp->sense_buffer;
923 if (!sbuff) {
924 sdev_printk(KERN_ERR, scp->device,
925 "%s: sense_buffer is NULL\n", __func__);
926 return;
927 }
928 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
929 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400930 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500931 memset(sks, 0, sizeof(sks));
932 sks[0] = 0x80;
933 if (c_d)
934 sks[0] |= 0x40;
935 if (in_bit >= 0) {
936 sks[0] |= 0x8;
937 sks[0] |= 0x7 & in_bit;
938 }
939 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400940 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500941 sl = sbuff[7] + 8;
942 sbuff[7] = sl;
943 sbuff[sl] = 0x2;
944 sbuff[sl + 1] = 0x6;
945 memcpy(sbuff + sl + 4, sks, 3);
946 } else
947 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400948 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500949 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
950 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
951 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
952}
953
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400954static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900955{
956 unsigned char *sbuff;
957
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400958 sbuff = scp->sense_buffer;
959 if (!sbuff) {
960 sdev_printk(KERN_ERR, scp->device,
961 "%s: sense_buffer is NULL\n", __func__);
962 return;
963 }
964 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900965
Douglas Gilbert773642d2016-04-25 12:16:28 -0400966 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900967
Douglas Gilbert773642d2016-04-25 12:16:28 -0400968 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400969 sdev_printk(KERN_INFO, scp->device,
970 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
971 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900972}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
Douglas Gilbertfd321192016-04-25 12:16:33 -0400974static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500975{
976 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
977}
978
Nathan Chancellor6f4e6262019-02-07 09:07:20 -0700979static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
980 void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400982 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400983 if (0x1261 == cmd)
984 sdev_printk(KERN_INFO, dev,
985 "%s: BLKFLSBUF [0x1261]\n", __func__);
986 else if (0x5331 == cmd)
987 sdev_printk(KERN_INFO, dev,
988 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
989 __func__);
990 else
991 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
992 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 }
994 return -EINVAL;
995 /* return -ENOTTY; // correct return but upsets fdisk */
996}
997
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500998static void config_cdb_len(struct scsi_device *sdev)
999{
1000 switch (sdebug_cdb_len) {
1001 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
1002 sdev->use_10_for_rw = false;
1003 sdev->use_16_for_rw = false;
1004 sdev->use_10_for_ms = false;
1005 break;
1006 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
1007 sdev->use_10_for_rw = true;
1008 sdev->use_16_for_rw = false;
1009 sdev->use_10_for_ms = false;
1010 break;
1011 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
1012 sdev->use_10_for_rw = true;
1013 sdev->use_16_for_rw = false;
1014 sdev->use_10_for_ms = true;
1015 break;
1016 case 16:
1017 sdev->use_10_for_rw = false;
1018 sdev->use_16_for_rw = true;
1019 sdev->use_10_for_ms = true;
1020 break;
1021 case 32: /* No knobs to suggest this so same as 16 for now */
1022 sdev->use_10_for_rw = false;
1023 sdev->use_16_for_rw = true;
1024 sdev->use_10_for_ms = true;
1025 break;
1026 default:
1027 pr_warn("unexpected cdb_len=%d, force to 10\n",
1028 sdebug_cdb_len);
1029 sdev->use_10_for_rw = true;
1030 sdev->use_16_for_rw = false;
1031 sdev->use_10_for_ms = false;
1032 sdebug_cdb_len = 10;
1033 break;
1034 }
1035}
1036
1037static void all_config_cdb_len(void)
1038{
1039 struct sdebug_host_info *sdbg_host;
1040 struct Scsi_Host *shost;
1041 struct scsi_device *sdev;
1042
1043 spin_lock(&sdebug_host_list_lock);
1044 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1045 shost = sdbg_host->shost;
1046 shost_for_each_device(sdev, shost) {
1047 config_cdb_len(sdev);
1048 }
1049 }
1050 spin_unlock(&sdebug_host_list_lock);
1051}
1052
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001053static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
1054{
1055 struct sdebug_host_info *sdhp;
1056 struct sdebug_dev_info *dp;
1057
1058 spin_lock(&sdebug_host_list_lock);
1059 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
1060 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
1061 if ((devip->sdbg_host == dp->sdbg_host) &&
1062 (devip->target == dp->target))
1063 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
1064 }
1065 }
1066 spin_unlock(&sdebug_host_list_lock);
1067}
1068
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001069static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001071 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001072
1073 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1074 if (k != SDEBUG_NUM_UAS) {
1075 const char *cp = NULL;
1076
1077 switch (k) {
1078 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001079 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1080 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001081 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001082 cp = "power on reset";
1083 break;
1084 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001085 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1086 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001087 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001088 cp = "bus reset";
1089 break;
1090 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001091 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1092 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001093 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001094 cp = "mode parameters changed";
1095 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05001096 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001097 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1098 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001099 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05001100 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -05001101 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001102 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001103 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001104 TARGET_CHANGED_ASC,
1105 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001106 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001107 cp = "microcode has been changed";
1108 break;
1109 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001110 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001111 TARGET_CHANGED_ASC,
1112 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001113 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001114 cp = "microcode has been changed without reset";
1115 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001116 case SDEBUG_UA_LUNS_CHANGED:
1117 /*
1118 * SPC-3 behavior is to report a UNIT ATTENTION with
1119 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
1120 * on the target, until a REPORT LUNS command is
1121 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -04001122 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001123 * values as struct scsi_device->scsi_level.
1124 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001125 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001126 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001127 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001128 TARGET_CHANGED_ASC,
1129 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001130 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001131 cp = "reported luns data has changed";
1132 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001133 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04001134 pr_warn("unexpected unit attention code=%d\n", k);
1135 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001136 cp = "unknown";
1137 break;
1138 }
1139 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001140 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001141 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001142 "%s reports: Unit attention: %s\n",
1143 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return check_condition_result;
1145 }
1146 return 0;
1147}
1148
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001149/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001150static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 int arr_len)
1152{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001153 int act_len;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001154 struct scsi_data_buffer *sdb = &scp->sdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001156 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001158 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbert773642d2016-04-25 12:16:28 -04001159 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001160
1161 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
1162 arr, arr_len);
Bart Van Assche42d387b2019-02-08 13:25:00 -08001163 scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 return 0;
1166}
1167
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001168/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1169 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1170 * calls, not required to write in ascending offset order. Assumes resid
1171 * set to scsi_bufflen() prior to any calls.
1172 */
1173static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1174 int arr_len, unsigned int off_dst)
1175{
Damien Le Moal9237f042019-10-30 18:08:47 +09001176 unsigned int act_len, n;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001177 struct scsi_data_buffer *sdb = &scp->sdb;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001178 off_t skip = off_dst;
1179
1180 if (sdb->length <= off_dst)
1181 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001182 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001183 return DID_ERROR << 16;
1184
1185 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1186 arr, arr_len, skip);
1187 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
Bart Van Assche42d387b2019-02-08 13:25:00 -08001188 __func__, off_dst, scsi_bufflen(scp), act_len,
1189 scsi_get_resid(scp));
Damien Le Moal9237f042019-10-30 18:08:47 +09001190 n = scsi_bufflen(scp) - (off_dst + act_len);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001191 scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001192 return 0;
1193}
1194
1195/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1196 * 'arr' or -1 if error.
1197 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001198static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1199 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001201 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001203 if (scp->sc_data_direction != DMA_TO_DEVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001205
1206 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207}
1208
1209
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001210static char sdebug_inq_vendor_id[9] = "Linux ";
1211static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001212static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001213/* Use some locally assigned NAAs for SAS addresses. */
1214static const u64 naa3_comp_a = 0x3222222000000000ULL;
1215static const u64 naa3_comp_b = 0x3333333000000000ULL;
1216static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001218/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001219static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1220 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001221 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001222 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001224 int num, port_a;
1225 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001227 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 /* T10 vendor identifier field format (faked) */
1229 arr[0] = 0x2; /* ASCII */
1230 arr[1] = 0x1;
1231 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001232 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1233 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1235 num = 8 + 16 + dev_id_str_len;
1236 arr[3] = num;
1237 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001238 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001239 if (sdebug_uuid_ctl) {
1240 /* Locally assigned UUID */
1241 arr[num++] = 0x1; /* binary (not necessarily sas) */
1242 arr[num++] = 0xa; /* PIV=0, lu, naa */
1243 arr[num++] = 0x0;
1244 arr[num++] = 0x12;
1245 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1246 arr[num++] = 0x0;
1247 memcpy(arr + num, lu_name, 16);
1248 num += 16;
1249 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001250 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001251 arr[num++] = 0x1; /* binary (not necessarily sas) */
1252 arr[num++] = 0x3; /* PIV=0, lu, naa */
1253 arr[num++] = 0x0;
1254 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001255 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001256 num += 8;
1257 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001258 /* Target relative port number */
1259 arr[num++] = 0x61; /* proto=sas, binary */
1260 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1261 arr[num++] = 0x0; /* reserved */
1262 arr[num++] = 0x4; /* length */
1263 arr[num++] = 0x0; /* reserved */
1264 arr[num++] = 0x0; /* reserved */
1265 arr[num++] = 0x0;
1266 arr[num++] = 0x1; /* relative port A */
1267 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001268 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001269 arr[num++] = 0x61; /* proto=sas, binary */
1270 arr[num++] = 0x93; /* piv=1, target port, naa */
1271 arr[num++] = 0x0;
1272 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001273 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001274 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001275 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001276 arr[num++] = 0x61; /* proto=sas, binary */
1277 arr[num++] = 0x95; /* piv=1, target port group id */
1278 arr[num++] = 0x0;
1279 arr[num++] = 0x4;
1280 arr[num++] = 0;
1281 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001282 put_unaligned_be16(port_group_id, arr + num);
1283 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001284 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001285 arr[num++] = 0x61; /* proto=sas, binary */
1286 arr[num++] = 0xa3; /* piv=1, target device, naa */
1287 arr[num++] = 0x0;
1288 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001289 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001290 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001291 /* SCSI name string: Target device identifier */
1292 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1293 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1294 arr[num++] = 0x0;
1295 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001296 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001297 num += 12;
1298 snprintf(b, sizeof(b), "%08X", target_dev_id);
1299 memcpy(arr + num, b, 8);
1300 num += 8;
1301 memset(arr + num, 0, 4);
1302 num += 4;
1303 return num;
1304}
1305
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001306static unsigned char vpd84_data[] = {
1307/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1308 0x22,0x22,0x22,0x0,0xbb,0x1,
1309 0x22,0x22,0x22,0x0,0xbb,0x2,
1310};
1311
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001312/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001313static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001314{
1315 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1316 return sizeof(vpd84_data);
1317}
1318
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001319/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001320static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001321{
1322 int num = 0;
John Pittman91d4c752018-02-09 21:12:43 -05001323 const char *na1 = "https://www.kernel.org/config";
1324 const char *na2 = "http://www.kernel.org/log";
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001325 int plen, olen;
1326
1327 arr[num++] = 0x1; /* lu, storage config */
1328 arr[num++] = 0x0; /* reserved */
1329 arr[num++] = 0x0;
1330 olen = strlen(na1);
1331 plen = olen + 1;
1332 if (plen % 4)
1333 plen = ((plen / 4) + 1) * 4;
1334 arr[num++] = plen; /* length, null termianted, padded */
1335 memcpy(arr + num, na1, olen);
1336 memset(arr + num + olen, 0, plen - olen);
1337 num += plen;
1338
1339 arr[num++] = 0x4; /* lu, logging */
1340 arr[num++] = 0x0; /* reserved */
1341 arr[num++] = 0x0;
1342 olen = strlen(na2);
1343 plen = olen + 1;
1344 if (plen % 4)
1345 plen = ((plen / 4) + 1) * 4;
1346 arr[num++] = plen; /* length, null terminated, padded */
1347 memcpy(arr + num, na2, olen);
1348 memset(arr + num + olen, 0, plen - olen);
1349 num += plen;
1350
1351 return num;
1352}
1353
1354/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001355static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001356{
1357 int num = 0;
1358 int port_a, port_b;
1359
1360 port_a = target_dev_id + 1;
1361 port_b = port_a + 1;
1362 arr[num++] = 0x0; /* reserved */
1363 arr[num++] = 0x0; /* reserved */
1364 arr[num++] = 0x0;
1365 arr[num++] = 0x1; /* relative port 1 (primary) */
1366 memset(arr + num, 0, 6);
1367 num += 6;
1368 arr[num++] = 0x0;
1369 arr[num++] = 12; /* length tp descriptor */
1370 /* naa-5 target port identifier (A) */
1371 arr[num++] = 0x61; /* proto=sas, binary */
1372 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1373 arr[num++] = 0x0; /* reserved */
1374 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001375 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001376 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001377 arr[num++] = 0x0; /* reserved */
1378 arr[num++] = 0x0; /* reserved */
1379 arr[num++] = 0x0;
1380 arr[num++] = 0x2; /* relative port 2 (secondary) */
1381 memset(arr + num, 0, 6);
1382 num += 6;
1383 arr[num++] = 0x0;
1384 arr[num++] = 12; /* length tp descriptor */
1385 /* naa-5 target port identifier (B) */
1386 arr[num++] = 0x61; /* proto=sas, binary */
1387 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1388 arr[num++] = 0x0; /* reserved */
1389 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001390 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001391 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001392
1393 return num;
1394}
1395
1396
1397static unsigned char vpd89_data[] = {
1398/* from 4th byte */ 0,0,0,0,
1399'l','i','n','u','x',' ',' ',' ',
1400'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1401'1','2','3','4',
14020x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
14030xec,0,0,0,
14040x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
14050,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
14060x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
14070x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
14080x53,0x41,
14090x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
14100x20,0x20,
14110x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
14120x10,0x80,
14130,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
14140x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
14150x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
14160,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
14170x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
14180x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
14190,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
14200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14230x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
14240,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
14250xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
14260,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
14270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14370,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14380,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1439};
1440
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001441/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001442static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001443{
1444 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1445 return sizeof(vpd89_data);
1446}
1447
1448
1449static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001450 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1451 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1452 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1453 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001454};
1455
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001456/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001457static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001458{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001459 unsigned int gran;
1460
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001461 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001462
1463 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001464 if (sdebug_opt_xferlen_exp != 0 &&
1465 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1466 gran = 1 << sdebug_opt_xferlen_exp;
1467 else
1468 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001469 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001470
1471 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001472 if (sdebug_store_sectors > 0x400)
1473 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001474
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001475 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001476 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001477
Douglas Gilbert773642d2016-04-25 12:16:28 -04001478 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001479 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001480 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001481
1482 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001483 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001484 }
1485
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001486 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001487 if (sdebug_unmap_alignment) {
1488 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001489 arr[28] |= 0x80; /* UGAVALID */
1490 }
1491
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001492 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001493 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001494
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001495 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001496 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001497
1498 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001499
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001500 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501}
1502
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001503/* Block device characteristics VPD page (SBC-3) */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001504static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001505{
1506 memset(arr, 0, 0x3c);
1507 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001508 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1509 arr[2] = 0;
1510 arr[3] = 5; /* less than 1.8" */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001511 if (devip->zmodel == BLK_ZONED_HA)
1512 arr[4] = 1 << 4; /* zoned field = 01b */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001513
1514 return 0x3c;
1515}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001517/* Logical block provisioning VPD page (SBC-4) */
1518static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001519{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001520 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001521 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001522 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001523 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001524 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001525 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001526 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001527 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001528 if (sdebug_lbprz && scsi_debug_lbp())
1529 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1530 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1531 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1532 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001533 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001534}
1535
Douglas Gilbertd36da302020-04-22 19:42:15 +09001536/* Zoned block device characteristics VPD page (ZBC mandatory) */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001537static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
Douglas Gilbertd36da302020-04-22 19:42:15 +09001538{
1539 memset(arr, 0, 0x3c);
1540 arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1541 /*
1542 * Set Optimal number of open sequential write preferred zones and
1543 * Optimal number of non-sequentially written sequential write
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001544 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1545 * fields set to zero, apart from Max. number of open swrz_s field.
Douglas Gilbertd36da302020-04-22 19:42:15 +09001546 */
1547 put_unaligned_be32(0xffffffff, &arr[4]);
1548 put_unaligned_be32(0xffffffff, &arr[8]);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001549 if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001550 put_unaligned_be32(devip->max_open, &arr[12]);
1551 else
1552 put_unaligned_be32(0xffffffff, &arr[12]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001553 return 0x3c;
1554}
1555
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001557#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001559static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560{
1561 unsigned char pq_pdt;
John Pittman91d4c752018-02-09 21:12:43 -05001562 unsigned char *arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001563 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001564 int alloc_len, n, ret;
Douglas Gilbertd36da302020-04-22 19:42:15 +09001565 bool have_wlun, is_disk, is_zbc, is_disk_zbc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566
Douglas Gilbert773642d2016-04-25 12:16:28 -04001567 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001568 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1569 if (! arr)
1570 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001571 is_disk = (sdebug_ptype == TYPE_DISK);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001572 is_zbc = (devip->zmodel != BLK_ZONED_NONE);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001573 is_disk_zbc = (is_disk || is_zbc);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001574 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001575 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001576 pq_pdt = TYPE_WLUN; /* present, wlun */
1577 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1578 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001579 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001580 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 arr[0] = pq_pdt;
1582 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001583 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001584 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 return check_condition_result;
1586 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001587 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001588 char lu_id_str[6];
1589 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001591 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1592 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001593 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001594 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001595 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001596 (devip->target * 1000) + devip->lun);
1597 target_dev_id = ((host_no + 1) * 2000) +
1598 (devip->target * 1000) - 3;
1599 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001601 arr[1] = cmd[2]; /*sanity */
1602 n = 4;
1603 arr[n++] = 0x0; /* this page */
1604 arr[n++] = 0x80; /* unit serial number */
1605 arr[n++] = 0x83; /* device identification */
1606 arr[n++] = 0x84; /* software interface ident. */
1607 arr[n++] = 0x85; /* management network addresses */
1608 arr[n++] = 0x86; /* extended inquiry */
1609 arr[n++] = 0x87; /* mode page policy */
1610 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbertd36da302020-04-22 19:42:15 +09001611 if (is_disk_zbc) { /* SBC or ZBC */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001612 arr[n++] = 0x89; /* ATA information */
1613 arr[n++] = 0xb0; /* Block limits */
1614 arr[n++] = 0xb1; /* Block characteristics */
Douglas Gilbertd36da302020-04-22 19:42:15 +09001615 if (is_disk)
1616 arr[n++] = 0xb2; /* LB Provisioning */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001617 if (is_zbc)
Douglas Gilbertd36da302020-04-22 19:42:15 +09001618 arr[n++] = 0xb6; /* ZB dev. char. */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001619 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001620 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001622 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001624 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001626 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001627 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1628 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001629 lu_id_str, len,
1630 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001631 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1632 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001633 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001634 } else if (0x85 == cmd[2]) { /* Management network addresses */
1635 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001636 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001637 } else if (0x86 == cmd[2]) { /* extended inquiry */
1638 arr[1] = cmd[2]; /*sanity */
1639 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001640 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001641 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001642 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001643 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1644 else
1645 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001646 arr[5] = 0x7; /* head of q, ordered + simple q's */
1647 } else if (0x87 == cmd[2]) { /* mode page policy */
1648 arr[1] = cmd[2]; /*sanity */
1649 arr[3] = 0x8; /* number of following entries */
1650 arr[4] = 0x2; /* disconnect-reconnect mp */
1651 arr[6] = 0x80; /* mlus, shared */
1652 arr[8] = 0x18; /* protocol specific lu */
1653 arr[10] = 0x82; /* mlus, per initiator port */
1654 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1655 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001656 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001657 } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001658 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001659 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001660 put_unaligned_be16(n, arr + 2);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001661 } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001662 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001663 arr[3] = inquiry_vpd_b0(&arr[4]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001664 } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001665 arr[1] = cmd[2]; /*sanity */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001666 arr[3] = inquiry_vpd_b1(devip, &arr[4]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001667 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001668 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001669 arr[3] = inquiry_vpd_b2(&arr[4]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001670 } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1671 arr[1] = cmd[2]; /*sanity */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001672 arr[3] = inquiry_vpd_b6(devip, &arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001674 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001675 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 return check_condition_result;
1677 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001678 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001679 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001680 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001681 kfree(arr);
1682 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 }
1684 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001685 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1686 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 arr[3] = 2; /* response_data_format==2 */
1688 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001689 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001690 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001691 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001692 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001694 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001695 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1696 memcpy(&arr[16], sdebug_inq_product_id, 16);
1697 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001698 /* Use Vendor Specific area to place driver date in ASCII hex */
1699 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001701 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1702 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001703 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001704 if (is_disk) { /* SBC-4 no version claimed */
1705 put_unaligned_be16(0x600, arr + n);
1706 n += 2;
1707 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1708 put_unaligned_be16(0x525, arr + n);
1709 n += 2;
Douglas Gilbertd36da302020-04-22 19:42:15 +09001710 } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */
1711 put_unaligned_be16(0x624, arr + n);
1712 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001714 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001715 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001716 min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001717 kfree(arr);
1718 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719}
1720
Douglas Gilbert84905d32020-07-23 15:48:19 -04001721/* See resp_iec_m_pg() for how this data is manipulated */
Douglas Gilbertfd321192016-04-25 12:16:33 -04001722static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1723 0, 0, 0x0, 0x0};
1724
John Pittman91d4c752018-02-09 21:12:43 -05001725static int resp_requests(struct scsi_cmnd *scp,
1726 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001728 unsigned char *cmd = scp->cmnd;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001729 unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */
1730 bool dsense = !!(cmd[1] & 1);
1731 int alloc_len = cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 int len = 18;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001733 int stopped_state = atomic_read(&devip->stopped);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001735 memset(arr, 0, sizeof(arr));
Douglas Gilbert84905d32020-07-23 15:48:19 -04001736 if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */
1737 if (dsense) {
1738 arr[0] = 0x72;
1739 arr[1] = NOT_READY;
1740 arr[2] = LOGICAL_UNIT_NOT_READY;
1741 arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
1742 len = 8;
1743 } else {
1744 arr[0] = 0x70;
1745 arr[2] = NOT_READY; /* NO_SENSE in sense_key */
1746 arr[7] = 0xa; /* 18 byte sense buffer */
1747 arr[12] = LOGICAL_UNIT_NOT_READY;
1748 arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
1749 }
1750 } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1751 /* Information exceptions control mode page: TEST=1, MRIE=6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001752 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001753 arr[0] = 0x72;
1754 arr[1] = 0x0; /* NO_SENSE in sense_key */
1755 arr[2] = THRESHOLD_EXCEEDED;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001756 arr[3] = 0xff; /* Failure prediction(false) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001757 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001758 } else {
1759 arr[0] = 0x70;
1760 arr[2] = 0x0; /* NO_SENSE in sense_key */
1761 arr[7] = 0xa; /* 18 byte sense buffer */
1762 arr[12] = THRESHOLD_EXCEEDED;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001763 arr[13] = 0xff; /* Failure prediction(false) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001764 }
Douglas Gilbert84905d32020-07-23 15:48:19 -04001765 } else { /* nothing to report */
1766 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001767 len = 8;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001768 memset(arr, 0, len);
1769 arr[0] = 0x72;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001770 } else {
Douglas Gilbert84905d32020-07-23 15:48:19 -04001771 memset(arr, 0, len);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001772 arr[0] = 0x70;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001773 arr[7] = 0xa;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001774 }
1775 }
Douglas Gilbert84905d32020-07-23 15:48:19 -04001776 return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777}
1778
Douglas Gilbertfc136382020-07-24 11:55:31 -04001779static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001780{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001781 unsigned char *cmd = scp->cmnd;
Douglas Gilbertfc136382020-07-24 11:55:31 -04001782 int power_cond, want_stop, stopped_state;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001783 bool changing;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001784
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001785 power_cond = (cmd[4] & 0xf0) >> 4;
1786 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001787 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001788 return check_condition_result;
1789 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04001790 want_stop = !(cmd[4] & 1);
1791 stopped_state = atomic_read(&devip->stopped);
1792 if (stopped_state == 2) {
1793 ktime_t now_ts = ktime_get_boottime();
1794
1795 if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1796 u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1797
1798 if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1799 /* tur_ms_to_ready timer extinguished */
1800 atomic_set(&devip->stopped, 0);
1801 stopped_state = 0;
1802 }
1803 }
1804 if (stopped_state == 2) {
1805 if (want_stop) {
1806 stopped_state = 1; /* dummy up success */
1807 } else { /* Disallow tur_ms_to_ready delay to be overridden */
1808 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1809 return check_condition_result;
1810 }
1811 }
1812 }
1813 changing = (stopped_state != want_stop);
1814 if (changing)
1815 atomic_xchg(&devip->stopped, want_stop);
1816 if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001817 return SDEG_RES_IMMED_MASK;
1818 else
1819 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001820}
1821
FUJITA Tomonori28898872008-03-30 00:59:55 +09001822static sector_t get_sdebug_capacity(void)
1823{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001824 static const unsigned int gibibyte = 1073741824;
1825
1826 if (sdebug_virtual_gb > 0)
1827 return (sector_t)sdebug_virtual_gb *
1828 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001829 else
1830 return sdebug_store_sectors;
1831}
1832
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833#define SDEBUG_READCAP_ARR_SZ 8
John Pittman91d4c752018-02-09 21:12:43 -05001834static int resp_readcap(struct scsi_cmnd *scp,
1835 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836{
1837 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001838 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001840 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001841 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001843 if (sdebug_capacity < 0xffffffff) {
1844 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001845 put_unaligned_be32(capac, arr + 0);
1846 } else
1847 put_unaligned_be32(0xffffffff, arr + 0);
1848 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1850}
1851
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001852#define SDEBUG_READCAP16_ARR_SZ 32
John Pittman91d4c752018-02-09 21:12:43 -05001853static int resp_readcap16(struct scsi_cmnd *scp,
1854 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001855{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001856 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001857 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001858 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001859
Douglas Gilbert773642d2016-04-25 12:16:28 -04001860 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001861 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001862 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001863 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001864 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1865 put_unaligned_be32(sdebug_sector_size, arr + 8);
1866 arr[13] = sdebug_physblk_exp & 0xf;
1867 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001868
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001869 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001870 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001871 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1872 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1873 * in the wider field maps to 0 in this field.
1874 */
1875 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1876 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001877 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001878
Douglas Gilbert773642d2016-04-25 12:16:28 -04001879 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001880
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001881 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001882 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001883 arr[12] |= 1; /* PROT_EN */
1884 }
1885
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001886 return fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001887 min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001888}
1889
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001890#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1891
John Pittman91d4c752018-02-09 21:12:43 -05001892static int resp_report_tgtpgs(struct scsi_cmnd *scp,
1893 struct sdebug_dev_info *devip)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001894{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001895 unsigned char *cmd = scp->cmnd;
John Pittman91d4c752018-02-09 21:12:43 -05001896 unsigned char *arr;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001897 int host_no = devip->sdbg_host->shost->host_no;
1898 int n, ret, alen, rlen;
1899 int port_group_a, port_group_b, port_a, port_b;
1900
Douglas Gilbert773642d2016-04-25 12:16:28 -04001901 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001902 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1903 if (! arr)
1904 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001905 /*
1906 * EVPD page 0x88 states we have two ports, one
1907 * real and a fake port with no device connected.
1908 * So we create two port groups with one port each
1909 * and set the group with port B to unavailable.
1910 */
1911 port_a = 0x1; /* relative port A */
1912 port_b = 0x2; /* relative port B */
1913 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001914 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001915 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001916 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001917
1918 /*
1919 * The asymmetric access state is cycled according to the host_id.
1920 */
1921 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001922 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001923 arr[n++] = host_no % 3; /* Asymm access state */
1924 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001925 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001926 arr[n++] = 0x0; /* Active/Optimized path */
1927 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001928 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001929 put_unaligned_be16(port_group_a, arr + n);
1930 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001931 arr[n++] = 0; /* Reserved */
1932 arr[n++] = 0; /* Status code */
1933 arr[n++] = 0; /* Vendor unique */
1934 arr[n++] = 0x1; /* One port per group */
1935 arr[n++] = 0; /* Reserved */
1936 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001937 put_unaligned_be16(port_a, arr + n);
1938 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001939 arr[n++] = 3; /* Port unavailable */
1940 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001941 put_unaligned_be16(port_group_b, arr + n);
1942 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001943 arr[n++] = 0; /* Reserved */
1944 arr[n++] = 0; /* Status code */
1945 arr[n++] = 0; /* Vendor unique */
1946 arr[n++] = 0x1; /* One port per group */
1947 arr[n++] = 0; /* Reserved */
1948 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001949 put_unaligned_be16(port_b, arr + n);
1950 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001951
1952 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001953 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001954
1955 /*
1956 * Return the smallest value of either
1957 * - The allocated length
1958 * - The constructed command length
1959 * - The maximum array size
1960 */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001961 rlen = min_t(int, alen, n);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001962 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001963 min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001964 kfree(arr);
1965 return ret;
1966}
1967
Douglas Gilbertfd321192016-04-25 12:16:33 -04001968static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1969 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001970{
1971 bool rctd;
1972 u8 reporting_opts, req_opcode, sdeb_i, supp;
1973 u16 req_sa, u;
1974 u32 alloc_len, a_len;
1975 int k, offset, len, errsts, count, bump, na;
1976 const struct opcode_info_t *oip;
1977 const struct opcode_info_t *r_oip;
1978 u8 *arr;
1979 u8 *cmd = scp->cmnd;
1980
1981 rctd = !!(cmd[2] & 0x80);
1982 reporting_opts = cmd[2] & 0x7;
1983 req_opcode = cmd[3];
1984 req_sa = get_unaligned_be16(cmd + 4);
1985 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001986 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001987 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1988 return check_condition_result;
1989 }
1990 if (alloc_len > 8192)
1991 a_len = 8192;
1992 else
1993 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001994 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001995 if (NULL == arr) {
1996 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1997 INSUFF_RES_ASCQ);
1998 return check_condition_result;
1999 }
2000 switch (reporting_opts) {
2001 case 0: /* all commands */
2002 /* count number of commands */
2003 for (count = 0, oip = opcode_info_arr;
2004 oip->num_attached != 0xff; ++oip) {
2005 if (F_INV_OP & oip->flags)
2006 continue;
2007 count += (oip->num_attached + 1);
2008 }
2009 bump = rctd ? 20 : 8;
2010 put_unaligned_be32(count * bump, arr);
2011 for (offset = 4, oip = opcode_info_arr;
2012 oip->num_attached != 0xff && offset < a_len; ++oip) {
2013 if (F_INV_OP & oip->flags)
2014 continue;
2015 na = oip->num_attached;
2016 arr[offset] = oip->opcode;
2017 put_unaligned_be16(oip->sa, arr + offset + 2);
2018 if (rctd)
2019 arr[offset + 5] |= 0x2;
2020 if (FF_SA & oip->flags)
2021 arr[offset + 5] |= 0x1;
2022 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
2023 if (rctd)
2024 put_unaligned_be16(0xa, arr + offset + 8);
2025 r_oip = oip;
2026 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
2027 if (F_INV_OP & oip->flags)
2028 continue;
2029 offset += bump;
2030 arr[offset] = oip->opcode;
2031 put_unaligned_be16(oip->sa, arr + offset + 2);
2032 if (rctd)
2033 arr[offset + 5] |= 0x2;
2034 if (FF_SA & oip->flags)
2035 arr[offset + 5] |= 0x1;
2036 put_unaligned_be16(oip->len_mask[0],
2037 arr + offset + 6);
2038 if (rctd)
2039 put_unaligned_be16(0xa,
2040 arr + offset + 8);
2041 }
2042 oip = r_oip;
2043 offset += bump;
2044 }
2045 break;
2046 case 1: /* one command: opcode only */
2047 case 2: /* one command: opcode plus service action */
2048 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
2049 sdeb_i = opcode_ind_arr[req_opcode];
2050 oip = &opcode_info_arr[sdeb_i];
2051 if (F_INV_OP & oip->flags) {
2052 supp = 1;
2053 offset = 4;
2054 } else {
2055 if (1 == reporting_opts) {
2056 if (FF_SA & oip->flags) {
2057 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
2058 2, 2);
2059 kfree(arr);
2060 return check_condition_result;
2061 }
2062 req_sa = 0;
2063 } else if (2 == reporting_opts &&
2064 0 == (FF_SA & oip->flags)) {
2065 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
2066 kfree(arr); /* point at requested sa */
2067 return check_condition_result;
2068 }
2069 if (0 == (FF_SA & oip->flags) &&
2070 req_opcode == oip->opcode)
2071 supp = 3;
2072 else if (0 == (FF_SA & oip->flags)) {
2073 na = oip->num_attached;
2074 for (k = 0, oip = oip->arrp; k < na;
2075 ++k, ++oip) {
2076 if (req_opcode == oip->opcode)
2077 break;
2078 }
2079 supp = (k >= na) ? 1 : 3;
2080 } else if (req_sa != oip->sa) {
2081 na = oip->num_attached;
2082 for (k = 0, oip = oip->arrp; k < na;
2083 ++k, ++oip) {
2084 if (req_sa == oip->sa)
2085 break;
2086 }
2087 supp = (k >= na) ? 1 : 3;
2088 } else
2089 supp = 3;
2090 if (3 == supp) {
2091 u = oip->len_mask[0];
2092 put_unaligned_be16(u, arr + 2);
2093 arr[4] = oip->opcode;
2094 for (k = 1; k < u; ++k)
2095 arr[4 + k] = (k < 16) ?
2096 oip->len_mask[k] : 0xff;
2097 offset = 4 + u;
2098 } else
2099 offset = 4;
2100 }
2101 arr[1] = (rctd ? 0x80 : 0) | supp;
2102 if (rctd) {
2103 put_unaligned_be16(0xa, arr + offset);
2104 offset += 12;
2105 }
2106 break;
2107 default:
2108 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
2109 kfree(arr);
2110 return check_condition_result;
2111 }
2112 offset = (offset < a_len) ? offset : a_len;
2113 len = (offset < alloc_len) ? offset : alloc_len;
2114 errsts = fill_from_dev_buffer(scp, arr, len);
2115 kfree(arr);
2116 return errsts;
2117}
2118
Douglas Gilbertfd321192016-04-25 12:16:33 -04002119static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2120 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002121{
2122 bool repd;
2123 u32 alloc_len, len;
2124 u8 arr[16];
2125 u8 *cmd = scp->cmnd;
2126
2127 memset(arr, 0, sizeof(arr));
2128 repd = !!(cmd[2] & 0x80);
2129 alloc_len = get_unaligned_be32(cmd + 6);
2130 if (alloc_len < 4) {
2131 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
2132 return check_condition_result;
2133 }
2134 arr[0] = 0xc8; /* ATS | ATSS | LURS */
2135 arr[1] = 0x1; /* ITNRS */
2136 if (repd) {
2137 arr[3] = 0xc;
2138 len = 16;
2139 } else
2140 len = 4;
2141
2142 len = (len < alloc_len) ? len : alloc_len;
2143 return fill_from_dev_buffer(scp, arr, len);
2144}
2145
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146/* <<Following mode page info copied from ST318451LW>> */
2147
John Pittman91d4c752018-02-09 21:12:43 -05002148static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149{ /* Read-Write Error Recovery page for mode_sense */
2150 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
2151 5, 0, 0xff, 0xff};
2152
2153 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
2154 if (1 == pcontrol)
2155 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
2156 return sizeof(err_recov_pg);
2157}
2158
John Pittman91d4c752018-02-09 21:12:43 -05002159static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160{ /* Disconnect-Reconnect page for mode_sense */
2161 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
2162 0, 0, 0, 0, 0, 0, 0, 0};
2163
2164 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
2165 if (1 == pcontrol)
2166 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
2167 return sizeof(disconnect_pg);
2168}
2169
John Pittman91d4c752018-02-09 21:12:43 -05002170static int resp_format_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171{ /* Format device page for mode_sense */
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002172 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
2173 0, 0, 0, 0, 0, 0, 0, 0,
2174 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002176 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002177 put_unaligned_be16(sdebug_sectors_per, p + 10);
2178 put_unaligned_be16(sdebug_sector_size, p + 12);
2179 if (sdebug_removable)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002180 p[20] |= 0x20; /* should agree with INQUIRY */
2181 if (1 == pcontrol)
2182 memset(p + 2, 0, sizeof(format_pg) - 2);
2183 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184}
2185
Douglas Gilbertfd321192016-04-25 12:16:33 -04002186static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2187 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2188 0, 0, 0, 0};
2189
John Pittman91d4c752018-02-09 21:12:43 -05002190static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002192 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2194 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
2196
Douglas Gilbert773642d2016-04-25 12:16:28 -04002197 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002198 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 memcpy(p, caching_pg, sizeof(caching_pg));
2200 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002201 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2202 else if (2 == pcontrol)
2203 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 return sizeof(caching_pg);
2205}
2206
Douglas Gilbertfd321192016-04-25 12:16:33 -04002207static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2208 0, 0, 0x2, 0x4b};
2209
John Pittman91d4c752018-02-09 21:12:43 -05002210static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002212 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05002213 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002214 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 0, 0, 0x2, 0x4b};
2216
Douglas Gilbert773642d2016-04-25 12:16:28 -04002217 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002219 else
2220 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002221
Douglas Gilbert773642d2016-04-25 12:16:28 -04002222 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002223 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2224
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2226 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002227 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2228 else if (2 == pcontrol)
2229 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 return sizeof(ctrl_m_pg);
2231}
2232
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002233
John Pittman91d4c752018-02-09 21:12:43 -05002234static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002236 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2237 0, 0, 0x0, 0x0};
2238 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2239 0, 0, 0x0, 0x0};
2240
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2242 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002243 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2244 else if (2 == pcontrol)
2245 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 return sizeof(iec_m_pg);
2247}
2248
John Pittman91d4c752018-02-09 21:12:43 -05002249static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002250{ /* SAS SSP mode page - short format for mode_sense */
2251 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2252 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2253
2254 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2255 if (1 == pcontrol)
2256 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2257 return sizeof(sas_sf_m_pg);
2258}
2259
2260
John Pittman91d4c752018-02-09 21:12:43 -05002261static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 int target_dev_id)
2263{ /* SAS phy control and discover mode page for mode_sense */
2264 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2265 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002266 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2267 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002268 0x2, 0, 0, 0, 0, 0, 0, 0,
2269 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2270 0, 0, 0, 0, 0, 0, 0, 0,
2271 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002272 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2273 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002274 0x3, 0, 0, 0, 0, 0, 0, 0,
2275 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2276 0, 0, 0, 0, 0, 0, 0, 0,
2277 };
2278 int port_a, port_b;
2279
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002280 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2281 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2282 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2283 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002284 port_a = target_dev_id + 1;
2285 port_b = port_a + 1;
2286 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002287 put_unaligned_be32(port_a, p + 20);
2288 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002289 if (1 == pcontrol)
2290 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2291 return sizeof(sas_pcd_m_pg);
2292}
2293
John Pittman91d4c752018-02-09 21:12:43 -05002294static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002295{ /* SAS SSP shared protocol specific port mode subpage */
2296 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2297 0, 0, 0, 0, 0, 0, 0, 0,
2298 };
2299
2300 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2301 if (1 == pcontrol)
2302 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2303 return sizeof(sas_sha_m_pg);
2304}
2305
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306#define SDEBUG_MAX_MSENSE_SZ 256
2307
Douglas Gilbertfd321192016-04-25 12:16:33 -04002308static int resp_mode_sense(struct scsi_cmnd *scp,
2309 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310{
Douglas Gilbert23183912006-09-16 20:30:47 -04002311 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002313 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002314 int target = scp->device->id;
John Pittman91d4c752018-02-09 21:12:43 -05002315 unsigned char *ap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002317 unsigned char *cmd = scp->cmnd;
Douglas Gilbertd36da302020-04-22 19:42:15 +09002318 bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002320 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 pcontrol = (cmd[2] & 0xc0) >> 6;
2322 pcode = cmd[2] & 0x3f;
2323 subpcode = cmd[3];
2324 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002325 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2326 is_disk = (sdebug_ptype == TYPE_DISK);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002327 is_zbc = (devip->zmodel != BLK_ZONED_NONE);
Douglas Gilbertd36da302020-04-22 19:42:15 +09002328 if ((is_disk || is_zbc) && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002329 bd_len = llbaa ? 16 : 8;
2330 else
2331 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002332 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2334 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002335 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 return check_condition_result;
2337 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002338 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2339 (devip->target * 1000) - 3;
Douglas Gilbertd36da302020-04-22 19:42:15 +09002340 /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2341 if (is_disk || is_zbc) {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002342 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002343 if (sdebug_wp)
2344 dev_spec |= 0x80;
2345 } else
Douglas Gilbert23183912006-09-16 20:30:47 -04002346 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 if (msense_6) {
2348 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002349 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 offset = 4;
2351 } else {
2352 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002353 if (16 == bd_len)
2354 arr[4] = 0x1; /* set LONGLBA bit */
2355 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 offset = 8;
2357 }
2358 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002359 if ((bd_len > 0) && (!sdebug_capacity))
2360 sdebug_capacity = get_sdebug_capacity();
2361
Douglas Gilbert23183912006-09-16 20:30:47 -04002362 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002363 if (sdebug_capacity > 0xfffffffe)
2364 put_unaligned_be32(0xffffffff, ap + 0);
2365 else
2366 put_unaligned_be32(sdebug_capacity, ap + 0);
2367 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002368 offset += bd_len;
2369 ap = arr + offset;
2370 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002371 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2372 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002373 offset += bd_len;
2374 ap = arr + offset;
2375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002377 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2378 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002379 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 return check_condition_result;
2381 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002382 bad_pcode = false;
2383
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 switch (pcode) {
2385 case 0x1: /* Read-Write error recovery page, direct access */
2386 len = resp_err_recov_pg(ap, pcontrol, target);
2387 offset += len;
2388 break;
2389 case 0x2: /* Disconnect-Reconnect page, all devices */
2390 len = resp_disconnect_pg(ap, pcontrol, target);
2391 offset += len;
2392 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002393 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002394 if (is_disk) {
2395 len = resp_format_pg(ap, pcontrol, target);
2396 offset += len;
2397 } else
2398 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002399 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 case 0x8: /* Caching page, direct access */
Douglas Gilbertd36da302020-04-22 19:42:15 +09002401 if (is_disk || is_zbc) {
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002402 len = resp_caching_pg(ap, pcontrol, target);
2403 offset += len;
2404 } else
2405 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 break;
2407 case 0xa: /* Control Mode page, all devices */
2408 len = resp_ctrl_m_pg(ap, pcontrol, target);
2409 offset += len;
2410 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002411 case 0x19: /* if spc==1 then sas phy, control+discover */
2412 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002413 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002414 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002415 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002416 len = 0;
2417 if ((0x0 == subpcode) || (0xff == subpcode))
2418 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2419 if ((0x1 == subpcode) || (0xff == subpcode))
2420 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2421 target_dev_id);
2422 if ((0x2 == subpcode) || (0xff == subpcode))
2423 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2424 offset += len;
2425 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 case 0x1c: /* Informational Exceptions Mode page, all devices */
2427 len = resp_iec_m_pg(ap, pcontrol, target);
2428 offset += len;
2429 break;
2430 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002431 if ((0 == subpcode) || (0xff == subpcode)) {
2432 len = resp_err_recov_pg(ap, pcontrol, target);
2433 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002434 if (is_disk) {
2435 len += resp_format_pg(ap + len, pcontrol,
2436 target);
2437 len += resp_caching_pg(ap + len, pcontrol,
2438 target);
Douglas Gilbertd36da302020-04-22 19:42:15 +09002439 } else if (is_zbc) {
2440 len += resp_caching_pg(ap + len, pcontrol,
2441 target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002442 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002443 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2444 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2445 if (0xff == subpcode) {
2446 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2447 target, target_dev_id);
2448 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2449 }
2450 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002451 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002452 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002453 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002454 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 break;
2457 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002458 bad_pcode = true;
2459 break;
2460 }
2461 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002462 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 return check_condition_result;
2464 }
2465 if (msense_6)
2466 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002467 else
2468 put_unaligned_be16((offset - 2), arr + 0);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002469 return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470}
2471
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002472#define SDEBUG_MAX_MSELECT_SZ 512
2473
Douglas Gilbertfd321192016-04-25 12:16:33 -04002474static int resp_mode_select(struct scsi_cmnd *scp,
2475 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002476{
2477 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002478 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002479 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002480 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002481 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002482
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002483 memset(arr, 0, sizeof(arr));
2484 pf = cmd[1] & 0x10;
2485 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002486 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002487 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002488 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002489 return check_condition_result;
2490 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002491 res = fetch_to_dev_buffer(scp, arr, param_len);
2492 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002493 return DID_ERROR << 16;
2494 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002495 sdev_printk(KERN_INFO, scp->device,
2496 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2497 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002498 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2499 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002500 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002501 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002502 return check_condition_result;
2503 }
2504 off = bd_len + (mselect6 ? 4 : 8);
2505 mpage = arr[off] & 0x3f;
2506 ps = !!(arr[off] & 0x80);
2507 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002508 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002509 return check_condition_result;
2510 }
2511 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002512 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002513 (arr[off + 1] + 2);
2514 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002515 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002516 PARAMETER_LIST_LENGTH_ERR, 0);
2517 return check_condition_result;
2518 }
2519 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002520 case 0x8: /* Caching Mode page */
2521 if (caching_pg[1] == arr[off + 1]) {
2522 memcpy(caching_pg + 2, arr + off + 2,
2523 sizeof(caching_pg) - 2);
2524 goto set_mode_changed_ua;
2525 }
2526 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002527 case 0xa: /* Control Mode page */
2528 if (ctrl_m_pg[1] == arr[off + 1]) {
2529 memcpy(ctrl_m_pg + 2, arr + off + 2,
2530 sizeof(ctrl_m_pg) - 2);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002531 if (ctrl_m_pg[4] & 0x8)
2532 sdebug_wp = true;
2533 else
2534 sdebug_wp = false;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002535 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002536 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002537 }
2538 break;
2539 case 0x1c: /* Informational Exceptions Mode page */
2540 if (iec_m_pg[1] == arr[off + 1]) {
2541 memcpy(iec_m_pg + 2, arr + off + 2,
2542 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002543 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002544 }
2545 break;
2546 default:
2547 break;
2548 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002549 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002550 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002551set_mode_changed_ua:
2552 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2553 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002554}
2555
John Pittman91d4c752018-02-09 21:12:43 -05002556static int resp_temp_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002557{
2558 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2559 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2560 };
2561
Douglas Gilbert9a051012017-12-23 12:48:10 -05002562 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2563 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002564}
2565
John Pittman91d4c752018-02-09 21:12:43 -05002566static int resp_ie_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002567{
2568 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2569 };
2570
Douglas Gilbert9a051012017-12-23 12:48:10 -05002571 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002572 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2573 arr[4] = THRESHOLD_EXCEEDED;
2574 arr[5] = 0xff;
2575 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002576 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002577}
2578
2579#define SDEBUG_MAX_LSENSE_SZ 512
2580
Douglas Gilbert9a051012017-12-23 12:48:10 -05002581static int resp_log_sense(struct scsi_cmnd *scp,
2582 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002583{
Bart Van Asscheab172412017-08-25 13:46:42 -07002584 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002585 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002586 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002587
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002588 memset(arr, 0, sizeof(arr));
2589 ppc = cmd[1] & 0x2;
2590 sp = cmd[1] & 0x1;
2591 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002592 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002593 return check_condition_result;
2594 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002595 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002596 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002597 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002598 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002599 if (0 == subpcode) {
2600 switch (pcode) {
2601 case 0x0: /* Supported log pages log page */
2602 n = 4;
2603 arr[n++] = 0x0; /* this page */
2604 arr[n++] = 0xd; /* Temperature */
2605 arr[n++] = 0x2f; /* Informational exceptions */
2606 arr[3] = n - 4;
2607 break;
2608 case 0xd: /* Temperature log page */
2609 arr[3] = resp_temp_l_pg(arr + 4);
2610 break;
2611 case 0x2f: /* Informational exceptions log page */
2612 arr[3] = resp_ie_l_pg(arr + 4);
2613 break;
2614 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002615 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002616 return check_condition_result;
2617 }
2618 } else if (0xff == subpcode) {
2619 arr[0] |= 0x40;
2620 arr[1] = subpcode;
2621 switch (pcode) {
2622 case 0x0: /* Supported log pages and subpages log page */
2623 n = 4;
2624 arr[n++] = 0x0;
2625 arr[n++] = 0x0; /* 0,0 page */
2626 arr[n++] = 0x0;
2627 arr[n++] = 0xff; /* this page */
2628 arr[n++] = 0xd;
2629 arr[n++] = 0x0; /* Temperature */
2630 arr[n++] = 0x2f;
2631 arr[n++] = 0x0; /* Informational exceptions */
2632 arr[3] = n - 4;
2633 break;
2634 case 0xd: /* Temperature subpages */
2635 n = 4;
2636 arr[n++] = 0xd;
2637 arr[n++] = 0x0; /* Temperature */
2638 arr[3] = n - 4;
2639 break;
2640 case 0x2f: /* Informational exceptions subpages */
2641 n = 4;
2642 arr[n++] = 0x2f;
2643 arr[n++] = 0x0; /* Informational exceptions */
2644 arr[3] = n - 4;
2645 break;
2646 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002647 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002648 return check_condition_result;
2649 }
2650 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002651 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002652 return check_condition_result;
2653 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002654 len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002655 return fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002656 min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002657}
2658
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002659static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660{
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002661 return devip->nr_zones != 0;
2662}
2663
2664static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2665 unsigned long long lba)
2666{
Damien Le Moal108e36f2020-05-07 11:35:26 +09002667 return &devip->zstate[lba >> devip->zsize_shift];
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002668}
2669
2670static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2671{
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002672 return zsp->z_type == ZBC_ZONE_TYPE_CNV;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002673}
2674
2675static void zbc_close_zone(struct sdebug_dev_info *devip,
2676 struct sdeb_zone_state *zsp)
2677{
2678 enum sdebug_z_cond zc;
2679
2680 if (zbc_zone_is_conv(zsp))
2681 return;
2682
2683 zc = zsp->z_cond;
2684 if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2685 return;
2686
2687 if (zc == ZC2_IMPLICIT_OPEN)
2688 devip->nr_imp_open--;
2689 else
2690 devip->nr_exp_open--;
2691
2692 if (zsp->z_wp == zsp->z_start) {
2693 zsp->z_cond = ZC1_EMPTY;
2694 } else {
2695 zsp->z_cond = ZC4_CLOSED;
2696 devip->nr_closed++;
2697 }
2698}
2699
2700static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2701{
2702 struct sdeb_zone_state *zsp = &devip->zstate[0];
2703 unsigned int i;
2704
2705 for (i = 0; i < devip->nr_zones; i++, zsp++) {
2706 if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2707 zbc_close_zone(devip, zsp);
2708 return;
2709 }
2710 }
2711}
2712
2713static void zbc_open_zone(struct sdebug_dev_info *devip,
2714 struct sdeb_zone_state *zsp, bool explicit)
2715{
2716 enum sdebug_z_cond zc;
2717
2718 if (zbc_zone_is_conv(zsp))
2719 return;
2720
2721 zc = zsp->z_cond;
2722 if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2723 (!explicit && zc == ZC2_IMPLICIT_OPEN))
2724 return;
2725
2726 /* Close an implicit open zone if necessary */
2727 if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2728 zbc_close_zone(devip, zsp);
2729 else if (devip->max_open &&
2730 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2731 zbc_close_imp_open_zone(devip);
2732
2733 if (zsp->z_cond == ZC4_CLOSED)
2734 devip->nr_closed--;
2735 if (explicit) {
2736 zsp->z_cond = ZC3_EXPLICIT_OPEN;
2737 devip->nr_exp_open++;
2738 } else {
2739 zsp->z_cond = ZC2_IMPLICIT_OPEN;
2740 devip->nr_imp_open++;
2741 }
2742}
2743
2744static void zbc_inc_wp(struct sdebug_dev_info *devip,
2745 unsigned long long lba, unsigned int num)
2746{
2747 struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002748 unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002749
2750 if (zbc_zone_is_conv(zsp))
2751 return;
2752
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002753 if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2754 zsp->z_wp += num;
2755 if (zsp->z_wp >= zend)
2756 zsp->z_cond = ZC5_FULL;
2757 return;
2758 }
2759
2760 while (num) {
2761 if (lba != zsp->z_wp)
2762 zsp->z_non_seq_resource = true;
2763
2764 end = lba + num;
2765 if (end >= zend) {
2766 n = zend - lba;
2767 zsp->z_wp = zend;
2768 } else if (end > zsp->z_wp) {
2769 n = num;
2770 zsp->z_wp = end;
2771 } else {
2772 n = num;
2773 }
2774 if (zsp->z_wp >= zend)
2775 zsp->z_cond = ZC5_FULL;
2776
2777 num -= n;
2778 lba += n;
2779 if (num) {
2780 zsp++;
2781 zend = zsp->z_start + zsp->z_size;
2782 }
2783 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002784}
2785
2786static int check_zbc_access_params(struct scsi_cmnd *scp,
2787 unsigned long long lba, unsigned int num, bool write)
2788{
2789 struct scsi_device *sdp = scp->device;
2790 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2791 struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2792 struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2793
2794 if (!write) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002795 if (devip->zmodel == BLK_ZONED_HA)
2796 return 0;
2797 /* For host-managed, reads cannot cross zone types boundaries */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002798 if (zsp_end != zsp &&
2799 zbc_zone_is_conv(zsp) &&
2800 !zbc_zone_is_conv(zsp_end)) {
2801 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2802 LBA_OUT_OF_RANGE,
2803 READ_INVDATA_ASCQ);
2804 return check_condition_result;
2805 }
2806 return 0;
2807 }
2808
2809 /* No restrictions for writes within conventional zones */
2810 if (zbc_zone_is_conv(zsp)) {
2811 if (!zbc_zone_is_conv(zsp_end)) {
2812 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2813 LBA_OUT_OF_RANGE,
2814 WRITE_BOUNDARY_ASCQ);
2815 return check_condition_result;
2816 }
2817 return 0;
2818 }
2819
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002820 if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2821 /* Writes cannot cross sequential zone boundaries */
2822 if (zsp_end != zsp) {
2823 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2824 LBA_OUT_OF_RANGE,
2825 WRITE_BOUNDARY_ASCQ);
2826 return check_condition_result;
2827 }
2828 /* Cannot write full zones */
2829 if (zsp->z_cond == ZC5_FULL) {
2830 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2831 INVALID_FIELD_IN_CDB, 0);
2832 return check_condition_result;
2833 }
2834 /* Writes must be aligned to the zone WP */
2835 if (lba != zsp->z_wp) {
2836 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2837 LBA_OUT_OF_RANGE,
2838 UNALIGNED_WRITE_ASCQ);
2839 return check_condition_result;
2840 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002841 }
2842
2843 /* Handle implicit open of closed and empty zones */
2844 if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2845 if (devip->max_open &&
2846 devip->nr_exp_open >= devip->max_open) {
2847 mk_sense_buffer(scp, DATA_PROTECT,
2848 INSUFF_RES_ASC,
2849 INSUFF_ZONE_ASCQ);
2850 return check_condition_result;
2851 }
2852 zbc_open_zone(devip, zsp, false);
2853 }
2854
2855 return 0;
2856}
2857
2858static inline int check_device_access_params
2859 (struct scsi_cmnd *scp, unsigned long long lba,
2860 unsigned int num, bool write)
2861{
2862 struct scsi_device *sdp = scp->device;
2863 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2864
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002865 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002866 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 return check_condition_result;
2868 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002869 /* transfer length excessive (tie in to block limits VPD page) */
2870 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002871 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002872 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002873 return check_condition_result;
2874 }
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002875 if (write && unlikely(sdebug_wp)) {
2876 mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
2877 return check_condition_result;
2878 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002879 if (sdebug_dev_is_zoned(devip))
2880 return check_zbc_access_params(scp, lba, num, write);
2881
FUJITA Tomonori19789102008-03-30 00:59:56 +09002882 return 0;
2883}
2884
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04002885/*
2886 * Note: if BUG_ON() fires it usually indicates a problem with the parser
2887 * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2888 * that access any of the "stores" in struct sdeb_store_info should call this
2889 * function with bug_if_fake_rw set to true.
2890 */
2891static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2892 bool bug_if_fake_rw)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002893{
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04002894 if (sdebug_fake_rw) {
2895 BUG_ON(bug_if_fake_rw); /* See note above */
2896 return NULL;
2897 }
2898 return xa_load(per_store_ap, devip->sdbg_host->si_idx);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002899}
2900
Akinobu Mitaa4517512013-07-08 16:01:57 -07002901/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002902static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
2903 u32 sg_skip, u64 lba, u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002904{
2905 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002906 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002907 enum dma_data_direction dir;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002908 struct scsi_data_buffer *sdb = &scp->sdb;
2909 u8 *fsp;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002910
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002911 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002912 dir = DMA_TO_DEVICE;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04002913 write_since_sync = true;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002914 } else {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002915 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002916 }
2917
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002918 if (!sdb->length || !sip)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002919 return 0;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002920 if (scp->sc_data_direction != dir)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002921 return -1;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002922 fsp = sip->storep;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002923
2924 block = do_div(lba, sdebug_store_sectors);
2925 if (block + num > sdebug_store_sectors)
2926 rest = block + num - sdebug_store_sectors;
2927
Dave Gordon386ecb12015-06-30 14:58:57 -07002928 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002929 fsp + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002930 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002931 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002932 return ret;
2933
2934 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002935 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002936 fsp, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002937 sg_skip + ((num - rest) * sdebug_sector_size),
2938 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002939 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002940
2941 return ret;
2942}
2943
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002944/* Returns number of bytes copied or -1 if error. */
2945static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
2946{
2947 struct scsi_data_buffer *sdb = &scp->sdb;
2948
2949 if (!sdb->length)
2950 return 0;
2951 if (scp->sc_data_direction != DMA_TO_DEVICE)
2952 return -1;
2953 return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
2954 num * sdebug_sector_size, 0, true);
2955}
2956
2957/* If sip->storep+lba compares equal to arr(num), then copy top half of
2958 * arr into sip->storep+lba and return true. If comparison fails then
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002959 * return false. */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002960static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04002961 const u8 *arr, bool compare_only)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002962{
2963 bool res;
2964 u64 block, rest = 0;
2965 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002966 u32 lb_size = sdebug_sector_size;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002967 u8 *fsp = sip->storep;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002968
2969 block = do_div(lba, store_blks);
2970 if (block + num > store_blks)
2971 rest = block + num - store_blks;
2972
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002973 res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002974 if (!res)
2975 return res;
2976 if (rest)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002977 res = memcmp(fsp, arr + ((num - rest) * lb_size),
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002978 rest * lb_size);
2979 if (!res)
2980 return res;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04002981 if (compare_only)
2982 return true;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002983 arr += num * lb_size;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002984 memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002985 if (rest)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002986 memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002987 return res;
2988}
2989
Akinobu Mita51d648a2013-09-18 21:27:28 +09002990static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09002991{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002992 __be16 csum;
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09002993
Douglas Gilbert773642d2016-04-25 12:16:28 -04002994 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002995 csum = (__force __be16)ip_compute_csum(buf, len);
2996 else
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09002997 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002998
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09002999 return csum;
3000}
3001
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003002static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09003003 sector_t sector, u32 ei_lba)
3004{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003005 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09003006
3007 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003008 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09003009 (unsigned long)sector,
3010 be16_to_cpu(sdt->guard_tag),
3011 be16_to_cpu(csum));
3012 return 0x01;
3013 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003014 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09003015 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003016 pr_err("REF check failed on sector %lu\n",
3017 (unsigned long)sector);
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09003018 return 0x03;
3019 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003020 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09003021 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003022 pr_err("REF check failed on sector %lu\n",
3023 (unsigned long)sector);
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09003024 return 0x03;
3025 }
3026 return 0;
3027}
3028
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003029static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003030 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003031{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003032 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003033 void *paddr;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003034 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003035 scp->device->hostdata, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003036 struct t10_pi_tuple *dif_storep = sip->dif_storep;
Akinobu Mita14faa942013-09-18 21:27:24 +09003037 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003038 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003039
Akinobu Mitae18d8be2013-06-29 17:59:18 +09003040 /* Bytes of protection data to copy into sgl */
3041 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003042
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003043 sg_miter_start(&miter, scsi_prot_sglist(scp),
3044 scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3045 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003046
3047 while (sg_miter_next(&miter) && resid > 0) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003048 size_t len = min_t(size_t, miter.length, resid);
3049 void *start = dif_store(sip, sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003050 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09003051
3052 if (dif_store_end < start + len)
3053 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003054
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003055 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09003056
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003057 if (read)
3058 memcpy(paddr, start, len - rest);
3059 else
3060 memcpy(start, paddr, len - rest);
3061
3062 if (rest) {
3063 if (read)
3064 memcpy(paddr + len - rest, dif_storep, rest);
3065 else
3066 memcpy(dif_storep, paddr + len - rest, rest);
3067 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003068
Akinobu Mitae18d8be2013-06-29 17:59:18 +09003069 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003070 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003071 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003072 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003073}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003074
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003075static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003076 unsigned int sectors, u32 ei_lba)
3077{
3078 unsigned int i;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003079 sector_t sector;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003080 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003081 scp->device->hostdata, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003082 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003083
Akinobu Mitac45eabec2014-02-26 22:56:58 +09003084 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003085 int ret;
3086
3087 sector = start_sec + i;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003088 sdt = dif_store(sip, sector);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003089
Akinobu Mita51d648a2013-09-18 21:27:28 +09003090 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003091 continue;
3092
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003093 ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
3094 ei_lba);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003095 if (ret) {
3096 dif_errors++;
3097 return ret;
3098 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003099 }
3100
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003101 dif_copy_prot(scp, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003102 dix_reads++;
3103
3104 return 0;
3105}
3106
Douglas Gilbertfd321192016-04-25 12:16:33 -04003107static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09003108{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003109 bool check_prot;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003110 u32 num;
3111 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003112 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003113 u64 lba;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003114 struct sdeb_store_info *sip = devip2sip(devip, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003115 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3116 u8 *cmd = scp->cmnd;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003117
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003118 switch (cmd[0]) {
3119 case READ_16:
3120 ei_lba = 0;
3121 lba = get_unaligned_be64(cmd + 2);
3122 num = get_unaligned_be32(cmd + 10);
3123 check_prot = true;
3124 break;
3125 case READ_10:
3126 ei_lba = 0;
3127 lba = get_unaligned_be32(cmd + 2);
3128 num = get_unaligned_be16(cmd + 7);
3129 check_prot = true;
3130 break;
3131 case READ_6:
3132 ei_lba = 0;
3133 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3134 (u32)(cmd[1] & 0x1f) << 16;
3135 num = (0 == cmd[4]) ? 256 : cmd[4];
3136 check_prot = true;
3137 break;
3138 case READ_12:
3139 ei_lba = 0;
3140 lba = get_unaligned_be32(cmd + 2);
3141 num = get_unaligned_be32(cmd + 6);
3142 check_prot = true;
3143 break;
3144 case XDWRITEREAD_10:
3145 ei_lba = 0;
3146 lba = get_unaligned_be32(cmd + 2);
3147 num = get_unaligned_be16(cmd + 7);
3148 check_prot = false;
3149 break;
3150 default: /* assume READ(32) */
3151 lba = get_unaligned_be64(cmd + 12);
3152 ei_lba = get_unaligned_be32(cmd + 20);
3153 num = get_unaligned_be32(cmd + 28);
3154 check_prot = false;
3155 break;
3156 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003157 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003158 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003159 (cmd[1] & 0xe0)) {
3160 mk_sense_invalid_opcode(scp);
3161 return check_condition_result;
3162 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003163 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3164 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003165 (cmd[1] & 0xe0) == 0)
3166 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3167 "to DIF device\n");
3168 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003169 if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
3170 atomic_read(&sdeb_inject_pending))) {
3171 num /= 2;
3172 atomic_set(&sdeb_inject_pending, 0);
3173 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003174
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003175 ret = check_device_access_params(scp, lba, num, false);
3176 if (ret)
3177 return ret;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003178 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05003179 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3180 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003181 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003182 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003183 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003184 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3185 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05003186 ret = (lba < OPT_MEDIUM_ERR_ADDR)
3187 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003188 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003189 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003190 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 return check_condition_result;
3192 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003193
Douglas Gilbert67da4132020-04-21 11:14:20 -04003194 read_lock(macc_lckp);
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003195
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003196 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003197 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003198 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003199
3200 if (prot_ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003201 read_unlock(macc_lckp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003202 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003203 return illegal_condition_result;
3204 }
3205 }
3206
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003207 ret = do_device_access(sip, scp, 0, lba, num, false);
Douglas Gilbert67da4132020-04-21 11:14:20 -04003208 read_unlock(macc_lckp);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003209 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07003210 return DID_ERROR << 16;
3211
Bart Van Assche42d387b2019-02-08 13:25:00 -08003212 scsi_set_resid(scp, scsi_bufflen(scp) - ret);
Akinobu Mitaa4517512013-07-08 16:01:57 -07003213
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003214 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3215 atomic_read(&sdeb_inject_pending))) {
3216 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3217 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3218 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003219 return check_condition_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003220 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003221 /* Logical block guard check failed */
3222 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003223 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003224 return illegal_condition_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003225 } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003226 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003227 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003228 return illegal_condition_result;
3229 }
3230 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07003231 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232}
3233
Tomas Winkler58a86352015-07-28 16:54:23 +03003234static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003235{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003236 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003237
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003238 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003239 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003240 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003241
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003242 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003243 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003244
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003245 if (c >= 0x20 && c < 0x7e)
3246 n += scnprintf(b + n, sizeof(b) - n,
3247 " %c ", buf[i+j]);
3248 else
3249 n += scnprintf(b + n, sizeof(b) - n,
3250 "%02x ", buf[i+j]);
3251 }
3252 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003253 }
3254}
3255
3256static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04003257 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003258{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003259 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003260 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003261 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003262 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003263 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003264 int dpage_offset;
3265 struct sg_mapping_iter diter;
3266 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003267
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003268 BUG_ON(scsi_sg_count(SCpnt) == 0);
3269 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3270
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003271 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3272 scsi_prot_sg_count(SCpnt),
3273 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3274 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3275 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003276
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003277 /* For each protection page */
3278 while (sg_miter_next(&piter)) {
3279 dpage_offset = 0;
3280 if (WARN_ON(!sg_miter_next(&diter))) {
3281 ret = 0x01;
3282 goto out;
3283 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003284
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003285 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003286 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003287 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003288 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003289 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003290 if (dpage_offset >= diter.length) {
3291 if (WARN_ON(!sg_miter_next(&diter))) {
3292 ret = 0x01;
3293 goto out;
3294 }
3295 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003296 }
3297
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003298 sdt = piter.addr + ppage_offset;
3299 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003300
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003301 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea42013-06-29 17:59:19 +09003302 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003303 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04003304 goto out;
3305 }
3306
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003307 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003308 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003309 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003310 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003311 diter.consumed = dpage_offset;
3312 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003313 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003314 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003315
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003316 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003317 dix_writes++;
3318
3319 return 0;
3320
3321out:
3322 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003323 sg_miter_stop(&diter);
3324 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003325 return ret;
3326}
3327
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003328static unsigned long lba_to_map_index(sector_t lba)
3329{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003330 if (sdebug_unmap_alignment)
3331 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3332 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003333 return lba;
3334}
3335
3336static sector_t map_index_to_lba(unsigned long index)
3337{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003338 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09003339
Douglas Gilbert773642d2016-04-25 12:16:28 -04003340 if (sdebug_unmap_alignment)
3341 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09003342 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003343}
3344
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003345static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
3346 unsigned int *num)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003347{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003348 sector_t end;
3349 unsigned int mapped;
3350 unsigned long index;
3351 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003352
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003353 index = lba_to_map_index(lba);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003354 mapped = test_bit(index, sip->map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003355
3356 if (mapped)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003357 next = find_next_zero_bit(sip->map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003358 else
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003359 next = find_next_bit(sip->map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003360
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003361 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003362 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003363 return mapped;
3364}
3365
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003366static void map_region(struct sdeb_store_info *sip, sector_t lba,
3367 unsigned int len)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003368{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003369 sector_t end = lba + len;
3370
Martin K. Petersen44d92692009-10-15 14:45:27 -04003371 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003372 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003373
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003374 if (index < map_size)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003375 set_bit(index, sip->map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003376
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003377 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003378 }
3379}
3380
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003381static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
3382 unsigned int len)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003383{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003384 sector_t end = lba + len;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003385 u8 *fsp = sip->storep;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003386
Martin K. Petersen44d92692009-10-15 14:45:27 -04003387 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003388 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003389
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003390 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04003391 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003392 index < map_size) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003393 clear_bit(index, sip->map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04003394 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003395 memset(fsp + lba * sdebug_sector_size,
Douglas Gilbert760f3b02016-05-06 00:40:27 -04003396 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04003397 sdebug_sector_size *
3398 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003399 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003400 if (sip->dif_storep) {
3401 memset(sip->dif_storep + lba, 0xff,
3402 sizeof(*sip->dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04003403 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09003404 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003405 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003406 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003407 }
3408}
3409
Douglas Gilbertfd321192016-04-25 12:16:33 -04003410static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003412 bool check_prot;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003413 u32 num;
3414 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003415 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003416 u64 lba;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003417 struct sdeb_store_info *sip = devip2sip(devip, true);
3418 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003419 u8 *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003421 switch (cmd[0]) {
3422 case WRITE_16:
3423 ei_lba = 0;
3424 lba = get_unaligned_be64(cmd + 2);
3425 num = get_unaligned_be32(cmd + 10);
3426 check_prot = true;
3427 break;
3428 case WRITE_10:
3429 ei_lba = 0;
3430 lba = get_unaligned_be32(cmd + 2);
3431 num = get_unaligned_be16(cmd + 7);
3432 check_prot = true;
3433 break;
3434 case WRITE_6:
3435 ei_lba = 0;
3436 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3437 (u32)(cmd[1] & 0x1f) << 16;
3438 num = (0 == cmd[4]) ? 256 : cmd[4];
3439 check_prot = true;
3440 break;
3441 case WRITE_12:
3442 ei_lba = 0;
3443 lba = get_unaligned_be32(cmd + 2);
3444 num = get_unaligned_be32(cmd + 6);
3445 check_prot = true;
3446 break;
3447 case 0x53: /* XDWRITEREAD(10) */
3448 ei_lba = 0;
3449 lba = get_unaligned_be32(cmd + 2);
3450 num = get_unaligned_be16(cmd + 7);
3451 check_prot = false;
3452 break;
3453 default: /* assume WRITE(32) */
3454 lba = get_unaligned_be64(cmd + 12);
3455 ei_lba = get_unaligned_be32(cmd + 20);
3456 num = get_unaligned_be32(cmd + 28);
3457 check_prot = false;
3458 break;
3459 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003460 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003461 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003462 (cmd[1] & 0xe0)) {
3463 mk_sense_invalid_opcode(scp);
3464 return check_condition_result;
3465 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003466 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3467 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003468 (cmd[1] & 0xe0) == 0)
3469 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3470 "to DIF device\n");
3471 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003472
Douglas Gilbert67da4132020-04-21 11:14:20 -04003473 write_lock(macc_lckp);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003474 ret = check_device_access_params(scp, lba, num, true);
3475 if (ret) {
3476 write_unlock(macc_lckp);
3477 return ret;
3478 }
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003479
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003480 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003481 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003482 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003483
3484 if (prot_ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003485 write_unlock(macc_lckp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003486 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003487 return illegal_condition_result;
3488 }
3489 }
3490
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003491 ret = do_device_access(sip, scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003492 if (unlikely(scsi_debug_lbp()))
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003493 map_region(sip, lba, num);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003494 /* If ZBC zone then bump its write pointer */
3495 if (sdebug_dev_is_zoned(devip))
3496 zbc_inc_wp(devip, lba, num);
Douglas Gilbert67da4132020-04-21 11:14:20 -04003497 write_unlock(macc_lckp);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003498 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003499 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003500 else if (unlikely(sdebug_verbose &&
3501 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003502 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003503 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003504 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003505
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003506 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3507 atomic_read(&sdeb_inject_pending))) {
3508 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3509 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3510 atomic_set(&sdeb_inject_pending, 0);
3511 return check_condition_result;
3512 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3513 /* Logical block guard check failed */
3514 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3515 atomic_set(&sdeb_inject_pending, 0);
3516 return illegal_condition_result;
3517 } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3518 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3519 atomic_set(&sdeb_inject_pending, 0);
3520 return illegal_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003521 }
3522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 return 0;
3524}
3525
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003526/*
3527 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3528 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3529 */
3530static int resp_write_scat(struct scsi_cmnd *scp,
3531 struct sdebug_dev_info *devip)
3532{
3533 u8 *cmd = scp->cmnd;
3534 u8 *lrdp = NULL;
3535 u8 *up;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003536 struct sdeb_store_info *sip = devip2sip(devip, true);
3537 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003538 u8 wrprotect;
3539 u16 lbdof, num_lrd, k;
3540 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3541 u32 lb_size = sdebug_sector_size;
3542 u32 ei_lba;
3543 u64 lba;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003544 int ret, res;
3545 bool is_16;
3546 static const u32 lrd_size = 32; /* + parameter list header size */
3547
3548 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3549 is_16 = false;
3550 wrprotect = (cmd[10] >> 5) & 0x7;
3551 lbdof = get_unaligned_be16(cmd + 12);
3552 num_lrd = get_unaligned_be16(cmd + 16);
3553 bt_len = get_unaligned_be32(cmd + 28);
3554 } else { /* that leaves WRITE SCATTERED(16) */
3555 is_16 = true;
3556 wrprotect = (cmd[2] >> 5) & 0x7;
3557 lbdof = get_unaligned_be16(cmd + 4);
3558 num_lrd = get_unaligned_be16(cmd + 8);
3559 bt_len = get_unaligned_be32(cmd + 10);
3560 if (unlikely(have_dif_prot)) {
3561 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3562 wrprotect) {
3563 mk_sense_invalid_opcode(scp);
3564 return illegal_condition_result;
3565 }
3566 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3567 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3568 wrprotect == 0)
3569 sdev_printk(KERN_ERR, scp->device,
3570 "Unprotected WR to DIF device\n");
3571 }
3572 }
3573 if ((num_lrd == 0) || (bt_len == 0))
3574 return 0; /* T10 says these do-nothings are not errors */
3575 if (lbdof == 0) {
3576 if (sdebug_verbose)
3577 sdev_printk(KERN_INFO, scp->device,
3578 "%s: %s: LB Data Offset field bad\n",
3579 my_name, __func__);
3580 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3581 return illegal_condition_result;
3582 }
3583 lbdof_blen = lbdof * lb_size;
3584 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3585 if (sdebug_verbose)
3586 sdev_printk(KERN_INFO, scp->device,
3587 "%s: %s: LBA range descriptors don't fit\n",
3588 my_name, __func__);
3589 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3590 return illegal_condition_result;
3591 }
3592 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3593 if (lrdp == NULL)
3594 return SCSI_MLQUEUE_HOST_BUSY;
3595 if (sdebug_verbose)
3596 sdev_printk(KERN_INFO, scp->device,
3597 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3598 my_name, __func__, lbdof_blen);
3599 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3600 if (res == -1) {
3601 ret = DID_ERROR << 16;
3602 goto err_out;
3603 }
3604
Douglas Gilbert67da4132020-04-21 11:14:20 -04003605 write_lock(macc_lckp);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003606 sg_off = lbdof_blen;
3607 /* Spec says Buffer xfer Length field in number of LBs in dout */
3608 cum_lb = 0;
3609 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3610 lba = get_unaligned_be64(up + 0);
3611 num = get_unaligned_be32(up + 8);
3612 if (sdebug_verbose)
3613 sdev_printk(KERN_INFO, scp->device,
3614 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3615 my_name, __func__, k, lba, num, sg_off);
3616 if (num == 0)
3617 continue;
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003618 ret = check_device_access_params(scp, lba, num, true);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003619 if (ret)
3620 goto err_out_unlock;
3621 num_by = num * lb_size;
3622 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3623
3624 if ((cum_lb + num) > bt_len) {
3625 if (sdebug_verbose)
3626 sdev_printk(KERN_INFO, scp->device,
3627 "%s: %s: sum of blocks > data provided\n",
3628 my_name, __func__);
3629 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3630 0);
3631 ret = illegal_condition_result;
3632 goto err_out_unlock;
3633 }
3634
3635 /* DIX + T10 DIF */
3636 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3637 int prot_ret = prot_verify_write(scp, lba, num,
3638 ei_lba);
3639
3640 if (prot_ret) {
3641 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3642 prot_ret);
3643 ret = illegal_condition_result;
3644 goto err_out_unlock;
3645 }
3646 }
3647
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003648 ret = do_device_access(sip, scp, sg_off, lba, num, true);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003649 /* If ZBC zone then bump its write pointer */
3650 if (sdebug_dev_is_zoned(devip))
3651 zbc_inc_wp(devip, lba, num);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003652 if (unlikely(scsi_debug_lbp()))
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003653 map_region(sip, lba, num);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003654 if (unlikely(-1 == ret)) {
3655 ret = DID_ERROR << 16;
3656 goto err_out_unlock;
3657 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3658 sdev_printk(KERN_INFO, scp->device,
3659 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3660 my_name, num_by, ret);
3661
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003662 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3663 atomic_read(&sdeb_inject_pending))) {
3664 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3665 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3666 atomic_set(&sdeb_inject_pending, 0);
3667 ret = check_condition_result;
3668 goto err_out_unlock;
3669 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3670 /* Logical block guard check failed */
3671 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3672 atomic_set(&sdeb_inject_pending, 0);
3673 ret = illegal_condition_result;
3674 goto err_out_unlock;
3675 } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3676 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3677 atomic_set(&sdeb_inject_pending, 0);
3678 ret = illegal_condition_result;
3679 goto err_out_unlock;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003680 }
3681 }
3682 sg_off += num_by;
3683 cum_lb += num;
3684 }
3685 ret = 0;
3686err_out_unlock:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003687 write_unlock(macc_lckp);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003688err_out:
3689 kfree(lrdp);
3690 return ret;
3691}
3692
Douglas Gilbertfd321192016-04-25 12:16:33 -04003693static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3694 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003695{
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003696 struct scsi_device *sdp = scp->device;
3697 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003698 unsigned long long i;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003699 u64 block, lbaa;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003700 u32 lb_size = sdebug_sector_size;
3701 int ret;
3702 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003703 scp->device->hostdata, true);
3704 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003705 u8 *fs1p;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003706 u8 *fsp;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003707
Douglas Gilbert67da4132020-04-21 11:14:20 -04003708 write_lock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003709
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003710 ret = check_device_access_params(scp, lba, num, true);
3711 if (ret) {
3712 write_unlock(macc_lckp);
3713 return ret;
3714 }
3715
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003716 if (unmap && scsi_debug_lbp()) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003717 unmap_region(sip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003718 goto out;
3719 }
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003720 lbaa = lba;
3721 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003722 /* if ndob then zero 1 logical block, else fetch 1 logical block */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003723 fsp = sip->storep;
3724 fs1p = fsp + (block * lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003725 if (ndob) {
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003726 memset(fs1p, 0, lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003727 ret = 0;
3728 } else
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003729 ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003730
3731 if (-1 == ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003732 write_unlock(&sip->macc_lck);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003733 return DID_ERROR << 16;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003734 } else if (sdebug_verbose && !ndob && (ret < lb_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003735 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003736 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003737 my_name, "write same", lb_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003738
3739 /* Copy first sector to remaining blocks */
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003740 for (i = 1 ; i < num ; i++) {
3741 lbaa = lba + i;
3742 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003743 memmove(fsp + (block * lb_size), fs1p, lb_size);
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003744 }
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003745 if (scsi_debug_lbp())
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003746 map_region(sip, lba, num);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003747 /* If ZBC zone then bump its write pointer */
3748 if (sdebug_dev_is_zoned(devip))
3749 zbc_inc_wp(devip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003750out:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003751 write_unlock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003752
3753 return 0;
3754}
3755
Douglas Gilbertfd321192016-04-25 12:16:33 -04003756static int resp_write_same_10(struct scsi_cmnd *scp,
3757 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003758{
3759 u8 *cmd = scp->cmnd;
3760 u32 lba;
3761 u16 num;
3762 u32 ei_lba = 0;
3763 bool unmap = false;
3764
3765 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003766 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003767 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3768 return check_condition_result;
3769 } else
3770 unmap = true;
3771 }
3772 lba = get_unaligned_be32(cmd + 2);
3773 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003774 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003775 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3776 return check_condition_result;
3777 }
3778 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3779}
3780
Douglas Gilbertfd321192016-04-25 12:16:33 -04003781static int resp_write_same_16(struct scsi_cmnd *scp,
3782 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003783{
3784 u8 *cmd = scp->cmnd;
3785 u64 lba;
3786 u32 num;
3787 u32 ei_lba = 0;
3788 bool unmap = false;
3789 bool ndob = false;
3790
3791 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003792 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003793 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3794 return check_condition_result;
3795 } else
3796 unmap = true;
3797 }
3798 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3799 ndob = true;
3800 lba = get_unaligned_be64(cmd + 2);
3801 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003802 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003803 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3804 return check_condition_result;
3805 }
3806 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3807}
3808
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003809/* Note the mode field is in the same position as the (lower) service action
3810 * field. For the Report supported operation codes command, SPC-4 suggests
3811 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003812static int resp_write_buffer(struct scsi_cmnd *scp,
3813 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003814{
3815 u8 *cmd = scp->cmnd;
3816 struct scsi_device *sdp = scp->device;
3817 struct sdebug_dev_info *dp;
3818 u8 mode;
3819
3820 mode = cmd[1] & 0x1f;
3821 switch (mode) {
3822 case 0x4: /* download microcode (MC) and activate (ACT) */
3823 /* set UAs on this device only */
3824 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3825 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3826 break;
3827 case 0x5: /* download MC, save and ACT */
3828 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3829 break;
3830 case 0x6: /* download MC with offsets and ACT */
3831 /* set UAs on most devices (LUs) in this target */
3832 list_for_each_entry(dp,
3833 &devip->sdbg_host->dev_info_list,
3834 dev_list)
3835 if (dp->target == sdp->id) {
3836 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3837 if (devip != dp)
3838 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3839 dp->uas_bm);
3840 }
3841 break;
3842 case 0x7: /* download MC with offsets, save, and ACT */
3843 /* set UA on all devices (LUs) in this target */
3844 list_for_each_entry(dp,
3845 &devip->sdbg_host->dev_info_list,
3846 dev_list)
3847 if (dp->target == sdp->id)
3848 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3849 dp->uas_bm);
3850 break;
3851 default:
3852 /* do nothing for this command for other mode values */
3853 break;
3854 }
3855 return 0;
3856}
3857
Douglas Gilbertfd321192016-04-25 12:16:33 -04003858static int resp_comp_write(struct scsi_cmnd *scp,
3859 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003860{
3861 u8 *cmd = scp->cmnd;
3862 u8 *arr;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003863 struct sdeb_store_info *sip = devip2sip(devip, true);
3864 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003865 u64 lba;
3866 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003867 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003868 u8 num;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003869 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003870 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003871
Douglas Gilbertd467d312014-11-26 12:33:48 -05003872 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003873 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3874 if (0 == num)
3875 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003876 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003877 (cmd[1] & 0xe0)) {
3878 mk_sense_invalid_opcode(scp);
3879 return check_condition_result;
3880 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003881 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3882 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003883 (cmd[1] & 0xe0) == 0)
3884 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3885 "to DIF device\n");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003886 ret = check_device_access_params(scp, lba, num, false);
3887 if (ret)
3888 return ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003889 dnum = 2 * num;
Kees Cook6396bb22018-06-12 14:03:40 -07003890 arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003891 if (NULL == arr) {
3892 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3893 INSUFF_RES_ASCQ);
3894 return check_condition_result;
3895 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003896
Douglas Gilbert67da4132020-04-21 11:14:20 -04003897 write_lock(macc_lckp);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003898
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003899 ret = do_dout_fetch(scp, dnum, arr);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003900 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003901 retval = DID_ERROR << 16;
3902 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003903 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003904 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3905 "indicated=%u, IO sent=%d bytes\n", my_name,
3906 dnum * lb_size, ret);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04003907 if (!comp_write_worker(sip, lba, num, arr, false)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003908 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003909 retval = check_condition_result;
3910 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003911 }
3912 if (scsi_debug_lbp())
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003913 map_region(sip, lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003914cleanup:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003915 write_unlock(macc_lckp);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003916 kfree(arr);
3917 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003918}
3919
Martin K. Petersen44d92692009-10-15 14:45:27 -04003920struct unmap_block_desc {
3921 __be64 lba;
3922 __be32 blocks;
3923 __be32 __reserved;
3924};
3925
Douglas Gilbertfd321192016-04-25 12:16:33 -04003926static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003927{
3928 unsigned char *buf;
3929 struct unmap_block_desc *desc;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003930 struct sdeb_store_info *sip = devip2sip(devip, true);
3931 rwlock_t *macc_lckp = &sip->macc_lck;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003932 unsigned int i, payload_len, descriptors;
3933 int ret;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003934
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003935 if (!scsi_debug_lbp())
3936 return 0; /* fib and say its done */
3937 payload_len = get_unaligned_be16(scp->cmnd + 7);
3938 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003939
3940 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003941 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003942 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003943 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003944 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003945
Douglas Gilbertb333a812016-04-25 12:16:30 -04003946 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003947 if (!buf) {
3948 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3949 INSUFF_RES_ASCQ);
3950 return check_condition_result;
3951 }
3952
3953 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003954
3955 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3956 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3957
3958 desc = (void *)&buf[8];
3959
Douglas Gilbert67da4132020-04-21 11:14:20 -04003960 write_lock(macc_lckp);
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003961
Martin K. Petersen44d92692009-10-15 14:45:27 -04003962 for (i = 0 ; i < descriptors ; i++) {
3963 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3964 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3965
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003966 ret = check_device_access_params(scp, lba, num, true);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003967 if (ret)
3968 goto out;
3969
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003970 unmap_region(sip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003971 }
3972
3973 ret = 0;
3974
3975out:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003976 write_unlock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003977 kfree(buf);
3978
3979 return ret;
3980}
3981
3982#define SDEBUG_GET_LBA_STATUS_LEN 32
3983
Douglas Gilbertfd321192016-04-25 12:16:33 -04003984static int resp_get_lba_status(struct scsi_cmnd *scp,
3985 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003986{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003987 u8 *cmd = scp->cmnd;
3988 u64 lba;
3989 u32 alloc_len, mapped, num;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003990 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003991 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003992
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003993 lba = get_unaligned_be64(cmd + 2);
3994 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003995
3996 if (alloc_len < 24)
3997 return 0;
3998
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003999 ret = check_device_access_params(scp, lba, 1, false);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004000 if (ret)
4001 return ret;
4002
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004003 if (scsi_debug_lbp()) {
4004 struct sdeb_store_info *sip = devip2sip(devip, true);
4005
Douglas Gilbert87c715d2020-04-21 11:14:18 -04004006 mapped = map_state(sip, lba, &num);
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004007 } else {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004008 mapped = 1;
4009 /* following just in case virtual_gb changed */
4010 sdebug_capacity = get_sdebug_capacity();
4011 if (sdebug_capacity - lba <= 0xffffffff)
4012 num = sdebug_capacity - lba;
4013 else
4014 num = 0xffffffff;
4015 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04004016
4017 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004018 put_unaligned_be32(20, arr); /* Parameter Data Length */
4019 put_unaligned_be64(lba, arr + 8); /* LBA */
4020 put_unaligned_be32(num, arr + 16); /* Number of blocks */
4021 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04004022
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004023 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004024}
4025
Douglas Gilbert80c49562018-02-09 21:36:39 -05004026static int resp_sync_cache(struct scsi_cmnd *scp,
4027 struct sdebug_dev_info *devip)
4028{
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04004029 int res = 0;
Douglas Gilbert80c49562018-02-09 21:36:39 -05004030 u64 lba;
4031 u32 num_blocks;
4032 u8 *cmd = scp->cmnd;
4033
4034 if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
4035 lba = get_unaligned_be32(cmd + 2);
4036 num_blocks = get_unaligned_be16(cmd + 7);
4037 } else { /* SYNCHRONIZE_CACHE(16) */
4038 lba = get_unaligned_be64(cmd + 2);
4039 num_blocks = get_unaligned_be32(cmd + 10);
4040 }
4041 if (lba + num_blocks > sdebug_capacity) {
4042 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4043 return check_condition_result;
4044 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04004045 if (!write_since_sync || (cmd[1] & 0x2))
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04004046 res = SDEG_RES_IMMED_MASK;
4047 else /* delay if write_since_sync and IMMED clear */
4048 write_since_sync = false;
4049 return res;
Douglas Gilbert80c49562018-02-09 21:36:39 -05004050}
4051
Douglas Gilberted9f3e22020-04-21 11:14:22 -04004052/*
4053 * Assuming the LBA+num_blocks is not out-of-range, this function will return
4054 * CONDITION MET if the specified blocks will/have fitted in the cache, and
4055 * a GOOD status otherwise. Model a disk with a big cache and yield
4056 * CONDITION MET. Actually tries to bring range in main memory into the
4057 * cache associated with the CPU(s).
4058 */
4059static int resp_pre_fetch(struct scsi_cmnd *scp,
4060 struct sdebug_dev_info *devip)
4061{
4062 int res = 0;
4063 u64 lba;
4064 u64 block, rest = 0;
4065 u32 nblks;
4066 u8 *cmd = scp->cmnd;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004067 struct sdeb_store_info *sip = devip2sip(devip, true);
4068 rwlock_t *macc_lckp = &sip->macc_lck;
4069 u8 *fsp = sip->storep;
Douglas Gilberted9f3e22020-04-21 11:14:22 -04004070
4071 if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */
4072 lba = get_unaligned_be32(cmd + 2);
4073 nblks = get_unaligned_be16(cmd + 7);
4074 } else { /* PRE-FETCH(16) */
4075 lba = get_unaligned_be64(cmd + 2);
4076 nblks = get_unaligned_be32(cmd + 10);
4077 }
4078 if (lba + nblks > sdebug_capacity) {
4079 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4080 return check_condition_result;
4081 }
4082 if (!fsp)
4083 goto fini;
4084 /* PRE-FETCH spec says nothing about LBP or PI so skip them */
4085 block = do_div(lba, sdebug_store_sectors);
4086 if (block + nblks > sdebug_store_sectors)
4087 rest = block + nblks - sdebug_store_sectors;
4088
4089 /* Try to bring the PRE-FETCH range into CPU's cache */
4090 read_lock(macc_lckp);
4091 prefetch_range(fsp + (sdebug_sector_size * block),
4092 (nblks - rest) * sdebug_sector_size);
4093 if (rest)
4094 prefetch_range(fsp, rest * sdebug_sector_size);
4095 read_unlock(macc_lckp);
4096fini:
4097 if (cmd[1] & 0x2)
4098 res = SDEG_RES_IMMED_MASK;
4099 return res | condition_met_result;
4100}
4101
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004102#define RL_BUCKET_ELEMS 8
4103
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004104/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
4105 * (W-LUN), the normal Linux scanning logic does not associate it with a
4106 * device (e.g. /dev/sg7). The following magic will make that association:
4107 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
4108 * where <n> is a host number. If there are multiple targets in a host then
4109 * the above will associate a W-LUN to each target. To only get a W-LUN
4110 * for target 2, then use "echo '- 2 49409' > scan" .
4111 */
4112static int resp_report_luns(struct scsi_cmnd *scp,
4113 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02004115 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004116 unsigned int alloc_len;
4117 unsigned char select_report;
4118 u64 lun;
4119 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004120 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004121 unsigned int lun_cnt; /* normal LUN count (max: 256) */
4122 unsigned int wlun_cnt; /* report luns W-LUN count */
4123 unsigned int tlun_cnt; /* total LUN count */
4124 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004125 int k, j, n, res;
4126 unsigned int off_rsp = 0;
4127 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004129 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004130
4131 select_report = cmd[2];
4132 alloc_len = get_unaligned_be32(cmd + 6);
4133
4134 if (alloc_len < 4) {
4135 pr_err("alloc len too small %d\n", alloc_len);
4136 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 return check_condition_result;
4138 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004139
4140 switch (select_report) {
4141 case 0: /* all LUNs apart from W-LUNs */
4142 lun_cnt = sdebug_max_luns;
4143 wlun_cnt = 0;
4144 break;
4145 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004146 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004147 wlun_cnt = 1;
4148 break;
4149 case 2: /* all LUNs */
4150 lun_cnt = sdebug_max_luns;
4151 wlun_cnt = 1;
4152 break;
4153 case 0x10: /* only administrative LUs */
4154 case 0x11: /* see SPC-5 */
4155 case 0x12: /* only subsiduary LUs owned by referenced LU */
4156 default:
4157 pr_debug("select report invalid %d\n", select_report);
4158 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
4159 return check_condition_result;
4160 }
4161
4162 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004163 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004164
4165 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004166 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
4167 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004168 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
4169 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
4170
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004171 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004172 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004173 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4174 memset(arr, 0, sizeof(arr));
4175 lun_p = (struct scsi_lun *)&arr[0];
4176 if (k == 0) {
4177 put_unaligned_be32(rlen, &arr[0]);
4178 ++lun_p;
4179 j = 1;
4180 }
4181 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4182 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4183 break;
4184 int_to_scsilun(lun++, lun_p);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04004185 if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4186 lun_p->scsi_lun[0] |= 0x40;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004187 }
4188 if (j < RL_BUCKET_ELEMS)
4189 break;
4190 n = j * sz_lun;
4191 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4192 if (res)
4193 return res;
4194 off_rsp += n;
4195 }
4196 if (wlun_cnt) {
4197 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4198 ++j;
4199 }
4200 if (j > 0)
4201 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004202 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203}
4204
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004205static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4206{
4207 bool is_bytchk3 = false;
4208 u8 bytchk;
4209 int ret, j;
4210 u32 vnum, a_num, off;
4211 const u32 lb_size = sdebug_sector_size;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004212 u64 lba;
4213 u8 *arr;
4214 u8 *cmd = scp->cmnd;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004215 struct sdeb_store_info *sip = devip2sip(devip, true);
4216 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004217
4218 bytchk = (cmd[1] >> 1) & 0x3;
4219 if (bytchk == 0) {
4220 return 0; /* always claim internal verify okay */
4221 } else if (bytchk == 2) {
4222 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4223 return check_condition_result;
4224 } else if (bytchk == 3) {
4225 is_bytchk3 = true; /* 1 block sent, compared repeatedly */
4226 }
4227 switch (cmd[0]) {
4228 case VERIFY_16:
4229 lba = get_unaligned_be64(cmd + 2);
4230 vnum = get_unaligned_be32(cmd + 10);
4231 break;
4232 case VERIFY: /* is VERIFY(10) */
4233 lba = get_unaligned_be32(cmd + 2);
4234 vnum = get_unaligned_be16(cmd + 7);
4235 break;
4236 default:
4237 mk_sense_invalid_opcode(scp);
4238 return check_condition_result;
4239 }
4240 a_num = is_bytchk3 ? 1 : vnum;
4241 /* Treat following check like one for read (i.e. no write) access */
4242 ret = check_device_access_params(scp, lba, a_num, false);
4243 if (ret)
4244 return ret;
4245
4246 arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4247 if (!arr) {
4248 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4249 INSUFF_RES_ASCQ);
4250 return check_condition_result;
4251 }
4252 /* Not changing store, so only need read access */
Douglas Gilbert67da4132020-04-21 11:14:20 -04004253 read_lock(macc_lckp);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004254
4255 ret = do_dout_fetch(scp, a_num, arr);
4256 if (ret == -1) {
4257 ret = DID_ERROR << 16;
4258 goto cleanup;
4259 } else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4260 sdev_printk(KERN_INFO, scp->device,
4261 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4262 my_name, __func__, a_num * lb_size, ret);
4263 }
4264 if (is_bytchk3) {
4265 for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4266 memcpy(arr + off, arr, lb_size);
4267 }
4268 ret = 0;
4269 if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4270 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4271 ret = check_condition_result;
4272 goto cleanup;
4273 }
4274cleanup:
Douglas Gilbert67da4132020-04-21 11:14:20 -04004275 read_unlock(macc_lckp);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004276 kfree(arr);
4277 return ret;
4278}
4279
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004280#define RZONES_DESC_HD 64
4281
4282/* Report zones depending on start LBA nad reporting options */
4283static int resp_report_zones(struct scsi_cmnd *scp,
4284 struct sdebug_dev_info *devip)
4285{
4286 unsigned int i, max_zones, rep_max_zones, nrz = 0;
4287 int ret = 0;
4288 u32 alloc_len, rep_opts, rep_len;
4289 bool partial;
4290 u64 lba, zs_lba;
4291 u8 *arr = NULL, *desc;
4292 u8 *cmd = scp->cmnd;
4293 struct sdeb_zone_state *zsp;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004294 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004295 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4296
4297 if (!sdebug_dev_is_zoned(devip)) {
4298 mk_sense_invalid_opcode(scp);
4299 return check_condition_result;
4300 }
4301 zs_lba = get_unaligned_be64(cmd + 2);
4302 alloc_len = get_unaligned_be32(cmd + 10);
4303 rep_opts = cmd[14] & 0x3f;
4304 partial = cmd[14] & 0x80;
4305
4306 if (zs_lba >= sdebug_capacity) {
4307 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4308 return check_condition_result;
4309 }
4310
Damien Le Moal108e36f2020-05-07 11:35:26 +09004311 max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004312 rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4313 max_zones);
4314
4315 arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4316 if (!arr) {
4317 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4318 INSUFF_RES_ASCQ);
4319 return check_condition_result;
4320 }
4321
4322 read_lock(macc_lckp);
4323
4324 desc = arr + 64;
4325 for (i = 0; i < max_zones; i++) {
4326 lba = zs_lba + devip->zsize * i;
4327 if (lba > sdebug_capacity)
4328 break;
4329 zsp = zbc_zone(devip, lba);
4330 switch (rep_opts) {
4331 case 0x00:
4332 /* All zones */
4333 break;
4334 case 0x01:
4335 /* Empty zones */
4336 if (zsp->z_cond != ZC1_EMPTY)
4337 continue;
4338 break;
4339 case 0x02:
4340 /* Implicit open zones */
4341 if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4342 continue;
4343 break;
4344 case 0x03:
4345 /* Explicit open zones */
4346 if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4347 continue;
4348 break;
4349 case 0x04:
4350 /* Closed zones */
4351 if (zsp->z_cond != ZC4_CLOSED)
4352 continue;
4353 break;
4354 case 0x05:
4355 /* Full zones */
4356 if (zsp->z_cond != ZC5_FULL)
4357 continue;
4358 break;
4359 case 0x06:
4360 case 0x07:
4361 case 0x10:
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004362 /*
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004363 * Read-only, offline, reset WP recommended are
4364 * not emulated: no zones to report;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004365 */
4366 continue;
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004367 case 0x11:
4368 /* non-seq-resource set */
4369 if (!zsp->z_non_seq_resource)
4370 continue;
4371 break;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004372 case 0x3f:
4373 /* Not write pointer (conventional) zones */
4374 if (!zbc_zone_is_conv(zsp))
4375 continue;
4376 break;
4377 default:
4378 mk_sense_buffer(scp, ILLEGAL_REQUEST,
4379 INVALID_FIELD_IN_CDB, 0);
4380 ret = check_condition_result;
4381 goto fini;
4382 }
4383
4384 if (nrz < rep_max_zones) {
4385 /* Fill zone descriptor */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004386 desc[0] = zsp->z_type;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004387 desc[1] = zsp->z_cond << 4;
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004388 if (zsp->z_non_seq_resource)
4389 desc[1] |= 1 << 1;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004390 put_unaligned_be64((u64)zsp->z_size, desc + 8);
4391 put_unaligned_be64((u64)zsp->z_start, desc + 16);
4392 put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4393 desc += 64;
4394 }
4395
4396 if (partial && nrz >= rep_max_zones)
4397 break;
4398
4399 nrz++;
4400 }
4401
4402 /* Report header */
4403 put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4404 put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4405
4406 rep_len = (unsigned long)desc - (unsigned long)arr;
4407 ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4408
4409fini:
4410 read_unlock(macc_lckp);
4411 kfree(arr);
4412 return ret;
4413}
4414
4415/* Logic transplanted from tcmu-runner, file_zbc.c */
4416static void zbc_open_all(struct sdebug_dev_info *devip)
4417{
4418 struct sdeb_zone_state *zsp = &devip->zstate[0];
4419 unsigned int i;
4420
4421 for (i = 0; i < devip->nr_zones; i++, zsp++) {
4422 if (zsp->z_cond == ZC4_CLOSED)
4423 zbc_open_zone(devip, &devip->zstate[i], true);
4424 }
4425}
4426
4427static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4428{
4429 int res = 0;
4430 u64 z_id;
4431 enum sdebug_z_cond zc;
4432 u8 *cmd = scp->cmnd;
4433 struct sdeb_zone_state *zsp;
4434 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004435 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004436 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4437
4438 if (!sdebug_dev_is_zoned(devip)) {
4439 mk_sense_invalid_opcode(scp);
4440 return check_condition_result;
4441 }
4442
4443 write_lock(macc_lckp);
4444
4445 if (all) {
4446 /* Check if all closed zones can be open */
4447 if (devip->max_open &&
4448 devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4449 mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4450 INSUFF_ZONE_ASCQ);
4451 res = check_condition_result;
4452 goto fini;
4453 }
4454 /* Open all closed zones */
4455 zbc_open_all(devip);
4456 goto fini;
4457 }
4458
4459 /* Open the specified zone */
4460 z_id = get_unaligned_be64(cmd + 2);
4461 if (z_id >= sdebug_capacity) {
4462 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4463 res = check_condition_result;
4464 goto fini;
4465 }
4466
4467 zsp = zbc_zone(devip, z_id);
4468 if (z_id != zsp->z_start) {
4469 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4470 res = check_condition_result;
4471 goto fini;
4472 }
4473 if (zbc_zone_is_conv(zsp)) {
4474 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4475 res = check_condition_result;
4476 goto fini;
4477 }
4478
4479 zc = zsp->z_cond;
4480 if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4481 goto fini;
4482
4483 if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4484 mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4485 INSUFF_ZONE_ASCQ);
4486 res = check_condition_result;
4487 goto fini;
4488 }
4489
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004490 zbc_open_zone(devip, zsp, true);
4491fini:
4492 write_unlock(macc_lckp);
4493 return res;
4494}
4495
4496static void zbc_close_all(struct sdebug_dev_info *devip)
4497{
4498 unsigned int i;
4499
4500 for (i = 0; i < devip->nr_zones; i++)
4501 zbc_close_zone(devip, &devip->zstate[i]);
4502}
4503
4504static int resp_close_zone(struct scsi_cmnd *scp,
4505 struct sdebug_dev_info *devip)
4506{
4507 int res = 0;
4508 u64 z_id;
4509 u8 *cmd = scp->cmnd;
4510 struct sdeb_zone_state *zsp;
4511 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004512 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004513 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4514
4515 if (!sdebug_dev_is_zoned(devip)) {
4516 mk_sense_invalid_opcode(scp);
4517 return check_condition_result;
4518 }
4519
4520 write_lock(macc_lckp);
4521
4522 if (all) {
4523 zbc_close_all(devip);
4524 goto fini;
4525 }
4526
4527 /* Close specified zone */
4528 z_id = get_unaligned_be64(cmd + 2);
4529 if (z_id >= sdebug_capacity) {
4530 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4531 res = check_condition_result;
4532 goto fini;
4533 }
4534
4535 zsp = zbc_zone(devip, z_id);
4536 if (z_id != zsp->z_start) {
4537 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4538 res = check_condition_result;
4539 goto fini;
4540 }
4541 if (zbc_zone_is_conv(zsp)) {
4542 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4543 res = check_condition_result;
4544 goto fini;
4545 }
4546
4547 zbc_close_zone(devip, zsp);
4548fini:
4549 write_unlock(macc_lckp);
4550 return res;
4551}
4552
4553static void zbc_finish_zone(struct sdebug_dev_info *devip,
4554 struct sdeb_zone_state *zsp, bool empty)
4555{
4556 enum sdebug_z_cond zc = zsp->z_cond;
4557
4558 if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4559 zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4560 if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4561 zbc_close_zone(devip, zsp);
4562 if (zsp->z_cond == ZC4_CLOSED)
4563 devip->nr_closed--;
4564 zsp->z_wp = zsp->z_start + zsp->z_size;
4565 zsp->z_cond = ZC5_FULL;
4566 }
4567}
4568
4569static void zbc_finish_all(struct sdebug_dev_info *devip)
4570{
4571 unsigned int i;
4572
4573 for (i = 0; i < devip->nr_zones; i++)
4574 zbc_finish_zone(devip, &devip->zstate[i], false);
4575}
4576
4577static int resp_finish_zone(struct scsi_cmnd *scp,
4578 struct sdebug_dev_info *devip)
4579{
4580 struct sdeb_zone_state *zsp;
4581 int res = 0;
4582 u64 z_id;
4583 u8 *cmd = scp->cmnd;
4584 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004585 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004586 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4587
4588 if (!sdebug_dev_is_zoned(devip)) {
4589 mk_sense_invalid_opcode(scp);
4590 return check_condition_result;
4591 }
4592
4593 write_lock(macc_lckp);
4594
4595 if (all) {
4596 zbc_finish_all(devip);
4597 goto fini;
4598 }
4599
4600 /* Finish the specified zone */
4601 z_id = get_unaligned_be64(cmd + 2);
4602 if (z_id >= sdebug_capacity) {
4603 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4604 res = check_condition_result;
4605 goto fini;
4606 }
4607
4608 zsp = zbc_zone(devip, z_id);
4609 if (z_id != zsp->z_start) {
4610 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4611 res = check_condition_result;
4612 goto fini;
4613 }
4614 if (zbc_zone_is_conv(zsp)) {
4615 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4616 res = check_condition_result;
4617 goto fini;
4618 }
4619
4620 zbc_finish_zone(devip, zsp, true);
4621fini:
4622 write_unlock(macc_lckp);
4623 return res;
4624}
4625
4626static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4627 struct sdeb_zone_state *zsp)
4628{
4629 enum sdebug_z_cond zc;
4630
4631 if (zbc_zone_is_conv(zsp))
4632 return;
4633
4634 zc = zsp->z_cond;
4635 if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4636 zbc_close_zone(devip, zsp);
4637
4638 if (zsp->z_cond == ZC4_CLOSED)
4639 devip->nr_closed--;
4640
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004641 zsp->z_non_seq_resource = false;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004642 zsp->z_wp = zsp->z_start;
4643 zsp->z_cond = ZC1_EMPTY;
4644}
4645
4646static void zbc_rwp_all(struct sdebug_dev_info *devip)
4647{
4648 unsigned int i;
4649
4650 for (i = 0; i < devip->nr_zones; i++)
4651 zbc_rwp_zone(devip, &devip->zstate[i]);
4652}
4653
4654static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4655{
4656 struct sdeb_zone_state *zsp;
4657 int res = 0;
4658 u64 z_id;
4659 u8 *cmd = scp->cmnd;
4660 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004661 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004662 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4663
4664 if (!sdebug_dev_is_zoned(devip)) {
4665 mk_sense_invalid_opcode(scp);
4666 return check_condition_result;
4667 }
4668
4669 write_lock(macc_lckp);
4670
4671 if (all) {
4672 zbc_rwp_all(devip);
4673 goto fini;
4674 }
4675
4676 z_id = get_unaligned_be64(cmd + 2);
4677 if (z_id >= sdebug_capacity) {
4678 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4679 res = check_condition_result;
4680 goto fini;
4681 }
4682
4683 zsp = zbc_zone(devip, z_id);
4684 if (z_id != zsp->z_start) {
4685 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4686 res = check_condition_result;
4687 goto fini;
4688 }
4689 if (zbc_zone_is_conv(zsp)) {
4690 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4691 res = check_condition_result;
4692 goto fini;
4693 }
4694
4695 zbc_rwp_zone(devip, zsp);
4696fini:
4697 write_unlock(macc_lckp);
4698 return res;
4699}
4700
Douglas Gilbertc4837392016-05-06 00:40:26 -04004701static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4702{
John Garryc10fa552020-07-09 20:23:20 +08004703 u16 hwq;
John Garryf7c4cdc2020-08-19 23:20:33 +08004704 u32 tag = blk_mq_unique_tag(cmnd->request);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004705
John Garryf7c4cdc2020-08-19 23:20:33 +08004706 hwq = blk_mq_unique_tag_to_hwq(tag);
John Garryc10fa552020-07-09 20:23:20 +08004707
John Garryf7c4cdc2020-08-19 23:20:33 +08004708 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4709 if (WARN_ON_ONCE(hwq >= submit_queues))
4710 hwq = 0;
John Garryc10fa552020-07-09 20:23:20 +08004711
Bart Van Assche458df782018-01-26 08:52:19 -08004712 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004713}
4714
John Garryc10fa552020-07-09 20:23:20 +08004715static u32 get_tag(struct scsi_cmnd *cmnd)
4716{
4717 return blk_mq_unique_tag(cmnd->request);
4718}
4719
Douglas Gilbertc4837392016-05-06 00:40:26 -04004720/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004721static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722{
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004723 bool aborted = sd_dp->aborted;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004724 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004725 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004727 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004728 struct sdebug_queued_cmd *sqcp;
4729 struct scsi_cmnd *scp;
4730 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731
Douglas Gilbert10bde982018-01-10 16:57:31 -05004732 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004733 if (unlikely(aborted))
4734 sd_dp->aborted = false;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004735 qc_idx = sd_dp->qc_idx;
4736 sqp = sdebug_q_arr + sd_dp->sqa_idx;
4737 if (sdebug_statistics) {
4738 atomic_inc(&sdebug_completions);
4739 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4740 atomic_inc(&sdebug_miss_cpus);
4741 }
4742 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4743 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 return;
4745 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004746 spin_lock_irqsave(&sqp->qc_lock, iflags);
4747 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004748 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004749 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004750 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
John Garryc10fa552020-07-09 20:23:20 +08004751 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4752 sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 return;
4754 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004755 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004756 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004757 atomic_dec(&devip->num_in_q);
4758 else
Tomas Winklerc12879702015-07-28 16:54:20 +03004759 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004760 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004761 retiring = 1;
4762
4763 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004764 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4765 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03004766 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004767 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004769
4770 if (unlikely(retiring)) { /* user has reduced max_queue */
4771 int k, retval;
4772
4773 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004774 if (qc_idx >= retval) {
4775 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03004776 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004777 return;
4778 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004779 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004780 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004781 atomic_set(&retired_max_queue, 0);
4782 else
4783 atomic_set(&retired_max_queue, k + 1);
4784 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004785 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004786 if (unlikely(aborted)) {
4787 if (sdebug_verbose)
4788 pr_info("bypassing scsi_done() due to aborted cmd\n");
4789 return;
4790 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004791 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792}
4793
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004794/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004795static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004796{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004797 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4798 hrt);
4799 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004800 return HRTIMER_NORESTART;
4801}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802
Douglas Gilberta10bc122016-04-25 12:16:32 -04004803/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004804static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04004805{
4806 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4807 ew.work);
4808 sdebug_q_cmd_complete(sd_dp);
4809}
4810
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004811static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02004812static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004813
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004814static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4815{
4816 struct sdeb_zone_state *zsp;
4817 sector_t capacity = get_sdebug_capacity();
4818 sector_t zstart = 0;
4819 unsigned int i;
4820
4821 /*
Damien Le Moal98e0a682020-04-22 19:42:20 +09004822 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
4823 * a zone size allowing for at least 4 zones on the device. Otherwise,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004824 * use the specified zone size checking that at least 2 zones can be
4825 * created for the device.
4826 */
Damien Le Moal98e0a682020-04-22 19:42:20 +09004827 if (!sdeb_zbc_zone_size_mb) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004828 devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4829 >> ilog2(sdebug_sector_size);
4830 while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4831 devip->zsize >>= 1;
4832 if (devip->zsize < 2) {
4833 pr_err("Device capacity too small\n");
4834 return -EINVAL;
4835 }
4836 } else {
Damien Le Moal108e36f2020-05-07 11:35:26 +09004837 if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4838 pr_err("Zone size is not a power of 2\n");
4839 return -EINVAL;
4840 }
Damien Le Moal98e0a682020-04-22 19:42:20 +09004841 devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004842 >> ilog2(sdebug_sector_size);
4843 if (devip->zsize >= capacity) {
4844 pr_err("Zone size too large for device capacity\n");
4845 return -EINVAL;
4846 }
4847 }
4848
Damien Le Moal108e36f2020-05-07 11:35:26 +09004849 devip->zsize_shift = ilog2(devip->zsize);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004850 devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4851
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09004852 if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4853 pr_err("Number of conventional zones too large\n");
4854 return -EINVAL;
4855 }
4856 devip->nr_conv_zones = sdeb_zbc_nr_conv;
4857
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004858 if (devip->zmodel == BLK_ZONED_HM) {
4859 /* zbc_max_open_zones can be 0, meaning "not reported" */
4860 if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4861 devip->max_open = (devip->nr_zones - 1) / 2;
4862 else
4863 devip->max_open = sdeb_zbc_max_open;
4864 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004865
4866 devip->zstate = kcalloc(devip->nr_zones,
4867 sizeof(struct sdeb_zone_state), GFP_KERNEL);
4868 if (!devip->zstate)
4869 return -ENOMEM;
4870
4871 for (i = 0; i < devip->nr_zones; i++) {
4872 zsp = &devip->zstate[i];
4873
4874 zsp->z_start = zstart;
4875
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09004876 if (i < devip->nr_conv_zones) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004877 zsp->z_type = ZBC_ZONE_TYPE_CNV;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004878 zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4879 zsp->z_wp = (sector_t)-1;
4880 } else {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004881 if (devip->zmodel == BLK_ZONED_HM)
4882 zsp->z_type = ZBC_ZONE_TYPE_SWR;
4883 else
4884 zsp->z_type = ZBC_ZONE_TYPE_SWP;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004885 zsp->z_cond = ZC1_EMPTY;
4886 zsp->z_wp = zsp->z_start;
4887 }
4888
4889 if (zsp->z_start + devip->zsize < capacity)
4890 zsp->z_size = devip->zsize;
4891 else
4892 zsp->z_size = capacity - zsp->z_start;
4893
4894 zstart += zsp->z_size;
4895 }
4896
4897 return 0;
4898}
4899
Douglas Gilbertfd321192016-04-25 12:16:33 -04004900static struct sdebug_dev_info *sdebug_device_create(
4901 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004902{
4903 struct sdebug_dev_info *devip;
4904
4905 devip = kzalloc(sizeof(*devip), flags);
4906 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004907 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02004908 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004909 else if (sdebug_uuid_ctl == 2) {
4910 if (got_shared_uuid)
4911 devip->lu_name = shared_uuid;
4912 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02004913 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004914 got_shared_uuid = true;
4915 devip->lu_name = shared_uuid;
4916 }
4917 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004918 devip->sdbg_host = sdbg_host;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004919 if (sdeb_zbc_in_use) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004920 devip->zmodel = sdeb_zbc_model;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004921 if (sdebug_device_create_zones(devip)) {
4922 kfree(devip);
4923 return NULL;
4924 }
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004925 } else {
4926 devip->zmodel = BLK_ZONED_NONE;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004927 }
4928 devip->sdbg_host = sdbg_host;
Douglas Gilbertfc136382020-07-24 11:55:31 -04004929 devip->create_ts = ktime_get_boottime();
4930 atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004931 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
4932 }
4933 return devip;
4934}
4935
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004936static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004938 struct sdebug_host_info *sdbg_host;
4939 struct sdebug_dev_info *open_devip = NULL;
4940 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004942 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
4943 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004944 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004946 }
Douglas Gilbertad0c7772020-08-21 00:22:49 -04004947
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
4949 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05004950 (devip->target == sdev->id) &&
4951 (devip->lun == sdev->lun))
4952 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 else {
4954 if ((!devip->used) && (!open_devip))
4955 open_devip = devip;
4956 }
4957 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004958 if (!open_devip) { /* try and make a new one */
4959 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
4960 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004961 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962 return NULL;
4963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09004965
4966 open_devip->channel = sdev->channel;
4967 open_devip->target = sdev->id;
4968 open_devip->lun = sdev->lun;
4969 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004970 atomic_set(&open_devip->num_in_q, 0);
4971 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004972 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09004973 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974}
4975
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004976static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004978 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03004979 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004980 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004981 return 0;
4982}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004984static int scsi_debug_slave_configure(struct scsi_device *sdp)
4985{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004986 struct sdebug_dev_info *devip =
4987 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09004988
Douglas Gilbert773642d2016-04-25 12:16:28 -04004989 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03004990 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004991 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004992 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4993 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4994 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004995 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004996 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004997 return 1; /* no resources, will be marked offline */
4998 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01004999 sdp->hostdata = devip;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005000 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005001 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005002 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005003 return 0;
5004}
5005
5006static void scsi_debug_slave_destroy(struct scsi_device *sdp)
5007{
5008 struct sdebug_dev_info *devip =
5009 (struct sdebug_dev_info *)sdp->hostdata;
5010
Douglas Gilbert773642d2016-04-25 12:16:28 -04005011 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03005012 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005013 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5014 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005015 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005016 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005017 sdp->hostdata = NULL;
5018 }
5019}
5020
Douglas Gilbert10bde982018-01-10 16:57:31 -05005021static void stop_qc_helper(struct sdebug_defer *sd_dp,
5022 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005023{
5024 if (!sd_dp)
5025 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005026 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005027 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005028 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005029 cancel_work_sync(&sd_dp->ew.work);
5030}
5031
Douglas Gilberta10bc122016-04-25 12:16:32 -04005032/* If @cmnd found deletes its timer or work queue and returns true; else
5033 returns false */
5034static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005035{
5036 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005037 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005038 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005039 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005040 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005041 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005042 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005043
Douglas Gilbertc4837392016-05-06 00:40:26 -04005044 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5045 spin_lock_irqsave(&sqp->qc_lock, iflags);
5046 qmax = sdebug_max_queue;
5047 r_qmax = atomic_read(&retired_max_queue);
5048 if (r_qmax > qmax)
5049 qmax = r_qmax;
5050 for (k = 0; k < qmax; ++k) {
5051 if (test_bit(k, sqp->in_use_bm)) {
5052 sqcp = &sqp->qc_arr[k];
5053 if (cmnd != sqcp->a_cmnd)
5054 continue;
5055 /* found */
5056 devip = (struct sdebug_dev_info *)
5057 cmnd->device->hostdata;
5058 if (devip)
5059 atomic_dec(&devip->num_in_q);
5060 sqcp->a_cmnd = NULL;
5061 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005062 if (sd_dp) {
5063 l_defer_t = sd_dp->defer_t;
5064 sd_dp->defer_t = SDEB_DEFER_NONE;
5065 } else
5066 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005067 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005068 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005069 clear_bit(k, sqp->in_use_bm);
5070 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005071 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005072 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005073 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005074 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04005075 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005076}
5077
Douglas Gilberta10bc122016-04-25 12:16:32 -04005078/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005079static void stop_all_queued(void)
5080{
5081 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005082 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005083 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005084 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005085 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005086 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005087 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005088
Douglas Gilbertc4837392016-05-06 00:40:26 -04005089 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5090 spin_lock_irqsave(&sqp->qc_lock, iflags);
5091 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5092 if (test_bit(k, sqp->in_use_bm)) {
5093 sqcp = &sqp->qc_arr[k];
5094 if (sqcp->a_cmnd == NULL)
5095 continue;
5096 devip = (struct sdebug_dev_info *)
5097 sqcp->a_cmnd->device->hostdata;
5098 if (devip)
5099 atomic_dec(&devip->num_in_q);
5100 sqcp->a_cmnd = NULL;
5101 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005102 if (sd_dp) {
5103 l_defer_t = sd_dp->defer_t;
5104 sd_dp->defer_t = SDEB_DEFER_NONE;
5105 } else
5106 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005107 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005108 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005109 clear_bit(k, sqp->in_use_bm);
5110 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005111 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005112 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005113 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115}
5116
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005117/* Free queued command memory on heap */
5118static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005120 int j, k;
5121 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005122 struct sdebug_queued_cmd *sqcp;
5123
Douglas Gilbertc4837392016-05-06 00:40:26 -04005124 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5125 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5126 sqcp = &sqp->qc_arr[k];
5127 kfree(sqcp->sd_dp);
5128 sqcp->sd_dp = NULL;
5129 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131}
5132
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005133static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134{
Douglas Gilberta10bc122016-04-25 12:16:32 -04005135 bool ok;
5136
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005137 ++num_aborts;
5138 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04005139 ok = stop_queued_cmnd(SCpnt);
5140 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5141 sdev_printk(KERN_INFO, SCpnt->device,
5142 "%s: command%s found\n", __func__,
5143 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005145 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146}
5147
John Pittman91d4c752018-02-09 21:12:43 -05005148static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005151 if (SCpnt && SCpnt->device) {
5152 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005153 struct sdebug_dev_info *devip =
5154 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005155
Douglas Gilbert773642d2016-04-25 12:16:28 -04005156 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005157 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005159 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 }
5161 return SUCCESS;
5162}
5163
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005164static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5165{
5166 struct sdebug_host_info *sdbg_host;
5167 struct sdebug_dev_info *devip;
5168 struct scsi_device *sdp;
5169 struct Scsi_Host *hp;
5170 int k = 0;
5171
5172 ++num_target_resets;
5173 if (!SCpnt)
5174 goto lie;
5175 sdp = SCpnt->device;
5176 if (!sdp)
5177 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005178 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005179 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5180 hp = sdp->host;
5181 if (!hp)
5182 goto lie;
5183 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5184 if (sdbg_host) {
5185 list_for_each_entry(devip,
5186 &sdbg_host->dev_info_list,
5187 dev_list)
5188 if (devip->target == sdp->id) {
5189 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5190 ++k;
5191 }
5192 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005193 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005194 sdev_printk(KERN_INFO, sdp,
5195 "%s: %d device(s) found in target\n", __func__, k);
5196lie:
5197 return SUCCESS;
5198}
5199
John Pittman91d4c752018-02-09 21:12:43 -05005200static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201{
5202 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005203 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005204 struct scsi_device *sdp;
5205 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005206 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005209 if (!(SCpnt && SCpnt->device))
5210 goto lie;
5211 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005212 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005213 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5214 hp = sdp->host;
5215 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09005216 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005218 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05005219 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005220 dev_list) {
5221 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5222 ++k;
5223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 }
5225 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005226 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005227 sdev_printk(KERN_INFO, sdp,
5228 "%s: %d device(s) found in host\n", __func__, k);
5229lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 return SUCCESS;
5231}
5232
John Pittman91d4c752018-02-09 21:12:43 -05005233static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234{
John Pittman91d4c752018-02-09 21:12:43 -05005235 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005236 struct sdebug_dev_info *devip;
5237 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005240 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005241 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005242 spin_lock(&sdebug_host_list_lock);
5243 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005244 list_for_each_entry(devip, &sdbg_host->dev_info_list,
5245 dev_list) {
5246 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5247 ++k;
5248 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005249 }
5250 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04005252 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005253 sdev_printk(KERN_INFO, SCpnt->device,
5254 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 return SUCCESS;
5256}
5257
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005258static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259{
Christoph Hellwig1442f762020-03-24 08:25:26 +01005260 struct msdos_partition *pp;
John Pittman979e0dc2020-09-02 17:14:33 -04005261 int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 int sectors_per_part, num_sectors, k;
5263 int heads_by_sects, start_sec, end_sec;
5264
5265 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005266 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005268 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5269 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03005270 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 }
John Pittman8c657232020-09-02 17:14:34 -04005272 num_sectors = (int)get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04005274 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005276 starts[0] = sdebug_sectors_per;
John Pittman979e0dc2020-09-02 17:14:33 -04005277 max_part_secs = sectors_per_part;
5278 for (k = 1; k < sdebug_num_parts; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 starts[k] = ((k * sectors_per_part) / heads_by_sects)
5280 * heads_by_sects;
John Pittman979e0dc2020-09-02 17:14:33 -04005281 if (starts[k] - starts[k - 1] < max_part_secs)
5282 max_part_secs = starts[k] - starts[k - 1];
5283 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005284 starts[sdebug_num_parts] = num_sectors;
5285 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286
5287 ramp[510] = 0x55; /* magic partition markings */
5288 ramp[511] = 0xAA;
Christoph Hellwig1442f762020-03-24 08:25:26 +01005289 pp = (struct msdos_partition *)(ramp + 0x1be);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 for (k = 0; starts[k + 1]; ++k, ++pp) {
5291 start_sec = starts[k];
John Pittman979e0dc2020-09-02 17:14:33 -04005292 end_sec = starts[k] + max_part_secs - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 pp->boot_ind = 0;
5294
5295 pp->cyl = start_sec / heads_by_sects;
5296 pp->head = (start_sec - (pp->cyl * heads_by_sects))
5297 / sdebug_sectors_per;
5298 pp->sector = (start_sec % sdebug_sectors_per) + 1;
5299
5300 pp->end_cyl = end_sec / heads_by_sects;
5301 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
5302 / sdebug_sectors_per;
5303 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
5304
Akinobu Mita150c3542013-08-26 22:08:40 +09005305 pp->start_sect = cpu_to_le32(start_sec);
5306 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 pp->sys_ind = 0x83; /* plain Linux partition */
5308 }
5309}
5310
Douglas Gilbertc4837392016-05-06 00:40:26 -04005311static void block_unblock_all_queues(bool block)
5312{
5313 int j;
5314 struct sdebug_queue *sqp;
5315
5316 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5317 atomic_set(&sqp->blocked, (int)block);
5318}
5319
5320/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5321 * commands will be processed normally before triggers occur.
5322 */
5323static void tweak_cmnd_count(void)
5324{
5325 int count, modulo;
5326
5327 modulo = abs(sdebug_every_nth);
5328 if (modulo < 2)
5329 return;
5330 block_unblock_all_queues(true);
5331 count = atomic_read(&sdebug_cmnd_count);
5332 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5333 block_unblock_all_queues(false);
5334}
5335
5336static void clear_queue_stats(void)
5337{
5338 atomic_set(&sdebug_cmnd_count, 0);
5339 atomic_set(&sdebug_completions, 0);
5340 atomic_set(&sdebug_miss_cpus, 0);
5341 atomic_set(&sdebug_a_tsf, 0);
5342}
5343
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005344static bool inject_on_this_cmd(void)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005345{
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005346 if (sdebug_every_nth == 0)
5347 return false;
5348 return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005349}
5350
Douglas Gilberta2aede92020-04-21 11:14:21 -04005351#define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */
5352
Douglas Gilbertc4837392016-05-06 00:40:26 -04005353/* Complete the processing of the thread that queued a SCSI command to this
5354 * driver. It either completes the command by calling cmnd_done() or
5355 * schedules a hr timer or work queue then returns 0. Returns
5356 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5357 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04005358static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Martin Wilckf66b8512018-02-14 11:05:57 +01005359 int scsi_result,
5360 int (*pfp)(struct scsi_cmnd *,
5361 struct sdebug_dev_info *),
5362 int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363{
Douglas Gilberta2aede92020-04-21 11:14:21 -04005364 bool new_sd_dp;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005365 bool inject = false;
5366 int k, num_in_q, qdepth;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005367 unsigned long iflags;
5368 u64 ns_from_boot = 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005369 struct sdebug_queue *sqp;
5370 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03005371 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005372 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005374 if (unlikely(devip == NULL)) {
5375 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005376 scsi_result = DID_NO_CONNECT << 16;
5377 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03005379 sdp = cmnd->device;
5380
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005381 if (delta_jiff == 0)
5382 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383
Douglas Gilbertc4837392016-05-06 00:40:26 -04005384 sqp = get_queue(cmnd);
5385 spin_lock_irqsave(&sqp->qc_lock, iflags);
5386 if (unlikely(atomic_read(&sqp->blocked))) {
5387 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5388 return SCSI_MLQUEUE_HOST_BUSY;
5389 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005390 num_in_q = atomic_read(&devip->num_in_q);
5391 qdepth = cmnd->device->queue_depth;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005392 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005393 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005394 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005395 goto respond_in_thread;
5396 } else
5397 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005398 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005399 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5400 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005401 if ((num_in_q == (qdepth - 1)) &&
5402 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04005403 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005404 atomic_set(&sdebug_a_tsf, 0);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005405 inject = true;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005406 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005408 }
5409
Douglas Gilbertc4837392016-05-06 00:40:26 -04005410 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005411 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005412 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005413 if (scsi_result)
5414 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005415 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005416 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005417 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005418 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005419 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04005420 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005421 (scsi_result ? "status: TASK SET FULL" :
5422 "report: host busy"));
5423 if (scsi_result)
5424 goto respond_in_thread;
5425 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005426 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 }
Douglas Gilbert74595c02020-07-02 10:53:55 -04005428 set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005429 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005430 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005431 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005432 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005433 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005434 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert74595c02020-07-02 10:53:55 -04005435 if (!sd_dp) {
Douglas Gilbert10bde982018-01-10 16:57:31 -05005436 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
Douglas Gilbert74595c02020-07-02 10:53:55 -04005437 if (!sd_dp) {
5438 atomic_dec(&devip->num_in_q);
5439 clear_bit(k, sqp->in_use_bm);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005440 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilbert74595c02020-07-02 10:53:55 -04005441 }
Douglas Gilberta2aede92020-04-21 11:14:21 -04005442 new_sd_dp = true;
5443 } else {
5444 new_sd_dp = false;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005445 }
Martin Wilckf66b8512018-02-14 11:05:57 +01005446
John Garryc10fa552020-07-09 20:23:20 +08005447 /* Set the hostwide tag */
5448 if (sdebug_host_max_queue)
5449 sd_dp->hc_idx = get_tag(cmnd);
5450
Douglas Gilberta2aede92020-04-21 11:14:21 -04005451 if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)
5452 ns_from_boot = ktime_get_boottime_ns();
5453
5454 /* one of the resp_*() response functions is called here */
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005455 cmnd->result = pfp ? pfp(cmnd, devip) : 0;
Martin Wilckf66b8512018-02-14 11:05:57 +01005456 if (cmnd->result & SDEG_RES_IMMED_MASK) {
Martin Wilckf66b8512018-02-14 11:05:57 +01005457 cmnd->result &= ~SDEG_RES_IMMED_MASK;
5458 delta_jiff = ndelay = 0;
5459 }
5460 if (cmnd->result == 0 && scsi_result != 0)
5461 cmnd->result = scsi_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005462 if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
5463 if (atomic_read(&sdeb_inject_pending)) {
5464 mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
5465 atomic_set(&sdeb_inject_pending, 0);
5466 cmnd->result = check_condition_result;
5467 }
5468 }
Martin Wilckf66b8512018-02-14 11:05:57 +01005469
5470 if (unlikely(sdebug_verbose && cmnd->result))
5471 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5472 __func__, cmnd->result);
5473
Douglas Gilbert10bde982018-01-10 16:57:31 -05005474 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04005475 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005476
Douglas Gilbertb333a812016-04-25 12:16:30 -04005477 if (delta_jiff > 0) {
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005478 u64 ns = jiffies_to_nsecs(delta_jiff);
5479
5480 if (sdebug_random && ns < U32_MAX) {
5481 ns = prandom_u32_max((u32)ns);
5482 } else if (sdebug_random) {
5483 ns >>= 12; /* scale to 4 usec precision */
5484 if (ns < U32_MAX) /* over 4 hours max */
5485 ns = prandom_u32_max((u32)ns);
5486 ns <<= 12;
5487 }
5488 kt = ns_to_ktime(ns);
5489 } else { /* ndelay has a 4.2 second max */
5490 kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
5491 (u32)ndelay;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005492 if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5493 u64 d = ktime_get_boottime_ns() - ns_from_boot;
5494
5495 if (kt <= d) { /* elapsed duration >= kt */
Douglas Gilbert223f91b2020-08-13 11:57:38 -04005496 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005497 sqcp->a_cmnd = NULL;
5498 atomic_dec(&devip->num_in_q);
5499 clear_bit(k, sqp->in_use_bm);
Douglas Gilbert223f91b2020-08-13 11:57:38 -04005500 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005501 if (new_sd_dp)
5502 kfree(sd_dp);
5503 /* call scsi_done() from this thread */
5504 cmnd->scsi_done(cmnd);
5505 return 0;
5506 }
5507 /* otherwise reduce kt by elapsed time */
5508 kt -= d;
5509 }
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005510 }
Douglas Gilbert10bde982018-01-10 16:57:31 -05005511 if (!sd_dp->init_hrt) {
5512 sd_dp->init_hrt = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005513 sqcp->sd_dp = sd_dp;
5514 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005515 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04005516 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005517 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5518 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005519 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005520 if (sdebug_statistics)
5521 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05005522 sd_dp->defer_t = SDEB_DEFER_HRT;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005523 /* schedule the invocation of scsi_done() for a later time */
Douglas Gilbertc4837392016-05-06 00:40:26 -04005524 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
5525 } else { /* jdelay < 0, use work queue */
Douglas Gilbert10bde982018-01-10 16:57:31 -05005526 if (!sd_dp->init_wq) {
5527 sd_dp->init_wq = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005528 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005529 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5530 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005531 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005532 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005533 if (sdebug_statistics)
5534 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05005535 sd_dp->defer_t = SDEB_DEFER_WQ;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005536 if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
5537 atomic_read(&sdeb_inject_pending)))
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005538 sd_dp->aborted = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005539 schedule_work(&sd_dp->ew.work);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005540 if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
5541 atomic_read(&sdeb_inject_pending))) {
5542 sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", cmnd->request->tag);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005543 blk_abort_request(cmnd->request);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005544 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005545 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005546 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005547 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
5548 sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
5549 num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005550 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005551
5552respond_in_thread: /* call back to mid-layer using invocation thread */
Martin Wilckf66b8512018-02-14 11:05:57 +01005553 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5554 cmnd->result &= ~SDEG_RES_IMMED_MASK;
5555 if (cmnd->result == 0 && scsi_result != 0)
5556 cmnd->result = scsi_result;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005557 cmnd->scsi_done(cmnd);
5558 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005560
Douglas Gilbert23183912006-09-16 20:30:47 -04005561/* Note: The following macros create attribute files in the
5562 /sys/module/scsi_debug/parameters directory. Unfortunately this
5563 driver is unaware of a change and cannot trigger auxiliary actions
5564 as it can when the corresponding attribute in the
5565 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
5566 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005567module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5568module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005569module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005570module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04005571module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005572module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5573module_param_named(dif, sdebug_dif, int, S_IRUGO);
5574module_param_named(dix, sdebug_dix, int, S_IRUGO);
5575module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5576module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5577module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5578module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5579module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
John Garryc10fa552020-07-09 20:23:20 +08005580module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005581module_param_string(inq_product, sdebug_inq_product_id,
Douglas Gilbert5d807072020-04-21 11:14:23 -04005582 sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005583module_param_string(inq_rev, sdebug_inq_product_rev,
Douglas Gilbert5d807072020-04-21 11:14:23 -04005584 sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
5585module_param_string(inq_vendor, sdebug_inq_vendor_id,
5586 sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
5587module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005588module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5589module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5590module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005591module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04005592module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005593module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5594module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005595module_param_named(medium_error_count, sdebug_medium_error_count, int,
5596 S_IRUGO | S_IWUSR);
5597module_param_named(medium_error_start, sdebug_medium_error_start, int,
5598 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005599module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5600module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5601module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5602module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5603module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5604module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005605module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005606module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005607module_param_named(per_host_store, sdebug_per_host_store, bool,
5608 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005609module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5610module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005611module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005612module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5613module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5614module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005615module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005616module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005617module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbertfc136382020-07-24 11:55:31 -04005618module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005619module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5620module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5621module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5622module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005623module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005624module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005625module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04005626 S_IRUGO | S_IWUSR);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05005627module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005628module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005629 S_IRUGO | S_IWUSR);
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09005630module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
Damien Le Moal380603a2020-04-22 19:42:18 +09005631module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09005632module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
Damien Le Moal98e0a682020-04-22 19:42:20 +09005633module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634
5635MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
5636MODULE_DESCRIPTION("SCSI debug adapter driver");
5637MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005638MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639
Douglas Gilbert5d807072020-04-21 11:14:23 -04005640MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005641MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005642MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09005643MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005644MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005645MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005646MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
5647MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005648MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07005649MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04005650MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005651MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04005652MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
John Garryc10fa552020-07-09 20:23:20 +08005653MODULE_PARM_DESC(host_max_queue,
5654 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005655MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005656MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
5657 SDEBUG_VERSION "\")");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005658MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
5659MODULE_PARM_DESC(lbprz,
5660 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005661MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
5662MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
5663MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
5664MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005665MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertad0c7772020-08-21 00:22:49 -04005666MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005667MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05005668MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005669MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005670MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005671MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005672MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005674MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05005675MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01005676MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005677MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
5678MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
5679MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005681MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
Martin Pittd9867882012-09-06 12:04:33 +02005682MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005683MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005684MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005685MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005686MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005687MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Douglas Gilbertfc136382020-07-24 11:55:31 -04005688MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005689MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
5690MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04005691MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
5692MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005693MODULE_PARM_DESC(uuid_ctl,
5694 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005695MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005696MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05005697MODULE_PARM_DESC(wp, "Write Protect (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005698MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09005699MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
Damien Le Moal380603a2020-04-22 19:42:18 +09005700MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09005701MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
Damien Le Moal98e0a682020-04-22 19:42:20 +09005702MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005704#define SDEBUG_INFO_LEN 256
5705static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706
John Pittman91d4c752018-02-09 21:12:43 -05005707static const char *scsi_debug_info(struct Scsi_Host *shp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005709 int k;
5710
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005711 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5712 my_name, SDEBUG_VERSION, sdebug_version_date);
5713 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005714 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005715 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5716 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5717 sdebug_dev_size_mb, sdebug_opts, submit_queues,
5718 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719 return sdebug_info;
5720}
5721
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005722/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04005723static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5724 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725{
Al Viroc8ed5552013-03-31 01:46:06 -04005726 char arr[16];
5727 int opts;
5728 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729
Al Viroc8ed5552013-03-31 01:46:06 -04005730 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
5731 return -EACCES;
5732 memcpy(arr, buffer, minLen);
5733 arr[minLen] = '\0';
5734 if (1 != sscanf(arr, "%d", &opts))
5735 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005736 sdebug_opts = opts;
5737 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5738 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5739 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005740 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04005741 return length;
5742}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005744/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5745 * same for each scsi_debug host (if more than one). Some of the counters
5746 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04005747static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5748{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005749 int f, j, l;
5750 struct sdebug_queue *sqp;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005751 struct sdebug_host_info *sdhp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005752
Douglas Gilbertc4837392016-05-06 00:40:26 -04005753 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5754 SDEBUG_VERSION, sdebug_version_date);
5755 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5756 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5757 sdebug_opts, sdebug_every_nth);
5758 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5759 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5760 sdebug_sector_size, "bytes");
5761 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5762 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5763 num_aborts);
5764 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5765 num_dev_resets, num_target_resets, num_bus_resets,
5766 num_host_resets);
5767 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5768 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08005769 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5770 sdebug_statistics);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005771 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
5772 atomic_read(&sdebug_cmnd_count),
5773 atomic_read(&sdebug_completions),
5774 "miss_cpus", atomic_read(&sdebug_miss_cpus),
5775 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005776
Douglas Gilbertc4837392016-05-06 00:40:26 -04005777 seq_printf(m, "submit_queues=%d\n", submit_queues);
5778 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5779 seq_printf(m, " queue %d:\n", j);
5780 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5781 if (f != sdebug_max_queue) {
5782 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5783 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
5784 "first,last bits", f, l);
5785 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005786 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005787
5788 seq_printf(m, "this host_no=%d\n", host->host_no);
5789 if (!xa_empty(per_store_ap)) {
5790 bool niu;
5791 int idx;
5792 unsigned long l_idx;
5793 struct sdeb_store_info *sip;
5794
5795 seq_puts(m, "\nhost list:\n");
5796 j = 0;
5797 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
5798 idx = sdhp->si_idx;
5799 seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j,
5800 sdhp->shost->host_no, idx);
5801 ++j;
5802 }
5803 seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
5804 sdeb_most_recent_idx);
5805 j = 0;
5806 xa_for_each(per_store_ap, l_idx, sip) {
5807 niu = xa_get_mark(per_store_ap, l_idx,
5808 SDEB_XA_NOT_IN_USE);
5809 idx = (int)l_idx;
5810 seq_printf(m, " %d: idx=%d%s\n", j, idx,
5811 (niu ? " not_in_use" : ""));
5812 ++j;
5813 }
5814 }
Al Viroc8ed5552013-03-31 01:46:06 -04005815 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816}
5817
Akinobu Mita82069372013-10-14 22:48:04 +09005818static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819{
Douglas Gilbertc2206092016-04-25 12:16:31 -04005820 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821}
Douglas Gilbertc4837392016-05-06 00:40:26 -04005822/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5823 * of delay is jiffies.
5824 */
Akinobu Mita82069372013-10-14 22:48:04 +09005825static ssize_t delay_store(struct device_driver *ddp, const char *buf,
5826 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827{
Douglas Gilbertc2206092016-04-25 12:16:31 -04005828 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005830 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005831 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04005832 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005833 int j, k;
5834 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005835
Douglas Gilbertc4837392016-05-06 00:40:26 -04005836 block_unblock_all_queues(true);
5837 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5838 ++j, ++sqp) {
5839 k = find_first_bit(sqp->in_use_bm,
5840 sdebug_max_queue);
5841 if (k != sdebug_max_queue) {
5842 res = -EBUSY; /* queued commands */
5843 break;
5844 }
5845 }
5846 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04005847 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005848 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005849 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005850 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005852 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853 }
5854 return -EINVAL;
5855}
Akinobu Mita82069372013-10-14 22:48:04 +09005856static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005858static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5859{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005860 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005861}
5862/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04005863/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005864static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04005865 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005866{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005867 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005868
5869 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04005870 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005871 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005872 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005873 int j, k;
5874 struct sdebug_queue *sqp;
5875
5876 block_unblock_all_queues(true);
5877 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5878 ++j, ++sqp) {
5879 k = find_first_bit(sqp->in_use_bm,
5880 sdebug_max_queue);
5881 if (k != sdebug_max_queue) {
5882 res = -EBUSY; /* queued commands */
5883 break;
5884 }
5885 }
5886 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005887 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04005888 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
5889 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005890 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005891 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005892 }
5893 return res;
5894 }
5895 return -EINVAL;
5896}
5897static DRIVER_ATTR_RW(ndelay);
5898
Akinobu Mita82069372013-10-14 22:48:04 +09005899static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005901 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902}
5903
Akinobu Mita82069372013-10-14 22:48:04 +09005904static ssize_t opts_store(struct device_driver *ddp, const char *buf,
5905 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005907 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 char work[20];
5909
Douglas Gilbert9a051012017-12-23 12:48:10 -05005910 if (sscanf(buf, "%10s", work) == 1) {
5911 if (strncasecmp(work, "0x", 2) == 0) {
5912 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 goto opts_done;
5914 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005915 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 goto opts_done;
5917 }
5918 }
5919 return -EINVAL;
5920opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005921 sdebug_opts = opts;
5922 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5923 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005924 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 return count;
5926}
Akinobu Mita82069372013-10-14 22:48:04 +09005927static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928
Akinobu Mita82069372013-10-14 22:48:04 +09005929static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005931 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932}
Akinobu Mita82069372013-10-14 22:48:04 +09005933static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
5934 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005936 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09005938 /* Cannot change from or to TYPE_ZBC with sysfs */
5939 if (sdebug_ptype == TYPE_ZBC)
5940 return -EINVAL;
5941
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09005943 if (n == TYPE_ZBC)
5944 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005945 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 return count;
5947 }
5948 return -EINVAL;
5949}
Akinobu Mita82069372013-10-14 22:48:04 +09005950static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951
Akinobu Mita82069372013-10-14 22:48:04 +09005952static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005954 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005955}
Akinobu Mita82069372013-10-14 22:48:04 +09005956static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
5957 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005959 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960
5961 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005962 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 return count;
5964 }
5965 return -EINVAL;
5966}
Akinobu Mita82069372013-10-14 22:48:04 +09005967static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968
Akinobu Mita82069372013-10-14 22:48:04 +09005969static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04005970{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005971 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04005972}
Akinobu Mita82069372013-10-14 22:48:04 +09005973static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
5974 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04005975{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005976 int n, idx;
Douglas Gilbert23183912006-09-16 20:30:47 -04005977
5978 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005979 bool want_store = (n == 0);
5980 struct sdebug_host_info *sdhp;
5981
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005982 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005983 sdebug_fake_rw = (sdebug_fake_rw > 0);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005984 if (sdebug_fake_rw == n)
5985 return count; /* not transitioning so do nothing */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005986
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005987 if (want_store) { /* 1 --> 0 transition, set up store */
5988 if (sdeb_first_idx < 0) {
5989 idx = sdebug_add_store();
5990 if (idx < 0)
5991 return idx;
5992 } else {
5993 idx = sdeb_first_idx;
5994 xa_clear_mark(per_store_ap, idx,
5995 SDEB_XA_NOT_IN_USE);
5996 }
5997 /* make all hosts use same store */
5998 list_for_each_entry(sdhp, &sdebug_host_list,
5999 host_list) {
6000 if (sdhp->si_idx != idx) {
6001 xa_set_mark(per_store_ap, sdhp->si_idx,
6002 SDEB_XA_NOT_IN_USE);
6003 sdhp->si_idx = idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006004 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006005 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006006 sdeb_most_recent_idx = idx;
6007 } else { /* 0 --> 1 transition is trigger for shrink */
6008 sdebug_erase_all_stores(true /* apart from first */);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006009 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006010 sdebug_fake_rw = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04006011 return count;
6012 }
6013 return -EINVAL;
6014}
Akinobu Mita82069372013-10-14 22:48:04 +09006015static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04006016
Akinobu Mita82069372013-10-14 22:48:04 +09006017static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006018{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006019 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006020}
Akinobu Mita82069372013-10-14 22:48:04 +09006021static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
6022 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006023{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006024 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006025
6026 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006027 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006028 return count;
6029 }
6030 return -EINVAL;
6031}
Akinobu Mita82069372013-10-14 22:48:04 +09006032static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006033
Akinobu Mita82069372013-10-14 22:48:04 +09006034static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006036 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037}
Akinobu Mita82069372013-10-14 22:48:04 +09006038static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
6039 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006041 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042
6043 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006044 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 sdebug_max_tgts_luns();
6046 return count;
6047 }
6048 return -EINVAL;
6049}
Akinobu Mita82069372013-10-14 22:48:04 +09006050static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051
Akinobu Mita82069372013-10-14 22:48:04 +09006052static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006054 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055}
Akinobu Mita82069372013-10-14 22:48:04 +09006056static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006058static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
6059{
6060 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
6061}
6062
6063static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
6064 size_t count)
6065{
6066 bool v;
6067
6068 if (kstrtobool(buf, &v))
6069 return -EINVAL;
6070
6071 sdebug_per_host_store = v;
6072 return count;
6073}
6074static DRIVER_ATTR_RW(per_host_store);
6075
Akinobu Mita82069372013-10-14 22:48:04 +09006076static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006078 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079}
Akinobu Mita82069372013-10-14 22:48:04 +09006080static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081
Akinobu Mita82069372013-10-14 22:48:04 +09006082static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006084 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085}
Akinobu Mita82069372013-10-14 22:48:04 +09006086static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
6087 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006089 int nth;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006090 char work[20];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006092 if (sscanf(buf, "%10s", work) == 1) {
6093 if (strncasecmp(work, "0x", 2) == 0) {
6094 if (kstrtoint(work + 2, 16, &nth) == 0)
6095 goto every_nth_done;
6096 } else {
6097 if (kstrtoint(work, 10, &nth) == 0)
6098 goto every_nth_done;
Douglas Gilbertc4837392016-05-06 00:40:26 -04006099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100 }
6101 return -EINVAL;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006102
6103every_nth_done:
6104 sdebug_every_nth = nth;
6105 if (nth && !sdebug_statistics) {
6106 pr_info("every_nth needs statistics=1, set it\n");
6107 sdebug_statistics = true;
6108 }
6109 tweak_cmnd_count();
6110 return count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111}
Akinobu Mita82069372013-10-14 22:48:04 +09006112static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006114static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6115{
6116 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6117}
6118static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6119 size_t count)
6120{
6121 int n;
6122 bool changed;
6123
6124 if (kstrtoint(buf, 0, &n))
6125 return -EINVAL;
6126 if (n >= 0) {
6127 if (n > (int)SAM_LUN_AM_FLAT) {
6128 pr_warn("only LUN address methods 0 and 1 are supported\n");
6129 return -EINVAL;
6130 }
6131 changed = ((int)sdebug_lun_am != n);
6132 sdebug_lun_am = n;
6133 if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */
6134 struct sdebug_host_info *sdhp;
6135 struct sdebug_dev_info *dp;
6136
6137 spin_lock(&sdebug_host_list_lock);
6138 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6139 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6140 set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6141 }
6142 }
6143 spin_unlock(&sdebug_host_list_lock);
6144 }
6145 return count;
6146 }
6147 return -EINVAL;
6148}
6149static DRIVER_ATTR_RW(lun_format);
6150
Akinobu Mita82069372013-10-14 22:48:04 +09006151static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006153 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154}
Akinobu Mita82069372013-10-14 22:48:04 +09006155static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
6156 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006158 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05006159 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160
6161 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006162 if (n > 256) {
6163 pr_warn("max_luns can be no more than 256\n");
6164 return -EINVAL;
6165 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006166 changed = (sdebug_max_luns != n);
6167 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04006169 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05006170 struct sdebug_host_info *sdhp;
6171 struct sdebug_dev_info *dp;
6172
6173 spin_lock(&sdebug_host_list_lock);
6174 list_for_each_entry(sdhp, &sdebug_host_list,
6175 host_list) {
6176 list_for_each_entry(dp, &sdhp->dev_info_list,
6177 dev_list) {
6178 set_bit(SDEBUG_UA_LUNS_CHANGED,
6179 dp->uas_bm);
6180 }
6181 }
6182 spin_unlock(&sdebug_host_list_lock);
6183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184 return count;
6185 }
6186 return -EINVAL;
6187}
Akinobu Mita82069372013-10-14 22:48:04 +09006188static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189
Akinobu Mita82069372013-10-14 22:48:04 +09006190static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006191{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006192 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006193}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006194/* N.B. max_queue can be changed while there are queued commands. In flight
6195 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09006196static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
6197 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006198{
Douglas Gilbertc4837392016-05-06 00:40:26 -04006199 int j, n, k, a;
6200 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006201
6202 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
John Garryc10fa552020-07-09 20:23:20 +08006203 (n <= SDEBUG_CANQUEUE) &&
6204 (sdebug_host_max_queue == 0)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04006205 block_unblock_all_queues(true);
6206 k = 0;
6207 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6208 ++j, ++sqp) {
6209 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6210 if (a > k)
6211 k = a;
6212 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006213 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04006214 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006215 atomic_set(&retired_max_queue, 0);
6216 else if (k >= n)
6217 atomic_set(&retired_max_queue, k + 1);
6218 else
6219 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04006220 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006221 return count;
6222 }
6223 return -EINVAL;
6224}
Akinobu Mita82069372013-10-14 22:48:04 +09006225static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006226
John Garryc10fa552020-07-09 20:23:20 +08006227static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6228{
6229 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6230}
6231
6232/*
6233 * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6234 * in range [0, sdebug_host_max_queue), we can't change it.
6235 */
6236static DRIVER_ATTR_RO(host_max_queue);
6237
Akinobu Mita82069372013-10-14 22:48:04 +09006238static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006239{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006240 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006241}
Akinobu Mita82069372013-10-14 22:48:04 +09006242static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006243
Akinobu Mita82069372013-10-14 22:48:04 +09006244static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006246 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247}
Akinobu Mita82069372013-10-14 22:48:04 +09006248static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249
Akinobu Mita82069372013-10-14 22:48:04 +09006250static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006251{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006252 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006253}
Akinobu Mita82069372013-10-14 22:48:04 +09006254static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
6255 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006256{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006257 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006258 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006259
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006260 /* Ignore capacity change for ZBC drives for now */
6261 if (sdeb_zbc_in_use)
6262 return -ENOTSUPP;
6263
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006264 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006265 changed = (sdebug_virtual_gb != n);
6266 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006267 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006268 if (changed) {
6269 struct sdebug_host_info *sdhp;
6270 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006271
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05006272 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006273 list_for_each_entry(sdhp, &sdebug_host_list,
6274 host_list) {
6275 list_for_each_entry(dp, &sdhp->dev_info_list,
6276 dev_list) {
6277 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
6278 dp->uas_bm);
6279 }
6280 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05006281 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006282 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006283 return count;
6284 }
6285 return -EINVAL;
6286}
Akinobu Mita82069372013-10-14 22:48:04 +09006287static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006288
Akinobu Mita82069372013-10-14 22:48:04 +09006289static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006291 /* absolute number of hosts currently active is what is shown */
6292 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293}
6294
Akinobu Mita82069372013-10-14 22:48:04 +09006295static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
6296 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006297{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006298 bool found;
6299 unsigned long idx;
6300 struct sdeb_store_info *sip;
6301 bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09006302 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09006304 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306 if (delta_hosts > 0) {
6307 do {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006308 found = false;
6309 if (want_phs) {
6310 xa_for_each_marked(per_store_ap, idx, sip,
6311 SDEB_XA_NOT_IN_USE) {
6312 sdeb_most_recent_idx = (int)idx;
6313 found = true;
6314 break;
6315 }
6316 if (found) /* re-use case */
6317 sdebug_add_host_helper((int)idx);
6318 else
6319 sdebug_do_add_host(true);
6320 } else {
6321 sdebug_do_add_host(false);
6322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323 } while (--delta_hosts);
6324 } else if (delta_hosts < 0) {
6325 do {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006326 sdebug_do_remove_host(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327 } while (++delta_hosts);
6328 }
6329 return count;
6330}
Akinobu Mita82069372013-10-14 22:48:04 +09006331static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
Akinobu Mita82069372013-10-14 22:48:04 +09006333static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04006334{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006335 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04006336}
Akinobu Mita82069372013-10-14 22:48:04 +09006337static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
6338 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04006339{
6340 int n;
6341
6342 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006343 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04006344 return count;
6345 }
6346 return -EINVAL;
6347}
Akinobu Mita82069372013-10-14 22:48:04 +09006348static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04006349
Douglas Gilbertc4837392016-05-06 00:40:26 -04006350static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6351{
6352 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6353}
6354static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6355 size_t count)
6356{
6357 int n;
6358
6359 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6360 if (n > 0)
6361 sdebug_statistics = true;
6362 else {
6363 clear_queue_stats();
6364 sdebug_statistics = false;
6365 }
6366 return count;
6367 }
6368 return -EINVAL;
6369}
6370static DRIVER_ATTR_RW(statistics);
6371
Akinobu Mita82069372013-10-14 22:48:04 +09006372static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006373{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006374 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006375}
Akinobu Mita82069372013-10-14 22:48:04 +09006376static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006377
Douglas Gilbertc4837392016-05-06 00:40:26 -04006378static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6379{
6380 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6381}
6382static DRIVER_ATTR_RO(submit_queues);
6383
Akinobu Mita82069372013-10-14 22:48:04 +09006384static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006385{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006386 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006387}
Akinobu Mita82069372013-10-14 22:48:04 +09006388static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006389
Akinobu Mita82069372013-10-14 22:48:04 +09006390static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006391{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006392 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006393}
Akinobu Mita82069372013-10-14 22:48:04 +09006394static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006395
Akinobu Mita82069372013-10-14 22:48:04 +09006396static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006397{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006398 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006399}
Akinobu Mita82069372013-10-14 22:48:04 +09006400static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006401
Akinobu Mita82069372013-10-14 22:48:04 +09006402static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006403{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006404 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006405}
Akinobu Mita82069372013-10-14 22:48:04 +09006406static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006407
Akinobu Mita82069372013-10-14 22:48:04 +09006408static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04006409{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006410 ssize_t count = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006411
Martin K. Petersen5b94e232011-03-08 02:08:11 -05006412 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04006413 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
6414 sdebug_store_sectors);
6415
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006416 if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
6417 struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
6418
6419 if (sip)
6420 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
6421 (int)map_size, sip->map_storep);
6422 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04006423 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08006424 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04006425
6426 return count;
6427}
Akinobu Mita82069372013-10-14 22:48:04 +09006428static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04006429
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04006430static ssize_t random_show(struct device_driver *ddp, char *buf)
6431{
6432 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
6433}
6434
6435static ssize_t random_store(struct device_driver *ddp, const char *buf,
6436 size_t count)
6437{
6438 bool v;
6439
6440 if (kstrtobool(buf, &v))
6441 return -EINVAL;
6442
6443 sdebug_random = v;
6444 return count;
6445}
6446static DRIVER_ATTR_RW(random);
6447
Akinobu Mita82069372013-10-14 22:48:04 +09006448static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02006449{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006450 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02006451}
Akinobu Mita82069372013-10-14 22:48:04 +09006452static ssize_t removable_store(struct device_driver *ddp, const char *buf,
6453 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02006454{
6455 int n;
6456
6457 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006458 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02006459 return count;
6460 }
6461 return -EINVAL;
6462}
Akinobu Mita82069372013-10-14 22:48:04 +09006463static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02006464
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006465static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6466{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006467 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006468}
Douglas Gilbert185dd232016-04-25 12:16:29 -04006469/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006470static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6471 size_t count)
6472{
Douglas Gilbert185dd232016-04-25 12:16:29 -04006473 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006474
6475 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04006476 sdebug_host_lock = (n > 0);
6477 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006478 }
6479 return -EINVAL;
6480}
6481static DRIVER_ATTR_RW(host_lock);
6482
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006483static ssize_t strict_show(struct device_driver *ddp, char *buf)
6484{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006485 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006486}
6487static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6488 size_t count)
6489{
6490 int n;
6491
6492 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006493 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006494 return count;
6495 }
6496 return -EINVAL;
6497}
6498static DRIVER_ATTR_RW(strict);
6499
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04006500static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
6501{
6502 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
6503}
6504static DRIVER_ATTR_RO(uuid_ctl);
6505
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05006506static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
6507{
6508 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
6509}
6510static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
6511 size_t count)
6512{
6513 int ret, n;
6514
6515 ret = kstrtoint(buf, 0, &n);
6516 if (ret)
6517 return ret;
6518 sdebug_cdb_len = n;
6519 all_config_cdb_len();
6520 return count;
6521}
6522static DRIVER_ATTR_RW(cdb_len);
6523
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006524static const char * const zbc_model_strs_a[] = {
6525 [BLK_ZONED_NONE] = "none",
6526 [BLK_ZONED_HA] = "host-aware",
6527 [BLK_ZONED_HM] = "host-managed",
6528};
6529
6530static const char * const zbc_model_strs_b[] = {
6531 [BLK_ZONED_NONE] = "no",
6532 [BLK_ZONED_HA] = "aware",
6533 [BLK_ZONED_HM] = "managed",
6534};
6535
6536static const char * const zbc_model_strs_c[] = {
6537 [BLK_ZONED_NONE] = "0",
6538 [BLK_ZONED_HA] = "1",
6539 [BLK_ZONED_HM] = "2",
6540};
6541
6542static int sdeb_zbc_model_str(const char *cp)
6543{
6544 int res = sysfs_match_string(zbc_model_strs_a, cp);
6545
6546 if (res < 0) {
6547 res = sysfs_match_string(zbc_model_strs_b, cp);
6548 if (res < 0) {
6549 res = sysfs_match_string(zbc_model_strs_c, cp);
Dan Carpenter47742bd2020-05-09 13:04:08 +03006550 if (res < 0)
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006551 return -EINVAL;
6552 }
6553 }
6554 return res;
6555}
6556
6557static ssize_t zbc_show(struct device_driver *ddp, char *buf)
6558{
6559 return scnprintf(buf, PAGE_SIZE, "%s\n",
6560 zbc_model_strs_a[sdeb_zbc_model]);
6561}
6562static DRIVER_ATTR_RO(zbc);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006563
Douglas Gilbertfc136382020-07-24 11:55:31 -04006564static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6565{
6566 return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6567}
6568static DRIVER_ATTR_RO(tur_ms_to_ready);
6569
Akinobu Mita82069372013-10-14 22:48:04 +09006570/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04006571 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
6572 files (over those found in the /sys/module/scsi_debug/parameters
6573 directory) is that auxiliary actions can be triggered when an attribute
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006574 is changed. For example see: add_host_store() above.
Douglas Gilbert23183912006-09-16 20:30:47 -04006575 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006576
Akinobu Mita82069372013-10-14 22:48:04 +09006577static struct attribute *sdebug_drv_attrs[] = {
6578 &driver_attr_delay.attr,
6579 &driver_attr_opts.attr,
6580 &driver_attr_ptype.attr,
6581 &driver_attr_dsense.attr,
6582 &driver_attr_fake_rw.attr,
John Garryc10fa552020-07-09 20:23:20 +08006583 &driver_attr_host_max_queue.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006584 &driver_attr_no_lun_0.attr,
6585 &driver_attr_num_tgts.attr,
6586 &driver_attr_dev_size_mb.attr,
6587 &driver_attr_num_parts.attr,
6588 &driver_attr_every_nth.attr,
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006589 &driver_attr_lun_format.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006590 &driver_attr_max_luns.attr,
6591 &driver_attr_max_queue.attr,
6592 &driver_attr_no_uld.attr,
6593 &driver_attr_scsi_level.attr,
6594 &driver_attr_virtual_gb.attr,
6595 &driver_attr_add_host.attr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006596 &driver_attr_per_host_store.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006597 &driver_attr_vpd_use_hostno.attr,
6598 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04006599 &driver_attr_statistics.attr,
6600 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006601 &driver_attr_dix.attr,
6602 &driver_attr_dif.attr,
6603 &driver_attr_guard.attr,
6604 &driver_attr_ato.attr,
6605 &driver_attr_map.attr,
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04006606 &driver_attr_random.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006607 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006608 &driver_attr_host_lock.attr,
6609 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006610 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04006611 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05006612 &driver_attr_cdb_len.attr,
Douglas Gilbertfc136382020-07-24 11:55:31 -04006613 &driver_attr_tur_ms_to_ready.attr,
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006614 &driver_attr_zbc.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006615 NULL,
6616};
6617ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618
Akinobu Mita11ddcec2014-02-26 22:56:59 +09006619static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09006620
Linus Torvalds1da177e2005-04-16 15:20:36 -07006621static int __init scsi_debug_init(void)
6622{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006623 bool want_store = (sdebug_fake_rw == 0);
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09006624 unsigned long sz;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006625 int k, ret, hosts_to_add;
6626 int idx = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006627
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006628 ramdisk_lck_a[0] = &atomic_rw;
6629 ramdisk_lck_a[1] = &atomic_rw2;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006630 atomic_set(&retired_max_queue, 0);
6631
Douglas Gilbert773642d2016-04-25 12:16:28 -04006632 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006633 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04006634 sdebug_ndelay = 0;
6635 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04006636 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006637
Douglas Gilbert773642d2016-04-25 12:16:28 -04006638 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006639 case 512:
6640 case 1024:
6641 case 2048:
6642 case 4096:
6643 break;
6644 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04006645 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006646 return -EINVAL;
6647 }
6648
Douglas Gilbert773642d2016-04-25 12:16:28 -04006649 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02006650 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04006651 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02006652 case T10_PI_TYPE1_PROTECTION:
6653 case T10_PI_TYPE2_PROTECTION:
6654 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04006655 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006656 break;
6657
6658 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03006659 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006660 return -EINVAL;
6661 }
6662
Maurizio Lombardiaa5334c2019-11-15 17:37:27 +01006663 if (sdebug_num_tgts < 0) {
6664 pr_err("num_tgts must be >= 0\n");
6665 return -EINVAL;
6666 }
6667
Douglas Gilbert773642d2016-04-25 12:16:28 -04006668 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006669 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006670 return -EINVAL;
6671 }
6672
Douglas Gilbert773642d2016-04-25 12:16:28 -04006673 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006674 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006675 return -EINVAL;
6676 }
6677
Douglas Gilbert773642d2016-04-25 12:16:28 -04006678 if (sdebug_physblk_exp > 15) {
6679 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006680 return -EINVAL;
6681 }
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006682
6683 sdebug_lun_am = sdebug_lun_am_i;
6684 if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6685 pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6686 sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6687 }
6688
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006689 if (sdebug_max_luns > 256) {
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006690 if (sdebug_max_luns > 16384) {
6691 pr_warn("max_luns can be no more than 16384, use default\n");
6692 sdebug_max_luns = DEF_MAX_LUNS;
6693 }
6694 sdebug_lun_am = SAM_LUN_AM_FLAT;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006695 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006696
Douglas Gilbert773642d2016-04-25 12:16:28 -04006697 if (sdebug_lowest_aligned > 0x3fff) {
6698 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006699 return -EINVAL;
6700 }
6701
Douglas Gilbertc4837392016-05-06 00:40:26 -04006702 if (submit_queues < 1) {
6703 pr_err("submit_queues must be 1 or more\n");
6704 return -EINVAL;
6705 }
John Garryc87bf242020-07-09 20:23:19 +08006706
6707 if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6708 pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6709 return -EINVAL;
6710 }
6711
John Garryc10fa552020-07-09 20:23:20 +08006712 if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6713 (sdebug_host_max_queue < 0)) {
6714 pr_err("host_max_queue must be in range [0 %d]\n",
6715 SDEBUG_CANQUEUE);
6716 return -EINVAL;
6717 }
6718
6719 if (sdebug_host_max_queue &&
6720 (sdebug_max_queue != sdebug_host_max_queue)) {
6721 sdebug_max_queue = sdebug_host_max_queue;
6722 pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6723 sdebug_max_queue);
6724 }
6725
Douglas Gilbertc4837392016-05-06 00:40:26 -04006726 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6727 GFP_KERNEL);
6728 if (sdebug_q_arr == NULL)
6729 return -ENOMEM;
6730 for (k = 0; k < submit_queues; ++k)
6731 spin_lock_init(&sdebug_q_arr[k].qc_lock);
6732
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006733 /*
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006734 * check for host managed zoned block device specified with
6735 * ptype=0x14 or zbc=XXX.
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006736 */
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006737 if (sdebug_ptype == TYPE_ZBC) {
6738 sdeb_zbc_model = BLK_ZONED_HM;
6739 } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
6740 k = sdeb_zbc_model_str(sdeb_zbc_model_s);
6741 if (k < 0) {
6742 ret = k;
6743 goto free_vm;
6744 }
6745 sdeb_zbc_model = k;
6746 switch (sdeb_zbc_model) {
6747 case BLK_ZONED_NONE:
Damien Le Moal64e14ec2020-04-22 19:42:21 +09006748 case BLK_ZONED_HA:
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006749 sdebug_ptype = TYPE_DISK;
6750 break;
6751 case BLK_ZONED_HM:
6752 sdebug_ptype = TYPE_ZBC;
6753 break;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006754 default:
6755 pr_err("Invalid ZBC model\n");
6756 return -EINVAL;
6757 }
6758 }
6759 if (sdeb_zbc_model != BLK_ZONED_NONE) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006760 sdeb_zbc_in_use = true;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006761 if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
6762 sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
6763 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006764
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006765 if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
6766 sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006767 if (sdebug_dev_size_mb < 1)
6768 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
6769 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6770 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006771 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772
6773 /* play around with geometry, don't waste too much on track 0 */
6774 sdebug_heads = 8;
6775 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006776 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006778 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02006779 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006780 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
6781 (sdebug_sectors_per * sdebug_heads);
6782 if (sdebug_cylinders_per >= 1024) {
6783 /* other LLDs do this; implies >= 1GB ram disk ... */
6784 sdebug_heads = 255;
6785 sdebug_sectors_per = 63;
6786 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
6787 (sdebug_sectors_per * sdebug_heads);
6788 }
Martin K. Petersen5b94e232011-03-08 02:08:11 -05006789 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006790 sdebug_unmap_max_blocks =
6791 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04006792
Douglas Gilbert773642d2016-04-25 12:16:28 -04006793 sdebug_unmap_max_desc =
6794 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04006795
Douglas Gilbert773642d2016-04-25 12:16:28 -04006796 sdebug_unmap_granularity =
6797 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04006798
Douglas Gilbert773642d2016-04-25 12:16:28 -04006799 if (sdebug_unmap_alignment &&
6800 sdebug_unmap_granularity <=
6801 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006802 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04006803 ret = -EINVAL;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006804 goto free_q_arr;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006805 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006806 }
6807 xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
6808 if (want_store) {
6809 idx = sdebug_add_store();
6810 if (idx < 0) {
6811 ret = idx;
6812 goto free_q_arr;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006813 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04006814 }
6815
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006816 pseudo_primary = root_device_register("pseudo_0");
6817 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006818 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006819 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006820 goto free_vm;
6821 }
6822 ret = bus_register(&pseudo_lld_bus);
6823 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006824 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006825 goto dev_unreg;
6826 }
6827 ret = driver_register(&sdebug_driverfs_driver);
6828 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006829 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006830 goto bus_unreg;
6831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006833 hosts_to_add = sdebug_add_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006834 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006835
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006836 for (k = 0; k < hosts_to_add; k++) {
6837 if (want_store && k == 0) {
6838 ret = sdebug_add_host_helper(idx);
6839 if (ret < 0) {
6840 pr_err("add_host_helper k=%d, error=%d\n",
6841 k, -ret);
6842 break;
6843 }
6844 } else {
6845 ret = sdebug_do_add_host(want_store &&
6846 sdebug_per_host_store);
6847 if (ret < 0) {
6848 pr_err("add_host k=%d error=%d\n", k, -ret);
6849 break;
6850 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05006851 }
6852 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006853 if (sdebug_verbose)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006854 pr_info("built %d host(s)\n", sdebug_num_hosts);
Tomas Winklerc12879702015-07-28 16:54:20 +03006855
Linus Torvalds1da177e2005-04-16 15:20:36 -07006856 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006857
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006858bus_unreg:
6859 bus_unregister(&pseudo_lld_bus);
6860dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006861 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006862free_vm:
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006863 sdebug_erase_store(idx, NULL);
Douglas Gilbertc4837392016-05-06 00:40:26 -04006864free_q_arr:
6865 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006866 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006867}
6868
6869static void __exit scsi_debug_exit(void)
6870{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006871 int k = sdebug_num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006872
6873 stop_all_queued();
6874 for (; k; k--)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006875 sdebug_do_remove_host(true);
Luis Henriques52ab9762018-06-18 17:08:03 +01006876 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006877 driver_unregister(&sdebug_driverfs_driver);
6878 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006879 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006880
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006881 sdebug_erase_all_stores(false);
6882 xa_destroy(per_store_ap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006883}
6884
6885device_initcall(scsi_debug_init);
6886module_exit(scsi_debug_exit);
6887
John Pittman91d4c752018-02-09 21:12:43 -05006888static void sdebug_release_adapter(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006889{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006890 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006891
6892 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05006893 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006894}
6895
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006896/* idx must be valid, if sip is NULL then it will be obtained using idx */
6897static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006898{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006899 if (idx < 0)
6900 return;
6901 if (!sip) {
6902 if (xa_empty(per_store_ap))
6903 return;
6904 sip = xa_load(per_store_ap, idx);
6905 if (!sip)
6906 return;
6907 }
6908 vfree(sip->map_storep);
6909 vfree(sip->dif_storep);
6910 vfree(sip->storep);
6911 xa_erase(per_store_ap, idx);
6912 kfree(sip);
6913}
6914
6915/* Assume apart_from_first==false only in shutdown case. */
6916static void sdebug_erase_all_stores(bool apart_from_first)
6917{
6918 unsigned long idx;
6919 struct sdeb_store_info *sip = NULL;
6920
6921 xa_for_each(per_store_ap, idx, sip) {
6922 if (apart_from_first)
6923 apart_from_first = false;
6924 else
6925 sdebug_erase_store(idx, sip);
6926 }
6927 if (apart_from_first)
6928 sdeb_most_recent_idx = sdeb_first_idx;
6929}
6930
6931/*
6932 * Returns store xarray new element index (idx) if >=0 else negated errno.
6933 * Limit the number of stores to 65536.
6934 */
6935static int sdebug_add_store(void)
6936{
6937 int res;
6938 u32 n_idx;
6939 unsigned long iflags;
6940 unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6941 struct sdeb_store_info *sip = NULL;
6942 struct xa_limit xal = { .max = 1 << 16, .min = 0 };
6943
6944 sip = kzalloc(sizeof(*sip), GFP_KERNEL);
6945 if (!sip)
6946 return -ENOMEM;
6947
6948 xa_lock_irqsave(per_store_ap, iflags);
6949 res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
6950 if (unlikely(res < 0)) {
6951 xa_unlock_irqrestore(per_store_ap, iflags);
6952 kfree(sip);
6953 pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
6954 return res;
6955 }
6956 sdeb_most_recent_idx = n_idx;
6957 if (sdeb_first_idx < 0)
6958 sdeb_first_idx = n_idx;
6959 xa_unlock_irqrestore(per_store_ap, iflags);
6960
6961 res = -ENOMEM;
6962 sip->storep = vzalloc(sz);
6963 if (!sip->storep) {
6964 pr_err("user data oom\n");
6965 goto err;
6966 }
6967 if (sdebug_num_parts > 0)
6968 sdebug_build_parts(sip->storep, sz);
6969
6970 /* DIF/DIX: what T10 calls Protection Information (PI) */
6971 if (sdebug_dix) {
6972 int dif_size;
6973
6974 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
6975 sip->dif_storep = vmalloc(dif_size);
6976
6977 pr_info("dif_storep %u bytes @ %pK\n", dif_size,
6978 sip->dif_storep);
6979
6980 if (!sip->dif_storep) {
6981 pr_err("DIX oom\n");
6982 goto err;
6983 }
6984 memset(sip->dif_storep, 0xff, dif_size);
6985 }
6986 /* Logical Block Provisioning */
6987 if (scsi_debug_lbp()) {
6988 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
6989 sip->map_storep = vmalloc(array_size(sizeof(long),
6990 BITS_TO_LONGS(map_size)));
6991
6992 pr_info("%lu provisioning blocks\n", map_size);
6993
6994 if (!sip->map_storep) {
6995 pr_err("LBP map oom\n");
6996 goto err;
6997 }
6998
6999 bitmap_zero(sip->map_storep, map_size);
7000
7001 /* Map first 1KB for partition table */
7002 if (sdebug_num_parts)
7003 map_region(sip, 0, 2);
7004 }
7005
7006 rwlock_init(&sip->macc_lck);
7007 return (int)n_idx;
7008err:
7009 sdebug_erase_store((int)n_idx, sip);
7010 pr_warn("%s: failed, errno=%d\n", __func__, -res);
7011 return res;
7012}
7013
7014static int sdebug_add_host_helper(int per_host_idx)
7015{
7016 int k, devs_per_host, idx;
7017 int error = -ENOMEM;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007018 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007019 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020
Douglas Gilbert9a051012017-12-23 12:48:10 -05007021 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007022 if (!sdbg_host)
Douglas Gilbert9a051012017-12-23 12:48:10 -05007023 return -ENOMEM;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007024 idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
7025 if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
7026 xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
7027 sdbg_host->si_idx = idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007028
Douglas Gilbert9a051012017-12-23 12:48:10 -05007029 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007030
Douglas Gilbert773642d2016-04-25 12:16:28 -04007031 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007032 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09007033 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007034 if (!sdbg_devinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007035 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007037
Douglas Gilbert9a051012017-12-23 12:48:10 -05007038 spin_lock(&sdebug_host_list_lock);
7039 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
7040 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007041
Douglas Gilbert9a051012017-12-23 12:48:10 -05007042 sdbg_host->dev.bus = &pseudo_lld_bus;
7043 sdbg_host->dev.parent = pseudo_primary;
7044 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007045 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046
Douglas Gilbert9a051012017-12-23 12:48:10 -05007047 error = device_register(&sdbg_host->dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007048 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007049 goto clean;
7050
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007051 ++sdebug_num_hosts;
7052 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007053
7054clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007055 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
7056 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007057 list_del(&sdbg_devinfo->dev_list);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09007058 kfree(sdbg_devinfo->zstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007059 kfree(sdbg_devinfo);
7060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007061 kfree(sdbg_host);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007062 pr_warn("%s: failed, errno=%d\n", __func__, -error);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007063 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007064}
7065
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007066static int sdebug_do_add_host(bool mk_new_store)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007067{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007068 int ph_idx = sdeb_most_recent_idx;
7069
7070 if (mk_new_store) {
7071 ph_idx = sdebug_add_store();
7072 if (ph_idx < 0)
7073 return ph_idx;
7074 }
7075 return sdebug_add_host_helper(ph_idx);
7076}
7077
7078static void sdebug_do_remove_host(bool the_end)
7079{
7080 int idx = -1;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007081 struct sdebug_host_info *sdbg_host = NULL;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007082 struct sdebug_host_info *sdbg_host2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007083
Douglas Gilbert9a051012017-12-23 12:48:10 -05007084 spin_lock(&sdebug_host_list_lock);
7085 if (!list_empty(&sdebug_host_list)) {
7086 sdbg_host = list_entry(sdebug_host_list.prev,
7087 struct sdebug_host_info, host_list);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007088 idx = sdbg_host->si_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007089 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007090 if (!the_end && idx >= 0) {
7091 bool unique = true;
7092
7093 list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
7094 if (sdbg_host2 == sdbg_host)
7095 continue;
7096 if (idx == sdbg_host2->si_idx) {
7097 unique = false;
7098 break;
7099 }
7100 }
7101 if (unique) {
7102 xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
7103 if (idx == sdeb_most_recent_idx)
7104 --sdeb_most_recent_idx;
7105 }
7106 }
7107 if (sdbg_host)
7108 list_del(&sdbg_host->host_list);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007109 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007110
7111 if (!sdbg_host)
7112 return;
7113
Douglas Gilbert773642d2016-04-25 12:16:28 -04007114 device_unregister(&sdbg_host->dev);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007115 --sdebug_num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116}
7117
Douglas Gilbertfd321192016-04-25 12:16:33 -04007118static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007119{
7120 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007121 struct sdebug_dev_info *devip;
7122
Douglas Gilbertc4837392016-05-06 00:40:26 -04007123 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007124 devip = (struct sdebug_dev_info *)sdev->hostdata;
7125 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007126 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007127 return -ENODEV;
7128 }
7129 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007130
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007131 if (qdepth < 1)
7132 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04007133 /* allow to exceed max host qc_arr elements for testing */
7134 if (qdepth > SDEBUG_CANQUEUE + 10)
7135 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01007136 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007137
Douglas Gilbert773642d2016-04-25 12:16:28 -04007138 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007139 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007140 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007141 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007142 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007143 return sdev->queue_depth;
7144}
7145
Douglas Gilbertc4837392016-05-06 00:40:26 -04007146static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05007147{
Douglas Gilbertc4837392016-05-06 00:40:26 -04007148 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04007149 if (sdebug_every_nth < -1)
7150 sdebug_every_nth = -1;
7151 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04007152 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04007153 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05007154 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04007155 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05007156 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007157 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05007158}
7159
Douglas Gilbertfc136382020-07-24 11:55:31 -04007160/* Response to TUR or media access command when device stopped */
7161static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7162{
7163 int stopped_state;
7164 u64 diff_ns = 0;
7165 ktime_t now_ts = ktime_get_boottime();
7166 struct scsi_device *sdp = scp->device;
7167
7168 stopped_state = atomic_read(&devip->stopped);
7169 if (stopped_state == 2) {
7170 if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7171 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7172 if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7173 /* tur_ms_to_ready timer extinguished */
7174 atomic_set(&devip->stopped, 0);
7175 return 0;
7176 }
7177 }
7178 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7179 if (sdebug_verbose)
7180 sdev_printk(KERN_INFO, sdp,
7181 "%s: Not ready: in process of becoming ready\n", my_name);
7182 if (scp->cmnd[0] == TEST_UNIT_READY) {
7183 u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7184
7185 if (diff_ns <= tur_nanosecs_to_ready)
7186 diff_ns = tur_nanosecs_to_ready - diff_ns;
7187 else
7188 diff_ns = tur_nanosecs_to_ready;
7189 /* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7190 do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */
7191 scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7192 diff_ns);
7193 return check_condition_result;
7194 }
7195 }
7196 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7197 if (sdebug_verbose)
7198 sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7199 my_name);
7200 return check_condition_result;
7201}
7202
Douglas Gilbertfd321192016-04-25 12:16:33 -04007203static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7204 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007205{
7206 u8 sdeb_i;
7207 struct scsi_device *sdp = scp->device;
7208 const struct opcode_info_t *oip;
7209 const struct opcode_info_t *r_oip;
7210 struct sdebug_dev_info *devip;
7211 u8 *cmd = scp->cmnd;
7212 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
Martin Wilckf66b8512018-02-14 11:05:57 +01007213 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007214 int k, na;
7215 int errsts = 0;
Douglas Gilbertad0c7772020-08-21 00:22:49 -04007216 u64 lun_index = sdp->lun & 0x3FFF;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007217 u32 flags;
7218 u16 sa;
7219 u8 opcode = cmd[0];
7220 bool has_wlun_rl;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007221 bool inject_now;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007222
7223 scsi_set_resid(scp, 0);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007224 if (sdebug_statistics) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007225 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007226 inject_now = inject_on_this_cmd();
7227 } else {
7228 inject_now = false;
7229 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007230 if (unlikely(sdebug_verbose &&
7231 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007232 char b[120];
7233 int n, len, sb;
7234
7235 len = scp->cmd_len;
7236 sb = (int)sizeof(b);
7237 if (len > 32)
7238 strcpy(b, "too long, over 32 bytes");
7239 else {
7240 for (k = 0, n = 0; k < len && n < sb; ++k)
7241 n += scnprintf(b + n, sb - n, "%02x ",
7242 (u32)cmd[k]);
7243 }
Bart Van Assche458df782018-01-26 08:52:19 -08007244 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7245 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007246 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007247 if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08007248 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03007249 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04007250 if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007251 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007252
7253 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
7254 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
7255 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007256 if (unlikely(!devip)) {
7257 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007258 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007259 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007260 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007261 if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
7262 atomic_set(&sdeb_inject_pending, 1);
7263
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007264 na = oip->num_attached;
7265 r_pfp = oip->pfp;
7266 if (na) { /* multiple commands with this opcode */
7267 r_oip = oip;
7268 if (FF_SA & r_oip->flags) {
7269 if (F_SA_LOW & oip->flags)
7270 sa = 0x1f & cmd[1];
7271 else
7272 sa = get_unaligned_be16(cmd + 8);
7273 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7274 if (opcode == oip->opcode && sa == oip->sa)
7275 break;
7276 }
7277 } else { /* since no service action only check opcode */
7278 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7279 if (opcode == oip->opcode)
7280 break;
7281 }
7282 }
7283 if (k > na) {
7284 if (F_SA_LOW & r_oip->flags)
7285 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7286 else if (F_SA_HIGH & r_oip->flags)
7287 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7288 else
7289 mk_sense_invalid_opcode(scp);
7290 goto check_cond;
7291 }
7292 } /* else (when na==0) we assume the oip is a match */
7293 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007294 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007295 mk_sense_invalid_opcode(scp);
7296 goto check_cond;
7297 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007298 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04007299 if (sdebug_verbose)
7300 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7301 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007302 mk_sense_invalid_opcode(scp);
7303 goto check_cond;
7304 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007305 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007306 u8 rem;
7307 int j;
7308
7309 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7310 rem = ~oip->len_mask[k] & cmd[k];
7311 if (rem) {
7312 for (j = 7; j >= 0; --j, rem <<= 1) {
7313 if (0x80 & rem)
7314 break;
7315 }
7316 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7317 goto check_cond;
7318 }
7319 }
7320 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007321 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04007322 find_first_bit(devip->uas_bm,
7323 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007324 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007325 if (errsts)
7326 goto check_cond;
7327 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04007328 if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7329 atomic_read(&devip->stopped))) {
7330 errsts = resp_not_ready(scp, devip);
7331 if (errsts)
7332 goto fini;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007333 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04007334 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007335 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007336 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007337 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007338 return 0; /* ignore command: make trouble */
7339 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007340 if (likely(oip->pfp))
Martin Wilckf66b8512018-02-14 11:05:57 +01007341 pfp = oip->pfp; /* calls a resp_* function */
7342 else
7343 pfp = r_pfp; /* if leaf function ptr NULL, try the root's */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007344
7345fini:
Douglas Gilbert67da4132020-04-21 11:14:20 -04007346 if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */
Martin Wilckf66b8512018-02-14 11:05:57 +01007347 return schedule_resp(scp, devip, errsts, pfp, 0, 0);
Douglas Gilbert75aa3202018-07-12 13:35:42 -04007348 else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
7349 sdebug_ndelay > 10000)) {
Douglas Gilbert80c49562018-02-09 21:36:39 -05007350 /*
Douglas Gilbert75aa3202018-07-12 13:35:42 -04007351 * Skip long delays if ndelay <= 10 microseconds. Otherwise
7352 * for Start Stop Unit (SSU) want at least 1 second delay and
7353 * if sdebug_jdelay>1 want a long delay of that many seconds.
7354 * For Synchronize Cache want 1/20 of SSU's delay.
Douglas Gilbert80c49562018-02-09 21:36:39 -05007355 */
7356 int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04007357 int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
Douglas Gilbert80c49562018-02-09 21:36:39 -05007358
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04007359 jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
Martin Wilckf66b8512018-02-14 11:05:57 +01007360 return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05007361 } else
Martin Wilckf66b8512018-02-14 11:05:57 +01007362 return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
Douglas Gilbert10bde982018-01-10 16:57:31 -05007363 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007364check_cond:
Martin Wilckf66b8512018-02-14 11:05:57 +01007365 return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007366err_out:
Martin Wilckf66b8512018-02-14 11:05:57 +01007367 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007368}
7369
FUJITA Tomonori9e603ca02008-03-02 18:30:16 +09007370static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04007371 .show_info = scsi_debug_show_info,
7372 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca02008-03-02 18:30:16 +09007373 .proc_name = sdebug_proc_name,
7374 .name = "SCSI DEBUG",
7375 .info = scsi_debug_info,
7376 .slave_alloc = scsi_debug_slave_alloc,
7377 .slave_configure = scsi_debug_slave_configure,
7378 .slave_destroy = scsi_debug_slave_destroy,
7379 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04007380 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007381 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca02008-03-02 18:30:16 +09007382 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca02008-03-02 18:30:16 +09007383 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007384 .eh_target_reset_handler = scsi_debug_target_reset,
7385 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca02008-03-02 18:30:16 +09007386 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04007387 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca02008-03-02 18:30:16 +09007388 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07007389 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007390 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09007391 .max_sectors = -1U,
Christoph Hellwig50c2e912018-12-13 16:17:03 +01007392 .max_segment_size = -1U,
FUJITA Tomonori9e603ca02008-03-02 18:30:16 +09007393 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007394 .track_queue_depth = 1,
FUJITA Tomonori9e603ca02008-03-02 18:30:16 +09007395};
7396
John Pittman91d4c752018-02-09 21:12:43 -05007397static int sdebug_driver_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007398{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05007399 int error = 0;
7400 struct sdebug_host_info *sdbg_host;
7401 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007402 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007403
7404 sdbg_host = to_sdebug_host(dev);
7405
John Garryf7c4cdc2020-08-19 23:20:33 +08007406 sdebug_driver_template.can_queue = sdebug_max_queue;
Christoph Hellwig2a3d4eb2018-12-13 16:17:02 +01007407 if (!sdebug_clustering)
Christoph Hellwig4af14d12018-12-13 16:17:09 +01007408 sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
7409
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007410 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
7411 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007412 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007413 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007415 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007416 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07007417 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04007418 my_name, submit_queues, nr_cpu_ids);
7419 submit_queues = nr_cpu_ids;
7420 }
John Garryc10fa552020-07-09 20:23:20 +08007421 /*
7422 * Decide whether to tell scsi subsystem that we want mq. The
John Garryf7c4cdc2020-08-19 23:20:33 +08007423 * following should give the same answer for each host.
John Garryc10fa552020-07-09 20:23:20 +08007424 */
John Garryf7c4cdc2020-08-19 23:20:33 +08007425 hpnt->nr_hw_queues = submit_queues;
7426 if (sdebug_host_max_queue)
7427 hpnt->host_tagset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428
Douglas Gilbert9a051012017-12-23 12:48:10 -05007429 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007430 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007431 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7432 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007433 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04007434 hpnt->max_id = sdebug_num_tgts;
7435 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03007436 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007437
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007438 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007439
Douglas Gilbert773642d2016-04-25 12:16:28 -04007440 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007441
Christoph Hellwig8475c812016-09-11 19:35:41 +02007442 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007443 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007444 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007445 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007446 break;
7447
Christoph Hellwig8475c812016-09-11 19:35:41 +02007448 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007449 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007450 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007451 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007452 break;
7453
Christoph Hellwig8475c812016-09-11 19:35:41 +02007454 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007455 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007456 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007457 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007458 break;
7459
7460 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04007461 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007462 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007463 break;
7464 }
7465
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007466 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007467
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007468 if (have_dif_prot || sdebug_dix)
7469 pr_info("host protection%s%s%s%s%s%s%s\n",
7470 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7471 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7472 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7473 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7474 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7475 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7476 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007477
Douglas Gilbert773642d2016-04-25 12:16:28 -04007478 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007479 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7480 else
7481 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7482
Douglas Gilbert773642d2016-04-25 12:16:28 -04007483 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7484 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04007485 if (sdebug_every_nth) /* need stats counters for every_nth */
7486 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007487 error = scsi_add_host(hpnt, &sdbg_host->dev);
7488 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007489 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05007490 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007491 scsi_host_put(hpnt);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007492 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007493 scsi_scan_host(hpnt);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007495
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007496 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007497}
7498
John Pittman91d4c752018-02-09 21:12:43 -05007499static int sdebug_driver_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007500{
Douglas Gilbert9a051012017-12-23 12:48:10 -05007501 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007502 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007503
7504 sdbg_host = to_sdebug_host(dev);
7505
7506 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007507 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007508 return -ENODEV;
7509 }
7510
Douglas Gilbert9a051012017-12-23 12:48:10 -05007511 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007512
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007513 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
7514 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05007515 list_del(&sdbg_devinfo->dev_list);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09007516 kfree(sdbg_devinfo->zstate);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007517 kfree(sdbg_devinfo);
7518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007519
Douglas Gilbert9a051012017-12-23 12:48:10 -05007520 scsi_host_put(sdbg_host->shost);
7521 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007522}
7523
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007524static int pseudo_lld_bus_match(struct device *dev,
7525 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007526{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007527 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007528}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007529
7530static struct bus_type pseudo_lld_bus = {
7531 .name = "pseudo",
7532 .match = pseudo_lld_bus_match,
7533 .probe = sdebug_driver_probe,
7534 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09007535 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007536};