blob: a5d1633b5bd80acf6e536e4c128cc331fe4002c0 [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 Gilbertfc09acb2021-04-14 21:50:31 -0400221#define DEF_CMD_PER_LUN SDEBUG_CANQUEUE
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400222
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,
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +0530325 SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3};
Douglas Gilbert10bde982018-01-10 16:57:31 -0500326
Douglas Gilbertfd321192016-04-25 12:16:33 -0400327struct sdebug_defer {
328 struct hrtimer hrt;
329 struct execute_work ew;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +0530330 ktime_t cmpl_ts;/* time since boot to complete this cmd */
Douglas Gilbertc4837392016-05-06 00:40:26 -0400331 int sqa_idx; /* index of sdebug_queue array */
332 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
John Garryc10fa552020-07-09 20:23:20 +0800333 int hc_idx; /* hostwide tag index */
Douglas Gilbertc4837392016-05-06 00:40:26 -0400334 int issuing_cpu;
Douglas Gilbert10bde982018-01-10 16:57:31 -0500335 bool init_hrt;
336 bool init_wq;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +0530337 bool init_poll;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400338 bool aborted; /* true when blk_abort_request() already called */
Douglas Gilbert10bde982018-01-10 16:57:31 -0500339 enum sdeb_defer_type defer_t;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400340};
341
342struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400343 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
344 * instance indicates this slot is in use.
345 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400346 struct sdebug_defer *sd_dp;
347 struct scsi_cmnd *a_cmnd;
348};
349
Douglas Gilbertc4837392016-05-06 00:40:26 -0400350struct sdebug_queue {
351 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
352 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
353 spinlock_t qc_lock;
354 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400355};
356
Douglas Gilbertc4837392016-05-06 00:40:26 -0400357static atomic_t sdebug_cmnd_count; /* number of incoming commands */
358static atomic_t sdebug_completions; /* count of deferred completions */
359static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
360static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
Douglas Gilbert3a90a632020-07-12 14:29:26 -0400361static atomic_t sdeb_inject_pending;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +0530362static atomic_t sdeb_mq_poll_count; /* bumped when mq_poll returns > 0 */
Douglas Gilbertc4837392016-05-06 00:40:26 -0400363
Douglas Gilbertfd321192016-04-25 12:16:33 -0400364struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400365 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
366 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400367 u8 opcode; /* if num_attached > 0, preferred */
368 u16 sa; /* service action */
369 u32 flags; /* OR-ed set of SDEB_F_* */
370 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
371 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500372 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
373 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400374};
375
376/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500377enum sdeb_opcode_index {
378 SDEB_I_INVALID_OPCODE = 0,
379 SDEB_I_INQUIRY = 1,
380 SDEB_I_REPORT_LUNS = 2,
381 SDEB_I_REQUEST_SENSE = 3,
382 SDEB_I_TEST_UNIT_READY = 4,
383 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
384 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
385 SDEB_I_LOG_SENSE = 7,
386 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
387 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
388 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
389 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500390 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
391 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500392 SDEB_I_MAINT_IN = 14,
393 SDEB_I_MAINT_OUT = 15,
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400394 SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500395 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500396 SDEB_I_RESERVE = 18, /* 6, 10 */
397 SDEB_I_RELEASE = 19, /* 6, 10 */
398 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
399 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
400 SDEB_I_ATA_PT = 22, /* 12, 16 */
401 SDEB_I_SEND_DIAG = 23,
402 SDEB_I_UNMAP = 24,
Bart Van Asschec2085562019-02-08 13:21:27 -0800403 SDEB_I_WRITE_BUFFER = 25,
404 SDEB_I_WRITE_SAME = 26, /* 10, 16 */
405 SDEB_I_SYNC_CACHE = 27, /* 10, 16 */
406 SDEB_I_COMP_WRITE = 28,
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400407 SDEB_I_PRE_FETCH = 29, /* 10, 16 */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900408 SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */
409 SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */
410 SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500411};
412
Douglas Gilbertc4837392016-05-06 00:40:26 -0400413
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500414static const unsigned char opcode_ind_arr[256] = {
415/* 0x0; 0x0->0x1f: 6 byte cdbs */
416 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
417 0, 0, 0, 0,
418 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
419 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
420 SDEB_I_RELEASE,
421 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
422 SDEB_I_ALLOW_REMOVAL, 0,
423/* 0x20; 0x20->0x3f: 10 byte cdbs */
424 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
425 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400426 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500427 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
428/* 0x40; 0x40->0x5f: 10 byte cdbs */
429 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
430 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
Bart Van Asschec2085562019-02-08 13:21:27 -0800431 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500432 SDEB_I_RELEASE,
433 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400434/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
437 0, SDEB_I_VARIABLE_LEN,
438/* 0x80; 0x80->0x9f: 16 byte cdbs */
439 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400440 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
441 0, 0, 0, SDEB_I_VERIFY,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900442 SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
443 SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500444 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 -0500445/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
446 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
447 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500448 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
449 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500450 0, 0, 0, 0, 0, 0, 0, 0,
451 0, 0, 0, 0, 0, 0, 0, 0,
452/* 0xc0; 0xc0->0xff: vendor specific */
453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
454 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
455 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
456 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
457};
458
Douglas Gilbert80c49562018-02-09 21:36:39 -0500459/*
460 * The following "response" functions return the SCSI mid-level's 4 byte
461 * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
462 * command completion, they can mask their return value with
463 * SDEG_RES_IMMED_MASK .
464 */
465#define SDEG_RES_IMMED_MASK 0x40000000
466
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500467static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
468static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
469static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
470static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
471static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
472static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
473static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
474static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
475static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500476static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500477static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
478static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
479static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
480static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
481static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500482static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
483static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400484static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500485static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
486static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500487static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500488static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert80c49562018-02-09 21:36:39 -0500489static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400490static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900491static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
492static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
493static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
494static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
495static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500496
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400497static int sdebug_do_add_host(bool mk_new_store);
498static int sdebug_add_host_helper(int per_host_idx);
499static void sdebug_do_remove_host(bool the_end);
500static int sdebug_add_store(void);
501static void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
502static void sdebug_erase_all_stores(bool apart_from_first);
503
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500504/*
505 * The following are overflow arrays for cdbs that "hit" the same index in
506 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
507 * should be placed in opcode_info_arr[], the others should be placed here.
508 */
509static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500510 {0, 0x1a, 0, F_D_IN, NULL, NULL,
511 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
512};
513
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500514static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500515 {0, 0x15, 0, F_D_OUT, NULL, NULL,
516 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
517};
518
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500519static const struct opcode_info_t read_iarr[] = {
520 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500521 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500522 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500523 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500524 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500525 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500526 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500527 0xc7, 0, 0, 0, 0} },
528};
529
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500530static const struct opcode_info_t write_iarr[] = {
531 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
532 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
533 0, 0, 0, 0, 0, 0} },
534 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
535 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
536 0, 0, 0} },
537 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
538 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
539 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500540};
541
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400542static const struct opcode_info_t verify_iarr[] = {
543 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
544 NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
545 0, 0, 0, 0, 0, 0} },
546};
547
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500548static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500549 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
550 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500551 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500552};
553
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500554static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
555 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500556 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500557 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500558 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
559 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
560 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500561};
562
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500563static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500564 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500565 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500566 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500567 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500568 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500569 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500570};
571
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500572static const struct opcode_info_t write_same_iarr[] = {
573 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500574 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500575 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500576};
577
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500578static const struct opcode_info_t reserve_iarr[] = {
579 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500580 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
581};
582
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500583static const struct opcode_info_t release_iarr[] = {
584 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500585 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
586};
587
Douglas Gilbert80c49562018-02-09 21:36:39 -0500588static const struct opcode_info_t sync_cache_iarr[] = {
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400589 {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500590 {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
591 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */
592};
593
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400594static const struct opcode_info_t pre_fetch_iarr[] = {
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400595 {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400596 {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
597 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */
598};
599
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900600static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400601 {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900602 {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
603 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400604 {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900605 {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
606 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400607 {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900608 {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
609 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */
610};
611
612static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400613 {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900614 {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
615 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
616};
617
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500618
619/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
620 * plus the terminating elements for logic that scans this table such as
621 * REPORT SUPPORTED OPERATION CODES. */
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400622static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500623/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500624 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500625 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500626 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500627 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
628 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
629 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500630 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500631 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
632 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
633 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
634 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500635/* 5 */
636 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
637 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
638 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
639 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
640 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
641 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
642 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500643 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
644 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500645 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500646 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
647 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500648 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
649 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
650 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500651/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500652 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
653 resp_write_dt0, write_iarr, /* WRITE(16) */
654 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500655 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400656 {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500657 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500658 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
659 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
660 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
661 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500662 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
663 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
664 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500665 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
666 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
667 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
668 0xff, 0, 0xc7, 0, 0, 0, 0} },
669/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500670 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
671 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -0400672 {ARRAY_SIZE(verify_iarr), 0x8f, 0,
673 F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */
674 verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
675 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500676 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
677 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
678 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
679 0xff, 0xff} },
680 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
681 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500682 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
683 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500684 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
685 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500686 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
687 0} },
688/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500689 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
690 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500691 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
692 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
693 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
694 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
695 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
696 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500697 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500698 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500699/* 25 */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500700 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
701 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
702 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500703 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
704 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
705 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
706 0, 0, 0, 0, 0} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400707 {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500708 resp_sync_cache, sync_cache_iarr,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500709 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500710 0, 0, 0, 0} }, /* SYNC_CACHE (10) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500711 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500712 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500713 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400714 {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400715 resp_pre_fetch, pre_fetch_iarr,
716 {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
717 0, 0, 0, 0} }, /* PRE-FETCH (10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500718
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400719/* 30 */
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400720 {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900721 resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
722 {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
723 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -0400724 {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900725 resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
726 {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
727 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
728/* sentinel */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500729 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
730 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
731};
732
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400733static int sdebug_num_hosts;
734static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400735static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500736static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400737static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert9267e0e2020-04-22 19:42:17 +0900738static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400739static int sdebug_dif = DEF_DIF;
740static int sdebug_dix = DEF_DIX;
741static int sdebug_dsense = DEF_D_SENSE;
742static int sdebug_every_nth = DEF_EVERY_NTH;
743static int sdebug_fake_rw = DEF_FAKE_RW;
744static unsigned int sdebug_guard = DEF_GUARD;
John Garryc10fa552020-07-09 20:23:20 +0800745static int sdebug_host_max_queue; /* per host */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400746static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
747static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400748static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Laurence Obermand9da8912018-02-03 13:38:35 -0500749static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
750static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400751static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400752static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400753static int sdebug_no_lun_0 = DEF_NO_LUN_0;
754static int sdebug_no_uld;
755static int sdebug_num_parts = DEF_NUM_PARTS;
756static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
757static int sdebug_opt_blks = DEF_OPT_BLKS;
758static int sdebug_opts = DEF_OPTS;
759static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100760static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400761static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400762static int sdebug_scsi_level = DEF_SCSI_LEVEL;
763static int sdebug_sector_size = DEF_SECTOR_SIZE;
Douglas Gilbertfc136382020-07-24 11:55:31 -0400764static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400765static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
766static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
767static unsigned int sdebug_lbpu = DEF_LBPU;
768static unsigned int sdebug_lbpws = DEF_LBPWS;
769static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
770static unsigned int sdebug_lbprz = DEF_LBPRZ;
771static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
772static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
773static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
774static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
775static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400776static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert0c4bc912020-04-21 11:14:17 -0400777static bool sdebug_random = DEF_RANDOM;
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400778static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400779static bool sdebug_removable = DEF_REMOVABLE;
780static bool sdebug_clustering;
781static bool sdebug_host_lock = DEF_HOST_LOCK;
782static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500783static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400784static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400785static bool have_dif_prot;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400786static bool write_since_sync;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400787static bool sdebug_statistics = DEF_STATISTICS;
Martin K. Petersen9447b6c2019-02-08 18:37:25 -0500788static bool sdebug_wp;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +0900789/* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
790static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
791static char *sdeb_zbc_model_s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792
Douglas Gilbertad0c7772020-08-21 00:22:49 -0400793enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
794 SAM_LUN_AM_FLAT = 0x1,
795 SAM_LUN_AM_LOGICAL_UNIT = 0x2,
796 SAM_LUN_AM_EXTENDED = 0x3};
797static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
798static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
799
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400800static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801static sector_t sdebug_capacity; /* in sectors */
802
803/* old BIOS stuff, kernel may get rid of them but some mode sense pages
804 may still need them */
805static int sdebug_heads; /* heads per disk */
806static int sdebug_cylinders_per; /* cylinders per surface */
807static int sdebug_sectors_per; /* sectors per cylinder */
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809static LIST_HEAD(sdebug_host_list);
810static DEFINE_SPINLOCK(sdebug_host_list_lock);
811
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400812static struct xarray per_store_arr;
813static struct xarray *per_store_ap = &per_store_arr;
814static int sdeb_first_idx = -1; /* invalid index ==> none created */
815static int sdeb_most_recent_idx = -1;
816static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Martin K. Petersen44d92692009-10-15 14:45:27 -0400818static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400819static int num_aborts;
820static int num_dev_resets;
821static int num_target_resets;
822static int num_bus_resets;
823static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500824static int dix_writes;
825static int dix_reads;
826static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900828/* ZBC global data */
Damien Le Moal64e14ec2020-04-22 19:42:21 +0900829static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */
Damien Le Moal98e0a682020-04-22 19:42:20 +0900830static int sdeb_zbc_zone_size_mb;
Damien Le Moal380603a2020-04-22 19:42:18 +0900831static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
Damien Le Moalaa8fecf2020-04-22 19:42:19 +0900832static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +0900833
Douglas Gilbertc4837392016-05-06 00:40:26 -0400834static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
Kashyap Desaic4b57d892021-02-15 13:10:46 +0530835static int poll_queues; /* iouring iopoll interface.*/
Douglas Gilbertc4837392016-05-06 00:40:26 -0400836static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838static DEFINE_RWLOCK(atomic_rw);
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400839static DEFINE_RWLOCK(atomic_rw2);
840
841static rwlock_t *ramdisk_lck_a[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400843static char sdebug_proc_name[] = MY_NAME;
844static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846static struct bus_type pseudo_lld_bus;
847
848static struct device_driver sdebug_driverfs_driver = {
849 .name = sdebug_proc_name,
850 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851};
852
853static const int check_condition_result =
854 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
855
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500856static const int illegal_condition_result =
857 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
858
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400859static const int device_qfull_result =
Hannes Reinecke7a64c812021-01-13 10:04:47 +0100860 (DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400861
Douglas Gilberted9f3e22020-04-21 11:14:22 -0400862static const int condition_met_result = SAM_STAT_CONDITION_MET;
863
Douglas Gilbertfd321192016-04-25 12:16:33 -0400864
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400865/* Only do the extra work involved in logical block provisioning if one or
866 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
867 * real reads and writes (i.e. not skipping them for speed).
868 */
869static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400870{
871 return 0 == sdebug_fake_rw &&
872 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
873}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400874
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400875static void *lba2fake_store(struct sdeb_store_info *sip,
876 unsigned long long lba)
Akinobu Mita14faa942013-09-18 21:27:24 +0900877{
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400878 struct sdeb_store_info *lsip = sip;
Akinobu Mita14faa942013-09-18 21:27:24 +0900879
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400880 lba = do_div(lba, sdebug_store_sectors);
881 if (!sip || !sip->storep) {
882 WARN_ON_ONCE(true);
883 lsip = xa_load(per_store_ap, 0); /* should never be NULL */
884 }
885 return lsip->storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900886}
887
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400888static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
889 sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900890{
Arnd Bergmann49413112015-11-20 17:38:28 +0100891 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900892
Douglas Gilbert87c715d2020-04-21 11:14:18 -0400893 return sip->dif_storep + sector;
Akinobu Mita14faa942013-09-18 21:27:24 +0900894}
895
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900896static void sdebug_max_tgts_luns(void)
897{
898 struct sdebug_host_info *sdbg_host;
899 struct Scsi_Host *hpnt;
900
901 spin_lock(&sdebug_host_list_lock);
902 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
903 hpnt = sdbg_host->shost;
904 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400905 (sdebug_num_tgts > hpnt->this_id))
906 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900907 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400908 hpnt->max_id = sdebug_num_tgts;
909 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300910 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900911 }
912 spin_unlock(&sdebug_host_list_lock);
913}
914
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500915enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
916
917/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400918static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
919 enum sdeb_cmd_data c_d,
920 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500921{
922 unsigned char *sbuff;
923 u8 sks[4];
924 int sl, asc;
925
926 sbuff = scp->sense_buffer;
927 if (!sbuff) {
928 sdev_printk(KERN_ERR, scp->device,
929 "%s: sense_buffer is NULL\n", __func__);
930 return;
931 }
932 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
933 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400934 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500935 memset(sks, 0, sizeof(sks));
936 sks[0] = 0x80;
937 if (c_d)
938 sks[0] |= 0x40;
939 if (in_bit >= 0) {
940 sks[0] |= 0x8;
941 sks[0] |= 0x7 & in_bit;
942 }
943 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400944 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500945 sl = sbuff[7] + 8;
946 sbuff[7] = sl;
947 sbuff[sl] = 0x2;
948 sbuff[sl + 1] = 0x6;
949 memcpy(sbuff + sl + 4, sks, 3);
950 } else
951 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400952 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500953 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
954 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
955 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
956}
957
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400958static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900959{
960 unsigned char *sbuff;
961
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400962 sbuff = scp->sense_buffer;
963 if (!sbuff) {
964 sdev_printk(KERN_ERR, scp->device,
965 "%s: sense_buffer is NULL\n", __func__);
966 return;
967 }
968 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900969
Douglas Gilbert773642d2016-04-25 12:16:28 -0400970 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900971
Douglas Gilbert773642d2016-04-25 12:16:28 -0400972 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400973 sdev_printk(KERN_INFO, scp->device,
974 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
975 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900976}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Douglas Gilbertfd321192016-04-25 12:16:33 -0400978static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500979{
980 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
981}
982
Nathan Chancellor6f4e6262019-02-07 09:07:20 -0700983static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
984 void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400986 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400987 if (0x1261 == cmd)
988 sdev_printk(KERN_INFO, dev,
989 "%s: BLKFLSBUF [0x1261]\n", __func__);
990 else if (0x5331 == cmd)
991 sdev_printk(KERN_INFO, dev,
992 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
993 __func__);
994 else
995 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
996 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 }
998 return -EINVAL;
999 /* return -ENOTTY; // correct return but upsets fdisk */
1000}
1001
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001002static void config_cdb_len(struct scsi_device *sdev)
1003{
1004 switch (sdebug_cdb_len) {
1005 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
1006 sdev->use_10_for_rw = false;
1007 sdev->use_16_for_rw = false;
1008 sdev->use_10_for_ms = false;
1009 break;
1010 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
1011 sdev->use_10_for_rw = true;
1012 sdev->use_16_for_rw = false;
1013 sdev->use_10_for_ms = false;
1014 break;
1015 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
1016 sdev->use_10_for_rw = true;
1017 sdev->use_16_for_rw = false;
1018 sdev->use_10_for_ms = true;
1019 break;
1020 case 16:
1021 sdev->use_10_for_rw = false;
1022 sdev->use_16_for_rw = true;
1023 sdev->use_10_for_ms = true;
1024 break;
1025 case 32: /* No knobs to suggest this so same as 16 for now */
1026 sdev->use_10_for_rw = false;
1027 sdev->use_16_for_rw = true;
1028 sdev->use_10_for_ms = true;
1029 break;
1030 default:
1031 pr_warn("unexpected cdb_len=%d, force to 10\n",
1032 sdebug_cdb_len);
1033 sdev->use_10_for_rw = true;
1034 sdev->use_16_for_rw = false;
1035 sdev->use_10_for_ms = false;
1036 sdebug_cdb_len = 10;
1037 break;
1038 }
1039}
1040
1041static void all_config_cdb_len(void)
1042{
1043 struct sdebug_host_info *sdbg_host;
1044 struct Scsi_Host *shost;
1045 struct scsi_device *sdev;
1046
1047 spin_lock(&sdebug_host_list_lock);
1048 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1049 shost = sdbg_host->shost;
1050 shost_for_each_device(sdev, shost) {
1051 config_cdb_len(sdev);
1052 }
1053 }
1054 spin_unlock(&sdebug_host_list_lock);
1055}
1056
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001057static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
1058{
1059 struct sdebug_host_info *sdhp;
1060 struct sdebug_dev_info *dp;
1061
1062 spin_lock(&sdebug_host_list_lock);
1063 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
1064 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
1065 if ((devip->sdbg_host == dp->sdbg_host) &&
1066 (devip->target == dp->target))
1067 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
1068 }
1069 }
1070 spin_unlock(&sdebug_host_list_lock);
1071}
1072
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001073static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001075 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001076
1077 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1078 if (k != SDEBUG_NUM_UAS) {
1079 const char *cp = NULL;
1080
1081 switch (k) {
1082 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001083 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1084 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001085 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001086 cp = "power on reset";
1087 break;
1088 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001089 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1090 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001091 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001092 cp = "bus reset";
1093 break;
1094 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001095 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1096 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001097 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001098 cp = "mode parameters changed";
1099 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05001100 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001101 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1102 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001103 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05001104 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -05001105 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001106 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001107 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001108 TARGET_CHANGED_ASC,
1109 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001110 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001111 cp = "microcode has been changed";
1112 break;
1113 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001114 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001115 TARGET_CHANGED_ASC,
1116 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001117 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001118 cp = "microcode has been changed without reset";
1119 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001120 case SDEBUG_UA_LUNS_CHANGED:
1121 /*
1122 * SPC-3 behavior is to report a UNIT ATTENTION with
1123 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
1124 * on the target, until a REPORT LUNS command is
1125 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -04001126 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001127 * values as struct scsi_device->scsi_level.
1128 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001129 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001130 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001131 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001132 TARGET_CHANGED_ASC,
1133 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001134 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001135 cp = "reported luns data has changed";
1136 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001137 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04001138 pr_warn("unexpected unit attention code=%d\n", k);
1139 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001140 cp = "unknown";
1141 break;
1142 }
1143 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001144 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001145 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001146 "%s reports: Unit attention: %s\n",
1147 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return check_condition_result;
1149 }
1150 return 0;
1151}
1152
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001153/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001154static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 int arr_len)
1156{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001157 int act_len;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001158 struct scsi_data_buffer *sdb = &scp->sdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001160 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001162 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbert773642d2016-04-25 12:16:28 -04001163 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001164
1165 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
1166 arr, arr_len);
Bart Van Assche42d387b2019-02-08 13:25:00 -08001167 scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 return 0;
1170}
1171
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001172/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1173 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1174 * calls, not required to write in ascending offset order. Assumes resid
1175 * set to scsi_bufflen() prior to any calls.
1176 */
1177static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1178 int arr_len, unsigned int off_dst)
1179{
Damien Le Moal9237f042019-10-30 18:08:47 +09001180 unsigned int act_len, n;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001181 struct scsi_data_buffer *sdb = &scp->sdb;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001182 off_t skip = off_dst;
1183
1184 if (sdb->length <= off_dst)
1185 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001186 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001187 return DID_ERROR << 16;
1188
1189 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1190 arr, arr_len, skip);
1191 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
Bart Van Assche42d387b2019-02-08 13:25:00 -08001192 __func__, off_dst, scsi_bufflen(scp), act_len,
1193 scsi_get_resid(scp));
Damien Le Moal9237f042019-10-30 18:08:47 +09001194 n = scsi_bufflen(scp) - (off_dst + act_len);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001195 scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001196 return 0;
1197}
1198
1199/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1200 * 'arr' or -1 if error.
1201 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001202static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1203 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001205 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001207 if (scp->sc_data_direction != DMA_TO_DEVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001209
1210 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211}
1212
1213
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001214static char sdebug_inq_vendor_id[9] = "Linux ";
1215static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001216static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001217/* Use some locally assigned NAAs for SAS addresses. */
1218static const u64 naa3_comp_a = 0x3222222000000000ULL;
1219static const u64 naa3_comp_b = 0x3333333000000000ULL;
1220static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001222/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001223static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1224 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001225 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001226 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001228 int num, port_a;
1229 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001231 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 /* T10 vendor identifier field format (faked) */
1233 arr[0] = 0x2; /* ASCII */
1234 arr[1] = 0x1;
1235 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001236 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1237 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1239 num = 8 + 16 + dev_id_str_len;
1240 arr[3] = num;
1241 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001242 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001243 if (sdebug_uuid_ctl) {
1244 /* Locally assigned UUID */
1245 arr[num++] = 0x1; /* binary (not necessarily sas) */
1246 arr[num++] = 0xa; /* PIV=0, lu, naa */
1247 arr[num++] = 0x0;
1248 arr[num++] = 0x12;
1249 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1250 arr[num++] = 0x0;
1251 memcpy(arr + num, lu_name, 16);
1252 num += 16;
1253 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001254 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001255 arr[num++] = 0x1; /* binary (not necessarily sas) */
1256 arr[num++] = 0x3; /* PIV=0, lu, naa */
1257 arr[num++] = 0x0;
1258 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001259 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001260 num += 8;
1261 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001262 /* Target relative port number */
1263 arr[num++] = 0x61; /* proto=sas, binary */
1264 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1265 arr[num++] = 0x0; /* reserved */
1266 arr[num++] = 0x4; /* length */
1267 arr[num++] = 0x0; /* reserved */
1268 arr[num++] = 0x0; /* reserved */
1269 arr[num++] = 0x0;
1270 arr[num++] = 0x1; /* relative port A */
1271 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001272 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001273 arr[num++] = 0x61; /* proto=sas, binary */
1274 arr[num++] = 0x93; /* piv=1, target port, naa */
1275 arr[num++] = 0x0;
1276 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001277 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001278 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001279 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001280 arr[num++] = 0x61; /* proto=sas, binary */
1281 arr[num++] = 0x95; /* piv=1, target port group id */
1282 arr[num++] = 0x0;
1283 arr[num++] = 0x4;
1284 arr[num++] = 0;
1285 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001286 put_unaligned_be16(port_group_id, arr + num);
1287 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001288 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001289 arr[num++] = 0x61; /* proto=sas, binary */
1290 arr[num++] = 0xa3; /* piv=1, target device, naa */
1291 arr[num++] = 0x0;
1292 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001293 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001294 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001295 /* SCSI name string: Target device identifier */
1296 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1297 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1298 arr[num++] = 0x0;
1299 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001300 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001301 num += 12;
1302 snprintf(b, sizeof(b), "%08X", target_dev_id);
1303 memcpy(arr + num, b, 8);
1304 num += 8;
1305 memset(arr + num, 0, 4);
1306 num += 4;
1307 return num;
1308}
1309
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001310static unsigned char vpd84_data[] = {
1311/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1312 0x22,0x22,0x22,0x0,0xbb,0x1,
1313 0x22,0x22,0x22,0x0,0xbb,0x2,
1314};
1315
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001316/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001317static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001318{
1319 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1320 return sizeof(vpd84_data);
1321}
1322
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001323/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001324static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001325{
1326 int num = 0;
John Pittman91d4c752018-02-09 21:12:43 -05001327 const char *na1 = "https://www.kernel.org/config";
1328 const char *na2 = "http://www.kernel.org/log";
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001329 int plen, olen;
1330
1331 arr[num++] = 0x1; /* lu, storage config */
1332 arr[num++] = 0x0; /* reserved */
1333 arr[num++] = 0x0;
1334 olen = strlen(na1);
1335 plen = olen + 1;
1336 if (plen % 4)
1337 plen = ((plen / 4) + 1) * 4;
1338 arr[num++] = plen; /* length, null termianted, padded */
1339 memcpy(arr + num, na1, olen);
1340 memset(arr + num + olen, 0, plen - olen);
1341 num += plen;
1342
1343 arr[num++] = 0x4; /* lu, logging */
1344 arr[num++] = 0x0; /* reserved */
1345 arr[num++] = 0x0;
1346 olen = strlen(na2);
1347 plen = olen + 1;
1348 if (plen % 4)
1349 plen = ((plen / 4) + 1) * 4;
1350 arr[num++] = plen; /* length, null terminated, padded */
1351 memcpy(arr + num, na2, olen);
1352 memset(arr + num + olen, 0, plen - olen);
1353 num += plen;
1354
1355 return num;
1356}
1357
1358/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001359static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001360{
1361 int num = 0;
1362 int port_a, port_b;
1363
1364 port_a = target_dev_id + 1;
1365 port_b = port_a + 1;
1366 arr[num++] = 0x0; /* reserved */
1367 arr[num++] = 0x0; /* reserved */
1368 arr[num++] = 0x0;
1369 arr[num++] = 0x1; /* relative port 1 (primary) */
1370 memset(arr + num, 0, 6);
1371 num += 6;
1372 arr[num++] = 0x0;
1373 arr[num++] = 12; /* length tp descriptor */
1374 /* naa-5 target port identifier (A) */
1375 arr[num++] = 0x61; /* proto=sas, binary */
1376 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1377 arr[num++] = 0x0; /* reserved */
1378 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001379 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001380 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001381 arr[num++] = 0x0; /* reserved */
1382 arr[num++] = 0x0; /* reserved */
1383 arr[num++] = 0x0;
1384 arr[num++] = 0x2; /* relative port 2 (secondary) */
1385 memset(arr + num, 0, 6);
1386 num += 6;
1387 arr[num++] = 0x0;
1388 arr[num++] = 12; /* length tp descriptor */
1389 /* naa-5 target port identifier (B) */
1390 arr[num++] = 0x61; /* proto=sas, binary */
1391 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1392 arr[num++] = 0x0; /* reserved */
1393 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001394 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001395 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001396
1397 return num;
1398}
1399
1400
1401static unsigned char vpd89_data[] = {
1402/* from 4th byte */ 0,0,0,0,
1403'l','i','n','u','x',' ',' ',' ',
1404'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1405'1','2','3','4',
14060x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
14070xec,0,0,0,
14080x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
14090,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
14100x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
14110x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
14120x53,0x41,
14130x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
14140x20,0x20,
14150x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
14160x10,0x80,
14170,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
14180x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
14190x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
14200,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
14210x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
14220x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
14230,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
14240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14270x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
14280,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
14290xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
14300,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
14390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14420,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1443};
1444
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001445/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001446static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001447{
1448 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1449 return sizeof(vpd89_data);
1450}
1451
1452
1453static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001454 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1455 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1456 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1457 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001458};
1459
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001460/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001461static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001463 unsigned int gran;
1464
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001465 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001466
1467 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001468 if (sdebug_opt_xferlen_exp != 0 &&
1469 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1470 gran = 1 << sdebug_opt_xferlen_exp;
1471 else
1472 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001473 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001474
1475 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001476 if (sdebug_store_sectors > 0x400)
1477 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001478
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001479 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001480 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001481
Douglas Gilbert773642d2016-04-25 12:16:28 -04001482 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001483 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001484 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001485
1486 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001487 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001488 }
1489
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001490 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001491 if (sdebug_unmap_alignment) {
1492 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001493 arr[28] |= 0x80; /* UGAVALID */
1494 }
1495
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001496 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001497 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001498
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001499 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001500 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001501
1502 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001503
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001504 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505}
1506
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001507/* Block device characteristics VPD page (SBC-3) */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001508static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001509{
1510 memset(arr, 0, 0x3c);
1511 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001512 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1513 arr[2] = 0;
1514 arr[3] = 5; /* less than 1.8" */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001515 if (devip->zmodel == BLK_ZONED_HA)
1516 arr[4] = 1 << 4; /* zoned field = 01b */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001517
1518 return 0x3c;
1519}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001521/* Logical block provisioning VPD page (SBC-4) */
1522static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001523{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001524 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001525 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001526 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001527 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001528 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001529 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001530 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001531 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001532 if (sdebug_lbprz && scsi_debug_lbp())
1533 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1534 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1535 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1536 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001537 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001538}
1539
Douglas Gilbertd36da302020-04-22 19:42:15 +09001540/* Zoned block device characteristics VPD page (ZBC mandatory) */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001541static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
Douglas Gilbertd36da302020-04-22 19:42:15 +09001542{
1543 memset(arr, 0, 0x3c);
1544 arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1545 /*
1546 * Set Optimal number of open sequential write preferred zones and
1547 * Optimal number of non-sequentially written sequential write
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001548 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1549 * fields set to zero, apart from Max. number of open swrz_s field.
Douglas Gilbertd36da302020-04-22 19:42:15 +09001550 */
1551 put_unaligned_be32(0xffffffff, &arr[4]);
1552 put_unaligned_be32(0xffffffff, &arr[8]);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001553 if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001554 put_unaligned_be32(devip->max_open, &arr[12]);
1555 else
1556 put_unaligned_be32(0xffffffff, &arr[12]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001557 return 0x3c;
1558}
1559
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001561#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001563static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564{
1565 unsigned char pq_pdt;
John Pittman91d4c752018-02-09 21:12:43 -05001566 unsigned char *arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001567 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001568 int alloc_len, n, ret;
Douglas Gilbertd36da302020-04-22 19:42:15 +09001569 bool have_wlun, is_disk, is_zbc, is_disk_zbc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
Douglas Gilbert773642d2016-04-25 12:16:28 -04001571 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001572 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1573 if (! arr)
1574 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001575 is_disk = (sdebug_ptype == TYPE_DISK);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001576 is_zbc = (devip->zmodel != BLK_ZONED_NONE);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001577 is_disk_zbc = (is_disk || is_zbc);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001578 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001579 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001580 pq_pdt = TYPE_WLUN; /* present, wlun */
1581 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1582 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001583 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001584 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 arr[0] = pq_pdt;
1586 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001587 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001588 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 return check_condition_result;
1590 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001591 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001592 char lu_id_str[6];
1593 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001595 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1596 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001597 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001598 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001599 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001600 (devip->target * 1000) + devip->lun);
1601 target_dev_id = ((host_no + 1) * 2000) +
1602 (devip->target * 1000) - 3;
1603 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001605 arr[1] = cmd[2]; /*sanity */
1606 n = 4;
1607 arr[n++] = 0x0; /* this page */
1608 arr[n++] = 0x80; /* unit serial number */
1609 arr[n++] = 0x83; /* device identification */
1610 arr[n++] = 0x84; /* software interface ident. */
1611 arr[n++] = 0x85; /* management network addresses */
1612 arr[n++] = 0x86; /* extended inquiry */
1613 arr[n++] = 0x87; /* mode page policy */
1614 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbertd36da302020-04-22 19:42:15 +09001615 if (is_disk_zbc) { /* SBC or ZBC */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001616 arr[n++] = 0x89; /* ATA information */
1617 arr[n++] = 0xb0; /* Block limits */
1618 arr[n++] = 0xb1; /* Block characteristics */
Douglas Gilbertd36da302020-04-22 19:42:15 +09001619 if (is_disk)
1620 arr[n++] = 0xb2; /* LB Provisioning */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001621 if (is_zbc)
Douglas Gilbertd36da302020-04-22 19:42:15 +09001622 arr[n++] = 0xb6; /* ZB dev. char. */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001623 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001624 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001626 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001628 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001630 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001631 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1632 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001633 lu_id_str, len,
1634 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001635 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1636 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001637 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001638 } else if (0x85 == cmd[2]) { /* Management network addresses */
1639 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001640 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001641 } else if (0x86 == cmd[2]) { /* extended inquiry */
1642 arr[1] = cmd[2]; /*sanity */
1643 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001644 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001645 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001646 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001647 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1648 else
1649 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001650 arr[5] = 0x7; /* head of q, ordered + simple q's */
1651 } else if (0x87 == cmd[2]) { /* mode page policy */
1652 arr[1] = cmd[2]; /*sanity */
1653 arr[3] = 0x8; /* number of following entries */
1654 arr[4] = 0x2; /* disconnect-reconnect mp */
1655 arr[6] = 0x80; /* mlus, shared */
1656 arr[8] = 0x18; /* protocol specific lu */
1657 arr[10] = 0x82; /* mlus, per initiator port */
1658 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1659 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001660 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001661 } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001662 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001663 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001664 put_unaligned_be16(n, arr + 2);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001665 } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001666 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001667 arr[3] = inquiry_vpd_b0(&arr[4]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001668 } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001669 arr[1] = cmd[2]; /*sanity */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001670 arr[3] = inquiry_vpd_b1(devip, &arr[4]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001671 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001672 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001673 arr[3] = inquiry_vpd_b2(&arr[4]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001674 } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1675 arr[1] = cmd[2]; /*sanity */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001676 arr[3] = inquiry_vpd_b6(devip, &arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001678 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001679 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 return check_condition_result;
1681 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001682 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001683 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001684 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001685 kfree(arr);
1686 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 }
1688 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001689 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1690 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 arr[3] = 2; /* response_data_format==2 */
1692 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001693 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001694 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001695 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001696 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001698 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001699 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1700 memcpy(&arr[16], sdebug_inq_product_id, 16);
1701 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001702 /* Use Vendor Specific area to place driver date in ASCII hex */
1703 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001705 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1706 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001707 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001708 if (is_disk) { /* SBC-4 no version claimed */
1709 put_unaligned_be16(0x600, arr + n);
1710 n += 2;
1711 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1712 put_unaligned_be16(0x525, arr + n);
1713 n += 2;
Douglas Gilbertd36da302020-04-22 19:42:15 +09001714 } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */
1715 put_unaligned_be16(0x624, arr + n);
1716 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001718 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001719 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001720 min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001721 kfree(arr);
1722 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723}
1724
Douglas Gilbert84905d32020-07-23 15:48:19 -04001725/* See resp_iec_m_pg() for how this data is manipulated */
Douglas Gilbertfd321192016-04-25 12:16:33 -04001726static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1727 0, 0, 0x0, 0x0};
1728
John Pittman91d4c752018-02-09 21:12:43 -05001729static int resp_requests(struct scsi_cmnd *scp,
1730 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001732 unsigned char *cmd = scp->cmnd;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001733 unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */
1734 bool dsense = !!(cmd[1] & 1);
1735 int alloc_len = cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 int len = 18;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001737 int stopped_state = atomic_read(&devip->stopped);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001739 memset(arr, 0, sizeof(arr));
Douglas Gilbert84905d32020-07-23 15:48:19 -04001740 if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */
1741 if (dsense) {
1742 arr[0] = 0x72;
1743 arr[1] = NOT_READY;
1744 arr[2] = LOGICAL_UNIT_NOT_READY;
1745 arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
1746 len = 8;
1747 } else {
1748 arr[0] = 0x70;
1749 arr[2] = NOT_READY; /* NO_SENSE in sense_key */
1750 arr[7] = 0xa; /* 18 byte sense buffer */
1751 arr[12] = LOGICAL_UNIT_NOT_READY;
1752 arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
1753 }
1754 } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1755 /* Information exceptions control mode page: TEST=1, MRIE=6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001756 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001757 arr[0] = 0x72;
1758 arr[1] = 0x0; /* NO_SENSE in sense_key */
1759 arr[2] = THRESHOLD_EXCEEDED;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001760 arr[3] = 0xff; /* Failure prediction(false) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001761 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001762 } else {
1763 arr[0] = 0x70;
1764 arr[2] = 0x0; /* NO_SENSE in sense_key */
1765 arr[7] = 0xa; /* 18 byte sense buffer */
1766 arr[12] = THRESHOLD_EXCEEDED;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001767 arr[13] = 0xff; /* Failure prediction(false) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001768 }
Douglas Gilbert84905d32020-07-23 15:48:19 -04001769 } else { /* nothing to report */
1770 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001771 len = 8;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001772 memset(arr, 0, len);
1773 arr[0] = 0x72;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001774 } else {
Douglas Gilbert84905d32020-07-23 15:48:19 -04001775 memset(arr, 0, len);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001776 arr[0] = 0x70;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001777 arr[7] = 0xa;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001778 }
1779 }
Douglas Gilbert84905d32020-07-23 15:48:19 -04001780 return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781}
1782
Douglas Gilbertfc136382020-07-24 11:55:31 -04001783static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001784{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001785 unsigned char *cmd = scp->cmnd;
Douglas Gilbertfc136382020-07-24 11:55:31 -04001786 int power_cond, want_stop, stopped_state;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001787 bool changing;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001788
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001789 power_cond = (cmd[4] & 0xf0) >> 4;
1790 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001791 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001792 return check_condition_result;
1793 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04001794 want_stop = !(cmd[4] & 1);
1795 stopped_state = atomic_read(&devip->stopped);
1796 if (stopped_state == 2) {
1797 ktime_t now_ts = ktime_get_boottime();
1798
1799 if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1800 u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1801
1802 if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1803 /* tur_ms_to_ready timer extinguished */
1804 atomic_set(&devip->stopped, 0);
1805 stopped_state = 0;
1806 }
1807 }
1808 if (stopped_state == 2) {
1809 if (want_stop) {
1810 stopped_state = 1; /* dummy up success */
1811 } else { /* Disallow tur_ms_to_ready delay to be overridden */
1812 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1813 return check_condition_result;
1814 }
1815 }
1816 }
1817 changing = (stopped_state != want_stop);
1818 if (changing)
1819 atomic_xchg(&devip->stopped, want_stop);
1820 if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001821 return SDEG_RES_IMMED_MASK;
1822 else
1823 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001824}
1825
FUJITA Tomonori28898872008-03-30 00:59:55 +09001826static sector_t get_sdebug_capacity(void)
1827{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001828 static const unsigned int gibibyte = 1073741824;
1829
1830 if (sdebug_virtual_gb > 0)
1831 return (sector_t)sdebug_virtual_gb *
1832 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001833 else
1834 return sdebug_store_sectors;
1835}
1836
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837#define SDEBUG_READCAP_ARR_SZ 8
John Pittman91d4c752018-02-09 21:12:43 -05001838static int resp_readcap(struct scsi_cmnd *scp,
1839 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840{
1841 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001842 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001844 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001845 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001847 if (sdebug_capacity < 0xffffffff) {
1848 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001849 put_unaligned_be32(capac, arr + 0);
1850 } else
1851 put_unaligned_be32(0xffffffff, arr + 0);
1852 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1854}
1855
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001856#define SDEBUG_READCAP16_ARR_SZ 32
John Pittman91d4c752018-02-09 21:12:43 -05001857static int resp_readcap16(struct scsi_cmnd *scp,
1858 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001859{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001860 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001861 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001862 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001863
Douglas Gilbert773642d2016-04-25 12:16:28 -04001864 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001865 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001866 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001867 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001868 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1869 put_unaligned_be32(sdebug_sector_size, arr + 8);
1870 arr[13] = sdebug_physblk_exp & 0xf;
1871 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001872
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001873 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001874 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001875 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1876 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1877 * in the wider field maps to 0 in this field.
1878 */
1879 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1880 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001881 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001882
Douglas Gilbert773642d2016-04-25 12:16:28 -04001883 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001884
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001885 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001886 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001887 arr[12] |= 1; /* PROT_EN */
1888 }
1889
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001890 return fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001891 min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001892}
1893
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001894#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1895
John Pittman91d4c752018-02-09 21:12:43 -05001896static int resp_report_tgtpgs(struct scsi_cmnd *scp,
1897 struct sdebug_dev_info *devip)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001898{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001899 unsigned char *cmd = scp->cmnd;
John Pittman91d4c752018-02-09 21:12:43 -05001900 unsigned char *arr;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001901 int host_no = devip->sdbg_host->shost->host_no;
1902 int n, ret, alen, rlen;
1903 int port_group_a, port_group_b, port_a, port_b;
1904
Douglas Gilbert773642d2016-04-25 12:16:28 -04001905 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001906 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1907 if (! arr)
1908 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001909 /*
1910 * EVPD page 0x88 states we have two ports, one
1911 * real and a fake port with no device connected.
1912 * So we create two port groups with one port each
1913 * and set the group with port B to unavailable.
1914 */
1915 port_a = 0x1; /* relative port A */
1916 port_b = 0x2; /* relative port B */
1917 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001918 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001919 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001920 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001921
1922 /*
1923 * The asymmetric access state is cycled according to the host_id.
1924 */
1925 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001926 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001927 arr[n++] = host_no % 3; /* Asymm access state */
1928 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001929 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001930 arr[n++] = 0x0; /* Active/Optimized path */
1931 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001932 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001933 put_unaligned_be16(port_group_a, arr + n);
1934 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001935 arr[n++] = 0; /* Reserved */
1936 arr[n++] = 0; /* Status code */
1937 arr[n++] = 0; /* Vendor unique */
1938 arr[n++] = 0x1; /* One port per group */
1939 arr[n++] = 0; /* Reserved */
1940 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001941 put_unaligned_be16(port_a, arr + n);
1942 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001943 arr[n++] = 3; /* Port unavailable */
1944 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001945 put_unaligned_be16(port_group_b, arr + n);
1946 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001947 arr[n++] = 0; /* Reserved */
1948 arr[n++] = 0; /* Status code */
1949 arr[n++] = 0; /* Vendor unique */
1950 arr[n++] = 0x1; /* One port per group */
1951 arr[n++] = 0; /* Reserved */
1952 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001953 put_unaligned_be16(port_b, arr + n);
1954 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001955
1956 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001957 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001958
1959 /*
1960 * Return the smallest value of either
1961 * - The allocated length
1962 * - The constructed command length
1963 * - The maximum array size
1964 */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001965 rlen = min_t(int, alen, n);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001966 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001967 min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001968 kfree(arr);
1969 return ret;
1970}
1971
Douglas Gilbertfd321192016-04-25 12:16:33 -04001972static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1973 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001974{
1975 bool rctd;
1976 u8 reporting_opts, req_opcode, sdeb_i, supp;
1977 u16 req_sa, u;
1978 u32 alloc_len, a_len;
1979 int k, offset, len, errsts, count, bump, na;
1980 const struct opcode_info_t *oip;
1981 const struct opcode_info_t *r_oip;
1982 u8 *arr;
1983 u8 *cmd = scp->cmnd;
1984
1985 rctd = !!(cmd[2] & 0x80);
1986 reporting_opts = cmd[2] & 0x7;
1987 req_opcode = cmd[3];
1988 req_sa = get_unaligned_be16(cmd + 4);
1989 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001990 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001991 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1992 return check_condition_result;
1993 }
1994 if (alloc_len > 8192)
1995 a_len = 8192;
1996 else
1997 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001998 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001999 if (NULL == arr) {
2000 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
2001 INSUFF_RES_ASCQ);
2002 return check_condition_result;
2003 }
2004 switch (reporting_opts) {
2005 case 0: /* all commands */
2006 /* count number of commands */
2007 for (count = 0, oip = opcode_info_arr;
2008 oip->num_attached != 0xff; ++oip) {
2009 if (F_INV_OP & oip->flags)
2010 continue;
2011 count += (oip->num_attached + 1);
2012 }
2013 bump = rctd ? 20 : 8;
2014 put_unaligned_be32(count * bump, arr);
2015 for (offset = 4, oip = opcode_info_arr;
2016 oip->num_attached != 0xff && offset < a_len; ++oip) {
2017 if (F_INV_OP & oip->flags)
2018 continue;
2019 na = oip->num_attached;
2020 arr[offset] = oip->opcode;
2021 put_unaligned_be16(oip->sa, arr + offset + 2);
2022 if (rctd)
2023 arr[offset + 5] |= 0x2;
2024 if (FF_SA & oip->flags)
2025 arr[offset + 5] |= 0x1;
2026 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
2027 if (rctd)
2028 put_unaligned_be16(0xa, arr + offset + 8);
2029 r_oip = oip;
2030 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
2031 if (F_INV_OP & oip->flags)
2032 continue;
2033 offset += bump;
2034 arr[offset] = oip->opcode;
2035 put_unaligned_be16(oip->sa, arr + offset + 2);
2036 if (rctd)
2037 arr[offset + 5] |= 0x2;
2038 if (FF_SA & oip->flags)
2039 arr[offset + 5] |= 0x1;
2040 put_unaligned_be16(oip->len_mask[0],
2041 arr + offset + 6);
2042 if (rctd)
2043 put_unaligned_be16(0xa,
2044 arr + offset + 8);
2045 }
2046 oip = r_oip;
2047 offset += bump;
2048 }
2049 break;
2050 case 1: /* one command: opcode only */
2051 case 2: /* one command: opcode plus service action */
2052 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
2053 sdeb_i = opcode_ind_arr[req_opcode];
2054 oip = &opcode_info_arr[sdeb_i];
2055 if (F_INV_OP & oip->flags) {
2056 supp = 1;
2057 offset = 4;
2058 } else {
2059 if (1 == reporting_opts) {
2060 if (FF_SA & oip->flags) {
2061 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
2062 2, 2);
2063 kfree(arr);
2064 return check_condition_result;
2065 }
2066 req_sa = 0;
2067 } else if (2 == reporting_opts &&
2068 0 == (FF_SA & oip->flags)) {
2069 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
2070 kfree(arr); /* point at requested sa */
2071 return check_condition_result;
2072 }
2073 if (0 == (FF_SA & oip->flags) &&
2074 req_opcode == oip->opcode)
2075 supp = 3;
2076 else if (0 == (FF_SA & oip->flags)) {
2077 na = oip->num_attached;
2078 for (k = 0, oip = oip->arrp; k < na;
2079 ++k, ++oip) {
2080 if (req_opcode == oip->opcode)
2081 break;
2082 }
2083 supp = (k >= na) ? 1 : 3;
2084 } else if (req_sa != oip->sa) {
2085 na = oip->num_attached;
2086 for (k = 0, oip = oip->arrp; k < na;
2087 ++k, ++oip) {
2088 if (req_sa == oip->sa)
2089 break;
2090 }
2091 supp = (k >= na) ? 1 : 3;
2092 } else
2093 supp = 3;
2094 if (3 == supp) {
2095 u = oip->len_mask[0];
2096 put_unaligned_be16(u, arr + 2);
2097 arr[4] = oip->opcode;
2098 for (k = 1; k < u; ++k)
2099 arr[4 + k] = (k < 16) ?
2100 oip->len_mask[k] : 0xff;
2101 offset = 4 + u;
2102 } else
2103 offset = 4;
2104 }
2105 arr[1] = (rctd ? 0x80 : 0) | supp;
2106 if (rctd) {
2107 put_unaligned_be16(0xa, arr + offset);
2108 offset += 12;
2109 }
2110 break;
2111 default:
2112 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
2113 kfree(arr);
2114 return check_condition_result;
2115 }
2116 offset = (offset < a_len) ? offset : a_len;
2117 len = (offset < alloc_len) ? offset : alloc_len;
2118 errsts = fill_from_dev_buffer(scp, arr, len);
2119 kfree(arr);
2120 return errsts;
2121}
2122
Douglas Gilbertfd321192016-04-25 12:16:33 -04002123static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2124 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002125{
2126 bool repd;
2127 u32 alloc_len, len;
2128 u8 arr[16];
2129 u8 *cmd = scp->cmnd;
2130
2131 memset(arr, 0, sizeof(arr));
2132 repd = !!(cmd[2] & 0x80);
2133 alloc_len = get_unaligned_be32(cmd + 6);
2134 if (alloc_len < 4) {
2135 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
2136 return check_condition_result;
2137 }
2138 arr[0] = 0xc8; /* ATS | ATSS | LURS */
2139 arr[1] = 0x1; /* ITNRS */
2140 if (repd) {
2141 arr[3] = 0xc;
2142 len = 16;
2143 } else
2144 len = 4;
2145
2146 len = (len < alloc_len) ? len : alloc_len;
2147 return fill_from_dev_buffer(scp, arr, len);
2148}
2149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150/* <<Following mode page info copied from ST318451LW>> */
2151
John Pittman91d4c752018-02-09 21:12:43 -05002152static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153{ /* Read-Write Error Recovery page for mode_sense */
2154 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
2155 5, 0, 0xff, 0xff};
2156
2157 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
2158 if (1 == pcontrol)
2159 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
2160 return sizeof(err_recov_pg);
2161}
2162
John Pittman91d4c752018-02-09 21:12:43 -05002163static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164{ /* Disconnect-Reconnect page for mode_sense */
2165 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
2166 0, 0, 0, 0, 0, 0, 0, 0};
2167
2168 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
2169 if (1 == pcontrol)
2170 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
2171 return sizeof(disconnect_pg);
2172}
2173
John Pittman91d4c752018-02-09 21:12:43 -05002174static int resp_format_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175{ /* Format device page for mode_sense */
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002176 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
2177 0, 0, 0, 0, 0, 0, 0, 0,
2178 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002180 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002181 put_unaligned_be16(sdebug_sectors_per, p + 10);
2182 put_unaligned_be16(sdebug_sector_size, p + 12);
2183 if (sdebug_removable)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002184 p[20] |= 0x20; /* should agree with INQUIRY */
2185 if (1 == pcontrol)
2186 memset(p + 2, 0, sizeof(format_pg) - 2);
2187 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188}
2189
Douglas Gilbertfd321192016-04-25 12:16:33 -04002190static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2191 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2192 0, 0, 0, 0};
2193
John Pittman91d4c752018-02-09 21:12:43 -05002194static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002196 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2197 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2198 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
2200
Douglas Gilbert773642d2016-04-25 12:16:28 -04002201 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002202 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 memcpy(p, caching_pg, sizeof(caching_pg));
2204 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002205 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2206 else if (2 == pcontrol)
2207 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 return sizeof(caching_pg);
2209}
2210
Douglas Gilbertfd321192016-04-25 12:16:33 -04002211static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2212 0, 0, 0x2, 0x4b};
2213
John Pittman91d4c752018-02-09 21:12:43 -05002214static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002216 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05002217 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002218 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 0, 0, 0x2, 0x4b};
2220
Douglas Gilbert773642d2016-04-25 12:16:28 -04002221 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002223 else
2224 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002225
Douglas Gilbert773642d2016-04-25 12:16:28 -04002226 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002227 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2228
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2230 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002231 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2232 else if (2 == pcontrol)
2233 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 return sizeof(ctrl_m_pg);
2235}
2236
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002237
John Pittman91d4c752018-02-09 21:12:43 -05002238static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002240 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2241 0, 0, 0x0, 0x0};
2242 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2243 0, 0, 0x0, 0x0};
2244
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2246 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002247 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2248 else if (2 == pcontrol)
2249 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 return sizeof(iec_m_pg);
2251}
2252
John Pittman91d4c752018-02-09 21:12:43 -05002253static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002254{ /* SAS SSP mode page - short format for mode_sense */
2255 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2256 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2257
2258 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2259 if (1 == pcontrol)
2260 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2261 return sizeof(sas_sf_m_pg);
2262}
2263
2264
John Pittman91d4c752018-02-09 21:12:43 -05002265static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002266 int target_dev_id)
2267{ /* SAS phy control and discover mode page for mode_sense */
2268 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2269 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002270 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2271 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002272 0x2, 0, 0, 0, 0, 0, 0, 0,
2273 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2274 0, 0, 0, 0, 0, 0, 0, 0,
2275 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002276 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2277 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002278 0x3, 0, 0, 0, 0, 0, 0, 0,
2279 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2280 0, 0, 0, 0, 0, 0, 0, 0,
2281 };
2282 int port_a, port_b;
2283
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002284 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2285 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2286 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2287 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002288 port_a = target_dev_id + 1;
2289 port_b = port_a + 1;
2290 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002291 put_unaligned_be32(port_a, p + 20);
2292 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002293 if (1 == pcontrol)
2294 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2295 return sizeof(sas_pcd_m_pg);
2296}
2297
John Pittman91d4c752018-02-09 21:12:43 -05002298static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002299{ /* SAS SSP shared protocol specific port mode subpage */
2300 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2301 0, 0, 0, 0, 0, 0, 0, 0,
2302 };
2303
2304 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2305 if (1 == pcontrol)
2306 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2307 return sizeof(sas_sha_m_pg);
2308}
2309
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310#define SDEBUG_MAX_MSENSE_SZ 256
2311
Douglas Gilbertfd321192016-04-25 12:16:33 -04002312static int resp_mode_sense(struct scsi_cmnd *scp,
2313 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314{
Douglas Gilbert23183912006-09-16 20:30:47 -04002315 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002317 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002318 int target = scp->device->id;
John Pittman91d4c752018-02-09 21:12:43 -05002319 unsigned char *ap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002321 unsigned char *cmd = scp->cmnd;
Douglas Gilbertd36da302020-04-22 19:42:15 +09002322 bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002324 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 pcontrol = (cmd[2] & 0xc0) >> 6;
2326 pcode = cmd[2] & 0x3f;
2327 subpcode = cmd[3];
2328 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002329 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2330 is_disk = (sdebug_ptype == TYPE_DISK);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002331 is_zbc = (devip->zmodel != BLK_ZONED_NONE);
Douglas Gilbertd36da302020-04-22 19:42:15 +09002332 if ((is_disk || is_zbc) && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002333 bd_len = llbaa ? 16 : 8;
2334 else
2335 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002336 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2338 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002339 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 return check_condition_result;
2341 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002342 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2343 (devip->target * 1000) - 3;
Douglas Gilbertd36da302020-04-22 19:42:15 +09002344 /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2345 if (is_disk || is_zbc) {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002346 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002347 if (sdebug_wp)
2348 dev_spec |= 0x80;
2349 } else
Douglas Gilbert23183912006-09-16 20:30:47 -04002350 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 if (msense_6) {
2352 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002353 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 offset = 4;
2355 } else {
2356 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002357 if (16 == bd_len)
2358 arr[4] = 0x1; /* set LONGLBA bit */
2359 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 offset = 8;
2361 }
2362 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002363 if ((bd_len > 0) && (!sdebug_capacity))
2364 sdebug_capacity = get_sdebug_capacity();
2365
Douglas Gilbert23183912006-09-16 20:30:47 -04002366 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002367 if (sdebug_capacity > 0xfffffffe)
2368 put_unaligned_be32(0xffffffff, ap + 0);
2369 else
2370 put_unaligned_be32(sdebug_capacity, ap + 0);
2371 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002372 offset += bd_len;
2373 ap = arr + offset;
2374 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002375 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2376 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002377 offset += bd_len;
2378 ap = arr + offset;
2379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002381 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2382 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002383 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 return check_condition_result;
2385 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002386 bad_pcode = false;
2387
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 switch (pcode) {
2389 case 0x1: /* Read-Write error recovery page, direct access */
2390 len = resp_err_recov_pg(ap, pcontrol, target);
2391 offset += len;
2392 break;
2393 case 0x2: /* Disconnect-Reconnect page, all devices */
2394 len = resp_disconnect_pg(ap, pcontrol, target);
2395 offset += len;
2396 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002397 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002398 if (is_disk) {
2399 len = resp_format_pg(ap, pcontrol, target);
2400 offset += len;
2401 } else
2402 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002403 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 case 0x8: /* Caching page, direct access */
Douglas Gilbertd36da302020-04-22 19:42:15 +09002405 if (is_disk || is_zbc) {
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002406 len = resp_caching_pg(ap, pcontrol, target);
2407 offset += len;
2408 } else
2409 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 break;
2411 case 0xa: /* Control Mode page, all devices */
2412 len = resp_ctrl_m_pg(ap, pcontrol, target);
2413 offset += len;
2414 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002415 case 0x19: /* if spc==1 then sas phy, control+discover */
2416 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002417 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002418 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002419 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002420 len = 0;
2421 if ((0x0 == subpcode) || (0xff == subpcode))
2422 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2423 if ((0x1 == subpcode) || (0xff == subpcode))
2424 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2425 target_dev_id);
2426 if ((0x2 == subpcode) || (0xff == subpcode))
2427 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2428 offset += len;
2429 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 case 0x1c: /* Informational Exceptions Mode page, all devices */
2431 len = resp_iec_m_pg(ap, pcontrol, target);
2432 offset += len;
2433 break;
2434 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002435 if ((0 == subpcode) || (0xff == subpcode)) {
2436 len = resp_err_recov_pg(ap, pcontrol, target);
2437 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002438 if (is_disk) {
2439 len += resp_format_pg(ap + len, pcontrol,
2440 target);
2441 len += resp_caching_pg(ap + len, pcontrol,
2442 target);
Douglas Gilbertd36da302020-04-22 19:42:15 +09002443 } else if (is_zbc) {
2444 len += resp_caching_pg(ap + len, pcontrol,
2445 target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002446 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002447 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2448 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2449 if (0xff == subpcode) {
2450 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2451 target, target_dev_id);
2452 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2453 }
2454 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002455 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002456 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002457 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002458 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 break;
2461 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002462 bad_pcode = true;
2463 break;
2464 }
2465 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002466 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 return check_condition_result;
2468 }
2469 if (msense_6)
2470 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002471 else
2472 put_unaligned_be16((offset - 2), arr + 0);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002473 return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474}
2475
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002476#define SDEBUG_MAX_MSELECT_SZ 512
2477
Douglas Gilbertfd321192016-04-25 12:16:33 -04002478static int resp_mode_select(struct scsi_cmnd *scp,
2479 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002480{
2481 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002482 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002483 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002484 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002485 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002486
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002487 memset(arr, 0, sizeof(arr));
2488 pf = cmd[1] & 0x10;
2489 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002490 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002491 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002492 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002493 return check_condition_result;
2494 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002495 res = fetch_to_dev_buffer(scp, arr, param_len);
2496 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002497 return DID_ERROR << 16;
2498 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002499 sdev_printk(KERN_INFO, scp->device,
2500 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2501 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002502 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2503 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002504 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002505 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002506 return check_condition_result;
2507 }
2508 off = bd_len + (mselect6 ? 4 : 8);
2509 mpage = arr[off] & 0x3f;
2510 ps = !!(arr[off] & 0x80);
2511 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002512 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002513 return check_condition_result;
2514 }
2515 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002516 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002517 (arr[off + 1] + 2);
2518 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002519 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002520 PARAMETER_LIST_LENGTH_ERR, 0);
2521 return check_condition_result;
2522 }
2523 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002524 case 0x8: /* Caching Mode page */
2525 if (caching_pg[1] == arr[off + 1]) {
2526 memcpy(caching_pg + 2, arr + off + 2,
2527 sizeof(caching_pg) - 2);
2528 goto set_mode_changed_ua;
2529 }
2530 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002531 case 0xa: /* Control Mode page */
2532 if (ctrl_m_pg[1] == arr[off + 1]) {
2533 memcpy(ctrl_m_pg + 2, arr + off + 2,
2534 sizeof(ctrl_m_pg) - 2);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002535 if (ctrl_m_pg[4] & 0x8)
2536 sdebug_wp = true;
2537 else
2538 sdebug_wp = false;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002539 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002540 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002541 }
2542 break;
2543 case 0x1c: /* Informational Exceptions Mode page */
2544 if (iec_m_pg[1] == arr[off + 1]) {
2545 memcpy(iec_m_pg + 2, arr + off + 2,
2546 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002547 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002548 }
2549 break;
2550 default:
2551 break;
2552 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002553 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002554 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002555set_mode_changed_ua:
2556 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2557 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002558}
2559
John Pittman91d4c752018-02-09 21:12:43 -05002560static int resp_temp_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002561{
2562 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2563 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2564 };
2565
Douglas Gilbert9a051012017-12-23 12:48:10 -05002566 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2567 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002568}
2569
John Pittman91d4c752018-02-09 21:12:43 -05002570static int resp_ie_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002571{
2572 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2573 };
2574
Douglas Gilbert9a051012017-12-23 12:48:10 -05002575 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002576 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2577 arr[4] = THRESHOLD_EXCEEDED;
2578 arr[5] = 0xff;
2579 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002580 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002581}
2582
2583#define SDEBUG_MAX_LSENSE_SZ 512
2584
Douglas Gilbert9a051012017-12-23 12:48:10 -05002585static int resp_log_sense(struct scsi_cmnd *scp,
2586 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002587{
Bart Van Asscheab172412017-08-25 13:46:42 -07002588 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002589 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002590 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002591
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002592 memset(arr, 0, sizeof(arr));
2593 ppc = cmd[1] & 0x2;
2594 sp = cmd[1] & 0x1;
2595 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002596 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002597 return check_condition_result;
2598 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002599 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002600 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002601 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002602 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002603 if (0 == subpcode) {
2604 switch (pcode) {
2605 case 0x0: /* Supported log pages log page */
2606 n = 4;
2607 arr[n++] = 0x0; /* this page */
2608 arr[n++] = 0xd; /* Temperature */
2609 arr[n++] = 0x2f; /* Informational exceptions */
2610 arr[3] = n - 4;
2611 break;
2612 case 0xd: /* Temperature log page */
2613 arr[3] = resp_temp_l_pg(arr + 4);
2614 break;
2615 case 0x2f: /* Informational exceptions log page */
2616 arr[3] = resp_ie_l_pg(arr + 4);
2617 break;
2618 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002619 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002620 return check_condition_result;
2621 }
2622 } else if (0xff == subpcode) {
2623 arr[0] |= 0x40;
2624 arr[1] = subpcode;
2625 switch (pcode) {
2626 case 0x0: /* Supported log pages and subpages log page */
2627 n = 4;
2628 arr[n++] = 0x0;
2629 arr[n++] = 0x0; /* 0,0 page */
2630 arr[n++] = 0x0;
2631 arr[n++] = 0xff; /* this page */
2632 arr[n++] = 0xd;
2633 arr[n++] = 0x0; /* Temperature */
2634 arr[n++] = 0x2f;
2635 arr[n++] = 0x0; /* Informational exceptions */
2636 arr[3] = n - 4;
2637 break;
2638 case 0xd: /* Temperature subpages */
2639 n = 4;
2640 arr[n++] = 0xd;
2641 arr[n++] = 0x0; /* Temperature */
2642 arr[3] = n - 4;
2643 break;
2644 case 0x2f: /* Informational exceptions subpages */
2645 n = 4;
2646 arr[n++] = 0x2f;
2647 arr[n++] = 0x0; /* Informational exceptions */
2648 arr[3] = n - 4;
2649 break;
2650 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002651 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002652 return check_condition_result;
2653 }
2654 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002655 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002656 return check_condition_result;
2657 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002658 len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002659 return fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002660 min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002661}
2662
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002663static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664{
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002665 return devip->nr_zones != 0;
2666}
2667
2668static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2669 unsigned long long lba)
2670{
Damien Le Moal108e36f2020-05-07 11:35:26 +09002671 return &devip->zstate[lba >> devip->zsize_shift];
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002672}
2673
2674static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2675{
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002676 return zsp->z_type == ZBC_ZONE_TYPE_CNV;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002677}
2678
2679static void zbc_close_zone(struct sdebug_dev_info *devip,
2680 struct sdeb_zone_state *zsp)
2681{
2682 enum sdebug_z_cond zc;
2683
2684 if (zbc_zone_is_conv(zsp))
2685 return;
2686
2687 zc = zsp->z_cond;
2688 if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2689 return;
2690
2691 if (zc == ZC2_IMPLICIT_OPEN)
2692 devip->nr_imp_open--;
2693 else
2694 devip->nr_exp_open--;
2695
2696 if (zsp->z_wp == zsp->z_start) {
2697 zsp->z_cond = ZC1_EMPTY;
2698 } else {
2699 zsp->z_cond = ZC4_CLOSED;
2700 devip->nr_closed++;
2701 }
2702}
2703
2704static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2705{
2706 struct sdeb_zone_state *zsp = &devip->zstate[0];
2707 unsigned int i;
2708
2709 for (i = 0; i < devip->nr_zones; i++, zsp++) {
2710 if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2711 zbc_close_zone(devip, zsp);
2712 return;
2713 }
2714 }
2715}
2716
2717static void zbc_open_zone(struct sdebug_dev_info *devip,
2718 struct sdeb_zone_state *zsp, bool explicit)
2719{
2720 enum sdebug_z_cond zc;
2721
2722 if (zbc_zone_is_conv(zsp))
2723 return;
2724
2725 zc = zsp->z_cond;
2726 if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2727 (!explicit && zc == ZC2_IMPLICIT_OPEN))
2728 return;
2729
2730 /* Close an implicit open zone if necessary */
2731 if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2732 zbc_close_zone(devip, zsp);
2733 else if (devip->max_open &&
2734 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2735 zbc_close_imp_open_zone(devip);
2736
2737 if (zsp->z_cond == ZC4_CLOSED)
2738 devip->nr_closed--;
2739 if (explicit) {
2740 zsp->z_cond = ZC3_EXPLICIT_OPEN;
2741 devip->nr_exp_open++;
2742 } else {
2743 zsp->z_cond = ZC2_IMPLICIT_OPEN;
2744 devip->nr_imp_open++;
2745 }
2746}
2747
2748static void zbc_inc_wp(struct sdebug_dev_info *devip,
2749 unsigned long long lba, unsigned int num)
2750{
2751 struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002752 unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002753
2754 if (zbc_zone_is_conv(zsp))
2755 return;
2756
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002757 if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2758 zsp->z_wp += num;
2759 if (zsp->z_wp >= zend)
2760 zsp->z_cond = ZC5_FULL;
2761 return;
2762 }
2763
2764 while (num) {
2765 if (lba != zsp->z_wp)
2766 zsp->z_non_seq_resource = true;
2767
2768 end = lba + num;
2769 if (end >= zend) {
2770 n = zend - lba;
2771 zsp->z_wp = zend;
2772 } else if (end > zsp->z_wp) {
2773 n = num;
2774 zsp->z_wp = end;
2775 } else {
2776 n = num;
2777 }
2778 if (zsp->z_wp >= zend)
2779 zsp->z_cond = ZC5_FULL;
2780
2781 num -= n;
2782 lba += n;
2783 if (num) {
2784 zsp++;
2785 zend = zsp->z_start + zsp->z_size;
2786 }
2787 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002788}
2789
2790static int check_zbc_access_params(struct scsi_cmnd *scp,
2791 unsigned long long lba, unsigned int num, bool write)
2792{
2793 struct scsi_device *sdp = scp->device;
2794 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2795 struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2796 struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2797
2798 if (!write) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002799 if (devip->zmodel == BLK_ZONED_HA)
2800 return 0;
2801 /* For host-managed, reads cannot cross zone types boundaries */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002802 if (zsp_end != zsp &&
2803 zbc_zone_is_conv(zsp) &&
2804 !zbc_zone_is_conv(zsp_end)) {
2805 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2806 LBA_OUT_OF_RANGE,
2807 READ_INVDATA_ASCQ);
2808 return check_condition_result;
2809 }
2810 return 0;
2811 }
2812
2813 /* No restrictions for writes within conventional zones */
2814 if (zbc_zone_is_conv(zsp)) {
2815 if (!zbc_zone_is_conv(zsp_end)) {
2816 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2817 LBA_OUT_OF_RANGE,
2818 WRITE_BOUNDARY_ASCQ);
2819 return check_condition_result;
2820 }
2821 return 0;
2822 }
2823
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002824 if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2825 /* Writes cannot cross sequential zone boundaries */
2826 if (zsp_end != zsp) {
2827 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2828 LBA_OUT_OF_RANGE,
2829 WRITE_BOUNDARY_ASCQ);
2830 return check_condition_result;
2831 }
2832 /* Cannot write full zones */
2833 if (zsp->z_cond == ZC5_FULL) {
2834 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2835 INVALID_FIELD_IN_CDB, 0);
2836 return check_condition_result;
2837 }
2838 /* Writes must be aligned to the zone WP */
2839 if (lba != zsp->z_wp) {
2840 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2841 LBA_OUT_OF_RANGE,
2842 UNALIGNED_WRITE_ASCQ);
2843 return check_condition_result;
2844 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002845 }
2846
2847 /* Handle implicit open of closed and empty zones */
2848 if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2849 if (devip->max_open &&
2850 devip->nr_exp_open >= devip->max_open) {
2851 mk_sense_buffer(scp, DATA_PROTECT,
2852 INSUFF_RES_ASC,
2853 INSUFF_ZONE_ASCQ);
2854 return check_condition_result;
2855 }
2856 zbc_open_zone(devip, zsp, false);
2857 }
2858
2859 return 0;
2860}
2861
2862static inline int check_device_access_params
2863 (struct scsi_cmnd *scp, unsigned long long lba,
2864 unsigned int num, bool write)
2865{
2866 struct scsi_device *sdp = scp->device;
2867 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2868
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002869 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002870 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 return check_condition_result;
2872 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002873 /* transfer length excessive (tie in to block limits VPD page) */
2874 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002875 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002876 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002877 return check_condition_result;
2878 }
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002879 if (write && unlikely(sdebug_wp)) {
2880 mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
2881 return check_condition_result;
2882 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002883 if (sdebug_dev_is_zoned(devip))
2884 return check_zbc_access_params(scp, lba, num, write);
2885
FUJITA Tomonori19789102008-03-30 00:59:56 +09002886 return 0;
2887}
2888
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04002889/*
2890 * Note: if BUG_ON() fires it usually indicates a problem with the parser
2891 * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2892 * that access any of the "stores" in struct sdeb_store_info should call this
2893 * function with bug_if_fake_rw set to true.
2894 */
2895static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2896 bool bug_if_fake_rw)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002897{
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04002898 if (sdebug_fake_rw) {
2899 BUG_ON(bug_if_fake_rw); /* See note above */
2900 return NULL;
2901 }
2902 return xa_load(per_store_ap, devip->sdbg_host->si_idx);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002903}
2904
Akinobu Mitaa4517512013-07-08 16:01:57 -07002905/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002906static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
2907 u32 sg_skip, u64 lba, u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002908{
2909 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002910 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002911 enum dma_data_direction dir;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002912 struct scsi_data_buffer *sdb = &scp->sdb;
2913 u8 *fsp;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002914
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002915 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002916 dir = DMA_TO_DEVICE;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04002917 write_since_sync = true;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002918 } else {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002919 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002920 }
2921
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002922 if (!sdb->length || !sip)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002923 return 0;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002924 if (scp->sc_data_direction != dir)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002925 return -1;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002926 fsp = sip->storep;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002927
2928 block = do_div(lba, sdebug_store_sectors);
2929 if (block + num > sdebug_store_sectors)
2930 rest = block + num - sdebug_store_sectors;
2931
Dave Gordon386ecb12015-06-30 14:58:57 -07002932 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002933 fsp + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002934 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002935 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002936 return ret;
2937
2938 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002939 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002940 fsp, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002941 sg_skip + ((num - rest) * sdebug_sector_size),
2942 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002943 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002944
2945 return ret;
2946}
2947
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002948/* Returns number of bytes copied or -1 if error. */
2949static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
2950{
2951 struct scsi_data_buffer *sdb = &scp->sdb;
2952
2953 if (!sdb->length)
2954 return 0;
2955 if (scp->sc_data_direction != DMA_TO_DEVICE)
2956 return -1;
2957 return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
2958 num * sdebug_sector_size, 0, true);
2959}
2960
2961/* If sip->storep+lba compares equal to arr(num), then copy top half of
2962 * arr into sip->storep+lba and return true. If comparison fails then
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002963 * return false. */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002964static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04002965 const u8 *arr, bool compare_only)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002966{
2967 bool res;
2968 u64 block, rest = 0;
2969 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002970 u32 lb_size = sdebug_sector_size;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002971 u8 *fsp = sip->storep;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002972
2973 block = do_div(lba, store_blks);
2974 if (block + num > store_blks)
2975 rest = block + num - store_blks;
2976
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002977 res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002978 if (!res)
2979 return res;
2980 if (rest)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002981 res = memcmp(fsp, arr + ((num - rest) * lb_size),
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002982 rest * lb_size);
2983 if (!res)
2984 return res;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04002985 if (compare_only)
2986 return true;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002987 arr += num * lb_size;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002988 memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002989 if (rest)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002990 memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002991 return res;
2992}
2993
Akinobu Mita51d648a2013-09-18 21:27:28 +09002994static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002995{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002996 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002997
Douglas Gilbert773642d2016-04-25 12:16:28 -04002998 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002999 csum = (__force __be16)ip_compute_csum(buf, len);
3000 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003001 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09003002
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003003 return csum;
3004}
3005
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003006static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003007 sector_t sector, u32 ei_lba)
3008{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003009 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003010
3011 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003012 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003013 (unsigned long)sector,
3014 be16_to_cpu(sdt->guard_tag),
3015 be16_to_cpu(csum));
3016 return 0x01;
3017 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003018 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003019 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003020 pr_err("REF check failed on sector %lu\n",
3021 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003022 return 0x03;
3023 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003024 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003025 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003026 pr_err("REF check failed on sector %lu\n",
3027 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003028 return 0x03;
3029 }
3030 return 0;
3031}
3032
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003033static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003034 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003035{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003036 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003037 void *paddr;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003038 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003039 scp->device->hostdata, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003040 struct t10_pi_tuple *dif_storep = sip->dif_storep;
Akinobu Mita14faa942013-09-18 21:27:24 +09003041 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003042 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003043
Akinobu Mitae18d8be2013-06-29 17:59:18 +09003044 /* Bytes of protection data to copy into sgl */
3045 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003046
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003047 sg_miter_start(&miter, scsi_prot_sglist(scp),
3048 scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3049 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003050
3051 while (sg_miter_next(&miter) && resid > 0) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003052 size_t len = min_t(size_t, miter.length, resid);
3053 void *start = dif_store(sip, sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003054 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09003055
3056 if (dif_store_end < start + len)
3057 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003058
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003059 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09003060
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003061 if (read)
3062 memcpy(paddr, start, len - rest);
3063 else
3064 memcpy(start, paddr, len - rest);
3065
3066 if (rest) {
3067 if (read)
3068 memcpy(paddr + len - rest, dif_storep, rest);
3069 else
3070 memcpy(dif_storep, paddr + len - rest, rest);
3071 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003072
Akinobu Mitae18d8be2013-06-29 17:59:18 +09003073 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003074 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003075 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003076 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003077}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003078
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003079static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003080 unsigned int sectors, u32 ei_lba)
3081{
3082 unsigned int i;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003083 sector_t sector;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003084 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003085 scp->device->hostdata, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003086 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003087
Akinobu Mitac45eabec2014-02-26 22:56:58 +09003088 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003089 int ret;
3090
3091 sector = start_sec + i;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003092 sdt = dif_store(sip, sector);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003093
Akinobu Mita51d648a2013-09-18 21:27:28 +09003094 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003095 continue;
3096
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003097 ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
3098 ei_lba);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003099 if (ret) {
3100 dif_errors++;
3101 return ret;
3102 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003103 }
3104
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003105 dif_copy_prot(scp, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003106 dix_reads++;
3107
3108 return 0;
3109}
3110
Douglas Gilbertfd321192016-04-25 12:16:33 -04003111static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09003112{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003113 bool check_prot;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003114 u32 num;
3115 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003116 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003117 u64 lba;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003118 struct sdeb_store_info *sip = devip2sip(devip, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003119 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3120 u8 *cmd = scp->cmnd;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003121
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003122 switch (cmd[0]) {
3123 case READ_16:
3124 ei_lba = 0;
3125 lba = get_unaligned_be64(cmd + 2);
3126 num = get_unaligned_be32(cmd + 10);
3127 check_prot = true;
3128 break;
3129 case READ_10:
3130 ei_lba = 0;
3131 lba = get_unaligned_be32(cmd + 2);
3132 num = get_unaligned_be16(cmd + 7);
3133 check_prot = true;
3134 break;
3135 case READ_6:
3136 ei_lba = 0;
3137 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3138 (u32)(cmd[1] & 0x1f) << 16;
3139 num = (0 == cmd[4]) ? 256 : cmd[4];
3140 check_prot = true;
3141 break;
3142 case READ_12:
3143 ei_lba = 0;
3144 lba = get_unaligned_be32(cmd + 2);
3145 num = get_unaligned_be32(cmd + 6);
3146 check_prot = true;
3147 break;
3148 case XDWRITEREAD_10:
3149 ei_lba = 0;
3150 lba = get_unaligned_be32(cmd + 2);
3151 num = get_unaligned_be16(cmd + 7);
3152 check_prot = false;
3153 break;
3154 default: /* assume READ(32) */
3155 lba = get_unaligned_be64(cmd + 12);
3156 ei_lba = get_unaligned_be32(cmd + 20);
3157 num = get_unaligned_be32(cmd + 28);
3158 check_prot = false;
3159 break;
3160 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003161 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003162 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003163 (cmd[1] & 0xe0)) {
3164 mk_sense_invalid_opcode(scp);
3165 return check_condition_result;
3166 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003167 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3168 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003169 (cmd[1] & 0xe0) == 0)
3170 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3171 "to DIF device\n");
3172 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003173 if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
3174 atomic_read(&sdeb_inject_pending))) {
3175 num /= 2;
3176 atomic_set(&sdeb_inject_pending, 0);
3177 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003178
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003179 ret = check_device_access_params(scp, lba, num, false);
3180 if (ret)
3181 return ret;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003182 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05003183 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3184 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003185 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003186 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003187 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003188 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3189 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05003190 ret = (lba < OPT_MEDIUM_ERR_ADDR)
3191 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003192 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003193 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003194 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 return check_condition_result;
3196 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003197
Douglas Gilbert67da4132020-04-21 11:14:20 -04003198 read_lock(macc_lckp);
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003199
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003200 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003201 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003202 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003203
3204 if (prot_ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003205 read_unlock(macc_lckp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003206 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003207 return illegal_condition_result;
3208 }
3209 }
3210
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003211 ret = do_device_access(sip, scp, 0, lba, num, false);
Douglas Gilbert67da4132020-04-21 11:14:20 -04003212 read_unlock(macc_lckp);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003213 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07003214 return DID_ERROR << 16;
3215
Bart Van Assche42d387b2019-02-08 13:25:00 -08003216 scsi_set_resid(scp, scsi_bufflen(scp) - ret);
Akinobu Mitaa4517512013-07-08 16:01:57 -07003217
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003218 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3219 atomic_read(&sdeb_inject_pending))) {
3220 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3221 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3222 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003223 return check_condition_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003224 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003225 /* Logical block guard check failed */
3226 mk_sense_buffer(scp, ABORTED_COMMAND, 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;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003229 } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003230 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003231 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003232 return illegal_condition_result;
3233 }
3234 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07003235 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236}
3237
Tomas Winkler58a86352015-07-28 16:54:23 +03003238static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003239{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003240 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003241
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003242 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003243 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003244 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003245
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003246 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003247 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003248
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003249 if (c >= 0x20 && c < 0x7e)
3250 n += scnprintf(b + n, sizeof(b) - n,
3251 " %c ", buf[i+j]);
3252 else
3253 n += scnprintf(b + n, sizeof(b) - n,
3254 "%02x ", buf[i+j]);
3255 }
3256 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003257 }
3258}
3259
3260static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04003261 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003262{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003263 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003264 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003265 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003266 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003267 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003268 int dpage_offset;
3269 struct sg_mapping_iter diter;
3270 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003271
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003272 BUG_ON(scsi_sg_count(SCpnt) == 0);
3273 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3274
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003275 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3276 scsi_prot_sg_count(SCpnt),
3277 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3278 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3279 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003280
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003281 /* For each protection page */
3282 while (sg_miter_next(&piter)) {
3283 dpage_offset = 0;
3284 if (WARN_ON(!sg_miter_next(&diter))) {
3285 ret = 0x01;
3286 goto out;
3287 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003288
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003289 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003290 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003291 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003292 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003293 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003294 if (dpage_offset >= diter.length) {
3295 if (WARN_ON(!sg_miter_next(&diter))) {
3296 ret = 0x01;
3297 goto out;
3298 }
3299 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003300 }
3301
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003302 sdt = piter.addr + ppage_offset;
3303 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003304
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003305 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003306 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003307 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04003308 goto out;
3309 }
3310
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003311 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003312 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003313 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003314 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003315 diter.consumed = dpage_offset;
3316 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003317 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003318 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003319
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003320 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003321 dix_writes++;
3322
3323 return 0;
3324
3325out:
3326 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003327 sg_miter_stop(&diter);
3328 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003329 return ret;
3330}
3331
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003332static unsigned long lba_to_map_index(sector_t lba)
3333{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003334 if (sdebug_unmap_alignment)
3335 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3336 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003337 return lba;
3338}
3339
3340static sector_t map_index_to_lba(unsigned long index)
3341{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003342 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09003343
Douglas Gilbert773642d2016-04-25 12:16:28 -04003344 if (sdebug_unmap_alignment)
3345 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09003346 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003347}
3348
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003349static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
3350 unsigned int *num)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003351{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003352 sector_t end;
3353 unsigned int mapped;
3354 unsigned long index;
3355 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003356
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003357 index = lba_to_map_index(lba);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003358 mapped = test_bit(index, sip->map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003359
3360 if (mapped)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003361 next = find_next_zero_bit(sip->map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003362 else
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003363 next = find_next_bit(sip->map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003364
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003365 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003366 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003367 return mapped;
3368}
3369
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003370static void map_region(struct sdeb_store_info *sip, sector_t lba,
3371 unsigned int len)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003372{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003373 sector_t end = lba + len;
3374
Martin K. Petersen44d92692009-10-15 14:45:27 -04003375 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003376 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003377
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003378 if (index < map_size)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003379 set_bit(index, sip->map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003380
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003381 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003382 }
3383}
3384
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003385static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
3386 unsigned int len)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003387{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003388 sector_t end = lba + len;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003389 u8 *fsp = sip->storep;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003390
Martin K. Petersen44d92692009-10-15 14:45:27 -04003391 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003392 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003393
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003394 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04003395 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003396 index < map_size) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003397 clear_bit(index, sip->map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04003398 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003399 memset(fsp + lba * sdebug_sector_size,
Douglas Gilbert760f3b02016-05-06 00:40:27 -04003400 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04003401 sdebug_sector_size *
3402 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003403 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003404 if (sip->dif_storep) {
3405 memset(sip->dif_storep + lba, 0xff,
3406 sizeof(*sip->dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04003407 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09003408 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003409 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003410 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003411 }
3412}
3413
Douglas Gilbertfd321192016-04-25 12:16:33 -04003414static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003416 bool check_prot;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003417 u32 num;
3418 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003419 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003420 u64 lba;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003421 struct sdeb_store_info *sip = devip2sip(devip, true);
3422 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003423 u8 *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003425 switch (cmd[0]) {
3426 case WRITE_16:
3427 ei_lba = 0;
3428 lba = get_unaligned_be64(cmd + 2);
3429 num = get_unaligned_be32(cmd + 10);
3430 check_prot = true;
3431 break;
3432 case WRITE_10:
3433 ei_lba = 0;
3434 lba = get_unaligned_be32(cmd + 2);
3435 num = get_unaligned_be16(cmd + 7);
3436 check_prot = true;
3437 break;
3438 case WRITE_6:
3439 ei_lba = 0;
3440 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3441 (u32)(cmd[1] & 0x1f) << 16;
3442 num = (0 == cmd[4]) ? 256 : cmd[4];
3443 check_prot = true;
3444 break;
3445 case WRITE_12:
3446 ei_lba = 0;
3447 lba = get_unaligned_be32(cmd + 2);
3448 num = get_unaligned_be32(cmd + 6);
3449 check_prot = true;
3450 break;
3451 case 0x53: /* XDWRITEREAD(10) */
3452 ei_lba = 0;
3453 lba = get_unaligned_be32(cmd + 2);
3454 num = get_unaligned_be16(cmd + 7);
3455 check_prot = false;
3456 break;
3457 default: /* assume WRITE(32) */
3458 lba = get_unaligned_be64(cmd + 12);
3459 ei_lba = get_unaligned_be32(cmd + 20);
3460 num = get_unaligned_be32(cmd + 28);
3461 check_prot = false;
3462 break;
3463 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003464 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003465 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003466 (cmd[1] & 0xe0)) {
3467 mk_sense_invalid_opcode(scp);
3468 return check_condition_result;
3469 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003470 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3471 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003472 (cmd[1] & 0xe0) == 0)
3473 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3474 "to DIF device\n");
3475 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003476
Douglas Gilbert67da4132020-04-21 11:14:20 -04003477 write_lock(macc_lckp);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003478 ret = check_device_access_params(scp, lba, num, true);
3479 if (ret) {
3480 write_unlock(macc_lckp);
3481 return ret;
3482 }
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003483
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003484 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003485 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003486 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003487
3488 if (prot_ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003489 write_unlock(macc_lckp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003490 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003491 return illegal_condition_result;
3492 }
3493 }
3494
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003495 ret = do_device_access(sip, scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003496 if (unlikely(scsi_debug_lbp()))
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003497 map_region(sip, lba, num);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003498 /* If ZBC zone then bump its write pointer */
3499 if (sdebug_dev_is_zoned(devip))
3500 zbc_inc_wp(devip, lba, num);
Douglas Gilbert67da4132020-04-21 11:14:20 -04003501 write_unlock(macc_lckp);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003502 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003503 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003504 else if (unlikely(sdebug_verbose &&
3505 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003506 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003507 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003508 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003509
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003510 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3511 atomic_read(&sdeb_inject_pending))) {
3512 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3513 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3514 atomic_set(&sdeb_inject_pending, 0);
3515 return check_condition_result;
3516 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3517 /* Logical block guard check failed */
3518 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3519 atomic_set(&sdeb_inject_pending, 0);
3520 return illegal_condition_result;
3521 } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3522 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3523 atomic_set(&sdeb_inject_pending, 0);
3524 return illegal_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003525 }
3526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 return 0;
3528}
3529
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003530/*
3531 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3532 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3533 */
3534static int resp_write_scat(struct scsi_cmnd *scp,
3535 struct sdebug_dev_info *devip)
3536{
3537 u8 *cmd = scp->cmnd;
3538 u8 *lrdp = NULL;
3539 u8 *up;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003540 struct sdeb_store_info *sip = devip2sip(devip, true);
3541 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003542 u8 wrprotect;
3543 u16 lbdof, num_lrd, k;
3544 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3545 u32 lb_size = sdebug_sector_size;
3546 u32 ei_lba;
3547 u64 lba;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003548 int ret, res;
3549 bool is_16;
3550 static const u32 lrd_size = 32; /* + parameter list header size */
3551
3552 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3553 is_16 = false;
3554 wrprotect = (cmd[10] >> 5) & 0x7;
3555 lbdof = get_unaligned_be16(cmd + 12);
3556 num_lrd = get_unaligned_be16(cmd + 16);
3557 bt_len = get_unaligned_be32(cmd + 28);
3558 } else { /* that leaves WRITE SCATTERED(16) */
3559 is_16 = true;
3560 wrprotect = (cmd[2] >> 5) & 0x7;
3561 lbdof = get_unaligned_be16(cmd + 4);
3562 num_lrd = get_unaligned_be16(cmd + 8);
3563 bt_len = get_unaligned_be32(cmd + 10);
3564 if (unlikely(have_dif_prot)) {
3565 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3566 wrprotect) {
3567 mk_sense_invalid_opcode(scp);
3568 return illegal_condition_result;
3569 }
3570 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3571 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3572 wrprotect == 0)
3573 sdev_printk(KERN_ERR, scp->device,
3574 "Unprotected WR to DIF device\n");
3575 }
3576 }
3577 if ((num_lrd == 0) || (bt_len == 0))
3578 return 0; /* T10 says these do-nothings are not errors */
3579 if (lbdof == 0) {
3580 if (sdebug_verbose)
3581 sdev_printk(KERN_INFO, scp->device,
3582 "%s: %s: LB Data Offset field bad\n",
3583 my_name, __func__);
3584 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3585 return illegal_condition_result;
3586 }
3587 lbdof_blen = lbdof * lb_size;
3588 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3589 if (sdebug_verbose)
3590 sdev_printk(KERN_INFO, scp->device,
3591 "%s: %s: LBA range descriptors don't fit\n",
3592 my_name, __func__);
3593 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3594 return illegal_condition_result;
3595 }
3596 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3597 if (lrdp == NULL)
3598 return SCSI_MLQUEUE_HOST_BUSY;
3599 if (sdebug_verbose)
3600 sdev_printk(KERN_INFO, scp->device,
3601 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3602 my_name, __func__, lbdof_blen);
3603 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3604 if (res == -1) {
3605 ret = DID_ERROR << 16;
3606 goto err_out;
3607 }
3608
Douglas Gilbert67da4132020-04-21 11:14:20 -04003609 write_lock(macc_lckp);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003610 sg_off = lbdof_blen;
3611 /* Spec says Buffer xfer Length field in number of LBs in dout */
3612 cum_lb = 0;
3613 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3614 lba = get_unaligned_be64(up + 0);
3615 num = get_unaligned_be32(up + 8);
3616 if (sdebug_verbose)
3617 sdev_printk(KERN_INFO, scp->device,
3618 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3619 my_name, __func__, k, lba, num, sg_off);
3620 if (num == 0)
3621 continue;
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003622 ret = check_device_access_params(scp, lba, num, true);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003623 if (ret)
3624 goto err_out_unlock;
3625 num_by = num * lb_size;
3626 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3627
3628 if ((cum_lb + num) > bt_len) {
3629 if (sdebug_verbose)
3630 sdev_printk(KERN_INFO, scp->device,
3631 "%s: %s: sum of blocks > data provided\n",
3632 my_name, __func__);
3633 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3634 0);
3635 ret = illegal_condition_result;
3636 goto err_out_unlock;
3637 }
3638
3639 /* DIX + T10 DIF */
3640 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3641 int prot_ret = prot_verify_write(scp, lba, num,
3642 ei_lba);
3643
3644 if (prot_ret) {
3645 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3646 prot_ret);
3647 ret = illegal_condition_result;
3648 goto err_out_unlock;
3649 }
3650 }
3651
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003652 ret = do_device_access(sip, scp, sg_off, lba, num, true);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003653 /* If ZBC zone then bump its write pointer */
3654 if (sdebug_dev_is_zoned(devip))
3655 zbc_inc_wp(devip, lba, num);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003656 if (unlikely(scsi_debug_lbp()))
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003657 map_region(sip, lba, num);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003658 if (unlikely(-1 == ret)) {
3659 ret = DID_ERROR << 16;
3660 goto err_out_unlock;
3661 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3662 sdev_printk(KERN_INFO, scp->device,
3663 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3664 my_name, num_by, ret);
3665
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003666 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3667 atomic_read(&sdeb_inject_pending))) {
3668 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3669 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3670 atomic_set(&sdeb_inject_pending, 0);
3671 ret = check_condition_result;
3672 goto err_out_unlock;
3673 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3674 /* Logical block guard check failed */
3675 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3676 atomic_set(&sdeb_inject_pending, 0);
3677 ret = illegal_condition_result;
3678 goto err_out_unlock;
3679 } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3680 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3681 atomic_set(&sdeb_inject_pending, 0);
3682 ret = illegal_condition_result;
3683 goto err_out_unlock;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003684 }
3685 }
3686 sg_off += num_by;
3687 cum_lb += num;
3688 }
3689 ret = 0;
3690err_out_unlock:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003691 write_unlock(macc_lckp);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003692err_out:
3693 kfree(lrdp);
3694 return ret;
3695}
3696
Douglas Gilbertfd321192016-04-25 12:16:33 -04003697static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3698 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003699{
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003700 struct scsi_device *sdp = scp->device;
3701 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003702 unsigned long long i;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003703 u64 block, lbaa;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003704 u32 lb_size = sdebug_sector_size;
3705 int ret;
3706 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003707 scp->device->hostdata, true);
3708 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003709 u8 *fs1p;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003710 u8 *fsp;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003711
Douglas Gilbert67da4132020-04-21 11:14:20 -04003712 write_lock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003713
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003714 ret = check_device_access_params(scp, lba, num, true);
3715 if (ret) {
3716 write_unlock(macc_lckp);
3717 return ret;
3718 }
3719
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003720 if (unmap && scsi_debug_lbp()) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003721 unmap_region(sip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003722 goto out;
3723 }
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003724 lbaa = lba;
3725 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003726 /* if ndob then zero 1 logical block, else fetch 1 logical block */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003727 fsp = sip->storep;
3728 fs1p = fsp + (block * lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003729 if (ndob) {
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003730 memset(fs1p, 0, lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003731 ret = 0;
3732 } else
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003733 ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003734
3735 if (-1 == ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003736 write_unlock(&sip->macc_lck);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003737 return DID_ERROR << 16;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003738 } else if (sdebug_verbose && !ndob && (ret < lb_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003739 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003740 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003741 my_name, "write same", lb_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003742
3743 /* Copy first sector to remaining blocks */
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003744 for (i = 1 ; i < num ; i++) {
3745 lbaa = lba + i;
3746 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003747 memmove(fsp + (block * lb_size), fs1p, lb_size);
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003748 }
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003749 if (scsi_debug_lbp())
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003750 map_region(sip, lba, num);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003751 /* If ZBC zone then bump its write pointer */
3752 if (sdebug_dev_is_zoned(devip))
3753 zbc_inc_wp(devip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003754out:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003755 write_unlock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003756
3757 return 0;
3758}
3759
Douglas Gilbertfd321192016-04-25 12:16:33 -04003760static int resp_write_same_10(struct scsi_cmnd *scp,
3761 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003762{
3763 u8 *cmd = scp->cmnd;
3764 u32 lba;
3765 u16 num;
3766 u32 ei_lba = 0;
3767 bool unmap = false;
3768
3769 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003770 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003771 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3772 return check_condition_result;
3773 } else
3774 unmap = true;
3775 }
3776 lba = get_unaligned_be32(cmd + 2);
3777 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003778 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003779 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3780 return check_condition_result;
3781 }
3782 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3783}
3784
Douglas Gilbertfd321192016-04-25 12:16:33 -04003785static int resp_write_same_16(struct scsi_cmnd *scp,
3786 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003787{
3788 u8 *cmd = scp->cmnd;
3789 u64 lba;
3790 u32 num;
3791 u32 ei_lba = 0;
3792 bool unmap = false;
3793 bool ndob = false;
3794
3795 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003796 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003797 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3798 return check_condition_result;
3799 } else
3800 unmap = true;
3801 }
3802 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3803 ndob = true;
3804 lba = get_unaligned_be64(cmd + 2);
3805 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003806 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003807 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3808 return check_condition_result;
3809 }
3810 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3811}
3812
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003813/* Note the mode field is in the same position as the (lower) service action
3814 * field. For the Report supported operation codes command, SPC-4 suggests
3815 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003816static int resp_write_buffer(struct scsi_cmnd *scp,
3817 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003818{
3819 u8 *cmd = scp->cmnd;
3820 struct scsi_device *sdp = scp->device;
3821 struct sdebug_dev_info *dp;
3822 u8 mode;
3823
3824 mode = cmd[1] & 0x1f;
3825 switch (mode) {
3826 case 0x4: /* download microcode (MC) and activate (ACT) */
3827 /* set UAs on this device only */
3828 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3829 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3830 break;
3831 case 0x5: /* download MC, save and ACT */
3832 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3833 break;
3834 case 0x6: /* download MC with offsets and ACT */
3835 /* set UAs on most devices (LUs) in this target */
3836 list_for_each_entry(dp,
3837 &devip->sdbg_host->dev_info_list,
3838 dev_list)
3839 if (dp->target == sdp->id) {
3840 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3841 if (devip != dp)
3842 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3843 dp->uas_bm);
3844 }
3845 break;
3846 case 0x7: /* download MC with offsets, save, and ACT */
3847 /* set UA on all devices (LUs) in this target */
3848 list_for_each_entry(dp,
3849 &devip->sdbg_host->dev_info_list,
3850 dev_list)
3851 if (dp->target == sdp->id)
3852 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3853 dp->uas_bm);
3854 break;
3855 default:
3856 /* do nothing for this command for other mode values */
3857 break;
3858 }
3859 return 0;
3860}
3861
Douglas Gilbertfd321192016-04-25 12:16:33 -04003862static int resp_comp_write(struct scsi_cmnd *scp,
3863 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003864{
3865 u8 *cmd = scp->cmnd;
3866 u8 *arr;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003867 struct sdeb_store_info *sip = devip2sip(devip, true);
3868 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003869 u64 lba;
3870 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003871 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003872 u8 num;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003873 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003874 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003875
Douglas Gilbertd467d312014-11-26 12:33:48 -05003876 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003877 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3878 if (0 == num)
3879 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003880 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003881 (cmd[1] & 0xe0)) {
3882 mk_sense_invalid_opcode(scp);
3883 return check_condition_result;
3884 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003885 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3886 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003887 (cmd[1] & 0xe0) == 0)
3888 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3889 "to DIF device\n");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003890 ret = check_device_access_params(scp, lba, num, false);
3891 if (ret)
3892 return ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003893 dnum = 2 * num;
Kees Cook6396bb22018-06-12 14:03:40 -07003894 arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003895 if (NULL == arr) {
3896 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3897 INSUFF_RES_ASCQ);
3898 return check_condition_result;
3899 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003900
Douglas Gilbert67da4132020-04-21 11:14:20 -04003901 write_lock(macc_lckp);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003902
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003903 ret = do_dout_fetch(scp, dnum, arr);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003904 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003905 retval = DID_ERROR << 16;
3906 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003907 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003908 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3909 "indicated=%u, IO sent=%d bytes\n", my_name,
3910 dnum * lb_size, ret);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04003911 if (!comp_write_worker(sip, lba, num, arr, false)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003912 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003913 retval = check_condition_result;
3914 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003915 }
3916 if (scsi_debug_lbp())
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003917 map_region(sip, lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003918cleanup:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003919 write_unlock(macc_lckp);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003920 kfree(arr);
3921 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003922}
3923
Martin K. Petersen44d92692009-10-15 14:45:27 -04003924struct unmap_block_desc {
3925 __be64 lba;
3926 __be32 blocks;
3927 __be32 __reserved;
3928};
3929
Douglas Gilbertfd321192016-04-25 12:16:33 -04003930static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003931{
3932 unsigned char *buf;
3933 struct unmap_block_desc *desc;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003934 struct sdeb_store_info *sip = devip2sip(devip, true);
3935 rwlock_t *macc_lckp = &sip->macc_lck;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003936 unsigned int i, payload_len, descriptors;
3937 int ret;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003938
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003939 if (!scsi_debug_lbp())
3940 return 0; /* fib and say its done */
3941 payload_len = get_unaligned_be16(scp->cmnd + 7);
3942 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003943
3944 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003945 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003946 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003947 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003948 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003949
Douglas Gilbertb333a812016-04-25 12:16:30 -04003950 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003951 if (!buf) {
3952 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3953 INSUFF_RES_ASCQ);
3954 return check_condition_result;
3955 }
3956
3957 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003958
3959 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3960 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3961
3962 desc = (void *)&buf[8];
3963
Douglas Gilbert67da4132020-04-21 11:14:20 -04003964 write_lock(macc_lckp);
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003965
Martin K. Petersen44d92692009-10-15 14:45:27 -04003966 for (i = 0 ; i < descriptors ; i++) {
3967 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3968 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3969
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003970 ret = check_device_access_params(scp, lba, num, true);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003971 if (ret)
3972 goto out;
3973
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003974 unmap_region(sip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003975 }
3976
3977 ret = 0;
3978
3979out:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003980 write_unlock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003981 kfree(buf);
3982
3983 return ret;
3984}
3985
3986#define SDEBUG_GET_LBA_STATUS_LEN 32
3987
Douglas Gilbertfd321192016-04-25 12:16:33 -04003988static int resp_get_lba_status(struct scsi_cmnd *scp,
3989 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003990{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003991 u8 *cmd = scp->cmnd;
3992 u64 lba;
3993 u32 alloc_len, mapped, num;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003994 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003995 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003996
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003997 lba = get_unaligned_be64(cmd + 2);
3998 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003999
4000 if (alloc_len < 24)
4001 return 0;
4002
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05004003 ret = check_device_access_params(scp, lba, 1, false);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004004 if (ret)
4005 return ret;
4006
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004007 if (scsi_debug_lbp()) {
4008 struct sdeb_store_info *sip = devip2sip(devip, true);
4009
Douglas Gilbert87c715d2020-04-21 11:14:18 -04004010 mapped = map_state(sip, lba, &num);
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004011 } else {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004012 mapped = 1;
4013 /* following just in case virtual_gb changed */
4014 sdebug_capacity = get_sdebug_capacity();
4015 if (sdebug_capacity - lba <= 0xffffffff)
4016 num = sdebug_capacity - lba;
4017 else
4018 num = 0xffffffff;
4019 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04004020
4021 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004022 put_unaligned_be32(20, arr); /* Parameter Data Length */
4023 put_unaligned_be64(lba, arr + 8); /* LBA */
4024 put_unaligned_be32(num, arr + 16); /* Number of blocks */
4025 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04004026
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004027 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004028}
4029
Douglas Gilbert80c49562018-02-09 21:36:39 -05004030static int resp_sync_cache(struct scsi_cmnd *scp,
4031 struct sdebug_dev_info *devip)
4032{
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04004033 int res = 0;
Douglas Gilbert80c49562018-02-09 21:36:39 -05004034 u64 lba;
4035 u32 num_blocks;
4036 u8 *cmd = scp->cmnd;
4037
4038 if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
4039 lba = get_unaligned_be32(cmd + 2);
4040 num_blocks = get_unaligned_be16(cmd + 7);
4041 } else { /* SYNCHRONIZE_CACHE(16) */
4042 lba = get_unaligned_be64(cmd + 2);
4043 num_blocks = get_unaligned_be32(cmd + 10);
4044 }
4045 if (lba + num_blocks > sdebug_capacity) {
4046 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4047 return check_condition_result;
4048 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04004049 if (!write_since_sync || (cmd[1] & 0x2))
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04004050 res = SDEG_RES_IMMED_MASK;
4051 else /* delay if write_since_sync and IMMED clear */
4052 write_since_sync = false;
4053 return res;
Douglas Gilbert80c49562018-02-09 21:36:39 -05004054}
4055
Douglas Gilberted9f3e22020-04-21 11:14:22 -04004056/*
4057 * Assuming the LBA+num_blocks is not out-of-range, this function will return
4058 * CONDITION MET if the specified blocks will/have fitted in the cache, and
4059 * a GOOD status otherwise. Model a disk with a big cache and yield
4060 * CONDITION MET. Actually tries to bring range in main memory into the
4061 * cache associated with the CPU(s).
4062 */
4063static int resp_pre_fetch(struct scsi_cmnd *scp,
4064 struct sdebug_dev_info *devip)
4065{
4066 int res = 0;
4067 u64 lba;
4068 u64 block, rest = 0;
4069 u32 nblks;
4070 u8 *cmd = scp->cmnd;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004071 struct sdeb_store_info *sip = devip2sip(devip, true);
4072 rwlock_t *macc_lckp = &sip->macc_lck;
4073 u8 *fsp = sip->storep;
Douglas Gilberted9f3e22020-04-21 11:14:22 -04004074
4075 if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */
4076 lba = get_unaligned_be32(cmd + 2);
4077 nblks = get_unaligned_be16(cmd + 7);
4078 } else { /* PRE-FETCH(16) */
4079 lba = get_unaligned_be64(cmd + 2);
4080 nblks = get_unaligned_be32(cmd + 10);
4081 }
4082 if (lba + nblks > sdebug_capacity) {
4083 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4084 return check_condition_result;
4085 }
4086 if (!fsp)
4087 goto fini;
4088 /* PRE-FETCH spec says nothing about LBP or PI so skip them */
4089 block = do_div(lba, sdebug_store_sectors);
4090 if (block + nblks > sdebug_store_sectors)
4091 rest = block + nblks - sdebug_store_sectors;
4092
4093 /* Try to bring the PRE-FETCH range into CPU's cache */
4094 read_lock(macc_lckp);
4095 prefetch_range(fsp + (sdebug_sector_size * block),
4096 (nblks - rest) * sdebug_sector_size);
4097 if (rest)
4098 prefetch_range(fsp, rest * sdebug_sector_size);
4099 read_unlock(macc_lckp);
4100fini:
4101 if (cmd[1] & 0x2)
4102 res = SDEG_RES_IMMED_MASK;
4103 return res | condition_met_result;
4104}
4105
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004106#define RL_BUCKET_ELEMS 8
4107
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004108/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
4109 * (W-LUN), the normal Linux scanning logic does not associate it with a
4110 * device (e.g. /dev/sg7). The following magic will make that association:
4111 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
4112 * where <n> is a host number. If there are multiple targets in a host then
4113 * the above will associate a W-LUN to each target. To only get a W-LUN
4114 * for target 2, then use "echo '- 2 49409' > scan" .
4115 */
4116static int resp_report_luns(struct scsi_cmnd *scp,
4117 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02004119 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004120 unsigned int alloc_len;
4121 unsigned char select_report;
4122 u64 lun;
4123 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004124 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004125 unsigned int lun_cnt; /* normal LUN count (max: 256) */
4126 unsigned int wlun_cnt; /* report luns W-LUN count */
4127 unsigned int tlun_cnt; /* total LUN count */
4128 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004129 int k, j, n, res;
4130 unsigned int off_rsp = 0;
4131 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004133 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004134
4135 select_report = cmd[2];
4136 alloc_len = get_unaligned_be32(cmd + 6);
4137
4138 if (alloc_len < 4) {
4139 pr_err("alloc len too small %d\n", alloc_len);
4140 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 return check_condition_result;
4142 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004143
4144 switch (select_report) {
4145 case 0: /* all LUNs apart from W-LUNs */
4146 lun_cnt = sdebug_max_luns;
4147 wlun_cnt = 0;
4148 break;
4149 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004150 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004151 wlun_cnt = 1;
4152 break;
4153 case 2: /* all LUNs */
4154 lun_cnt = sdebug_max_luns;
4155 wlun_cnt = 1;
4156 break;
4157 case 0x10: /* only administrative LUs */
4158 case 0x11: /* see SPC-5 */
4159 case 0x12: /* only subsiduary LUs owned by referenced LU */
4160 default:
4161 pr_debug("select report invalid %d\n", select_report);
4162 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
4163 return check_condition_result;
4164 }
4165
4166 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004167 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004168
4169 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004170 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
4171 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004172 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
4173 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
4174
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004175 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004176 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004177 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4178 memset(arr, 0, sizeof(arr));
4179 lun_p = (struct scsi_lun *)&arr[0];
4180 if (k == 0) {
4181 put_unaligned_be32(rlen, &arr[0]);
4182 ++lun_p;
4183 j = 1;
4184 }
4185 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4186 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4187 break;
4188 int_to_scsilun(lun++, lun_p);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04004189 if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4190 lun_p->scsi_lun[0] |= 0x40;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004191 }
4192 if (j < RL_BUCKET_ELEMS)
4193 break;
4194 n = j * sz_lun;
4195 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4196 if (res)
4197 return res;
4198 off_rsp += n;
4199 }
4200 if (wlun_cnt) {
4201 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4202 ++j;
4203 }
4204 if (j > 0)
4205 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004206 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207}
4208
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004209static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4210{
4211 bool is_bytchk3 = false;
4212 u8 bytchk;
4213 int ret, j;
4214 u32 vnum, a_num, off;
4215 const u32 lb_size = sdebug_sector_size;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004216 u64 lba;
4217 u8 *arr;
4218 u8 *cmd = scp->cmnd;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004219 struct sdeb_store_info *sip = devip2sip(devip, true);
4220 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004221
4222 bytchk = (cmd[1] >> 1) & 0x3;
4223 if (bytchk == 0) {
4224 return 0; /* always claim internal verify okay */
4225 } else if (bytchk == 2) {
4226 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4227 return check_condition_result;
4228 } else if (bytchk == 3) {
4229 is_bytchk3 = true; /* 1 block sent, compared repeatedly */
4230 }
4231 switch (cmd[0]) {
4232 case VERIFY_16:
4233 lba = get_unaligned_be64(cmd + 2);
4234 vnum = get_unaligned_be32(cmd + 10);
4235 break;
4236 case VERIFY: /* is VERIFY(10) */
4237 lba = get_unaligned_be32(cmd + 2);
4238 vnum = get_unaligned_be16(cmd + 7);
4239 break;
4240 default:
4241 mk_sense_invalid_opcode(scp);
4242 return check_condition_result;
4243 }
4244 a_num = is_bytchk3 ? 1 : vnum;
4245 /* Treat following check like one for read (i.e. no write) access */
4246 ret = check_device_access_params(scp, lba, a_num, false);
4247 if (ret)
4248 return ret;
4249
4250 arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4251 if (!arr) {
4252 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4253 INSUFF_RES_ASCQ);
4254 return check_condition_result;
4255 }
4256 /* Not changing store, so only need read access */
Douglas Gilbert67da4132020-04-21 11:14:20 -04004257 read_lock(macc_lckp);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004258
4259 ret = do_dout_fetch(scp, a_num, arr);
4260 if (ret == -1) {
4261 ret = DID_ERROR << 16;
4262 goto cleanup;
4263 } else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4264 sdev_printk(KERN_INFO, scp->device,
4265 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4266 my_name, __func__, a_num * lb_size, ret);
4267 }
4268 if (is_bytchk3) {
4269 for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4270 memcpy(arr + off, arr, lb_size);
4271 }
4272 ret = 0;
4273 if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4274 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4275 ret = check_condition_result;
4276 goto cleanup;
4277 }
4278cleanup:
Douglas Gilbert67da4132020-04-21 11:14:20 -04004279 read_unlock(macc_lckp);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004280 kfree(arr);
4281 return ret;
4282}
4283
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004284#define RZONES_DESC_HD 64
4285
4286/* Report zones depending on start LBA nad reporting options */
4287static int resp_report_zones(struct scsi_cmnd *scp,
4288 struct sdebug_dev_info *devip)
4289{
4290 unsigned int i, max_zones, rep_max_zones, nrz = 0;
4291 int ret = 0;
4292 u32 alloc_len, rep_opts, rep_len;
4293 bool partial;
4294 u64 lba, zs_lba;
4295 u8 *arr = NULL, *desc;
4296 u8 *cmd = scp->cmnd;
4297 struct sdeb_zone_state *zsp;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004298 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004299 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4300
4301 if (!sdebug_dev_is_zoned(devip)) {
4302 mk_sense_invalid_opcode(scp);
4303 return check_condition_result;
4304 }
4305 zs_lba = get_unaligned_be64(cmd + 2);
4306 alloc_len = get_unaligned_be32(cmd + 10);
4307 rep_opts = cmd[14] & 0x3f;
4308 partial = cmd[14] & 0x80;
4309
4310 if (zs_lba >= sdebug_capacity) {
4311 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4312 return check_condition_result;
4313 }
4314
Damien Le Moal108e36f2020-05-07 11:35:26 +09004315 max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004316 rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4317 max_zones);
4318
4319 arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4320 if (!arr) {
4321 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4322 INSUFF_RES_ASCQ);
4323 return check_condition_result;
4324 }
4325
4326 read_lock(macc_lckp);
4327
4328 desc = arr + 64;
4329 for (i = 0; i < max_zones; i++) {
4330 lba = zs_lba + devip->zsize * i;
4331 if (lba > sdebug_capacity)
4332 break;
4333 zsp = zbc_zone(devip, lba);
4334 switch (rep_opts) {
4335 case 0x00:
4336 /* All zones */
4337 break;
4338 case 0x01:
4339 /* Empty zones */
4340 if (zsp->z_cond != ZC1_EMPTY)
4341 continue;
4342 break;
4343 case 0x02:
4344 /* Implicit open zones */
4345 if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4346 continue;
4347 break;
4348 case 0x03:
4349 /* Explicit open zones */
4350 if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4351 continue;
4352 break;
4353 case 0x04:
4354 /* Closed zones */
4355 if (zsp->z_cond != ZC4_CLOSED)
4356 continue;
4357 break;
4358 case 0x05:
4359 /* Full zones */
4360 if (zsp->z_cond != ZC5_FULL)
4361 continue;
4362 break;
4363 case 0x06:
4364 case 0x07:
4365 case 0x10:
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004366 /*
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004367 * Read-only, offline, reset WP recommended are
4368 * not emulated: no zones to report;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004369 */
4370 continue;
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004371 case 0x11:
4372 /* non-seq-resource set */
4373 if (!zsp->z_non_seq_resource)
4374 continue;
4375 break;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004376 case 0x3f:
4377 /* Not write pointer (conventional) zones */
4378 if (!zbc_zone_is_conv(zsp))
4379 continue;
4380 break;
4381 default:
4382 mk_sense_buffer(scp, ILLEGAL_REQUEST,
4383 INVALID_FIELD_IN_CDB, 0);
4384 ret = check_condition_result;
4385 goto fini;
4386 }
4387
4388 if (nrz < rep_max_zones) {
4389 /* Fill zone descriptor */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004390 desc[0] = zsp->z_type;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004391 desc[1] = zsp->z_cond << 4;
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004392 if (zsp->z_non_seq_resource)
4393 desc[1] |= 1 << 1;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004394 put_unaligned_be64((u64)zsp->z_size, desc + 8);
4395 put_unaligned_be64((u64)zsp->z_start, desc + 16);
4396 put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4397 desc += 64;
4398 }
4399
4400 if (partial && nrz >= rep_max_zones)
4401 break;
4402
4403 nrz++;
4404 }
4405
4406 /* Report header */
4407 put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4408 put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4409
4410 rep_len = (unsigned long)desc - (unsigned long)arr;
4411 ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4412
4413fini:
4414 read_unlock(macc_lckp);
4415 kfree(arr);
4416 return ret;
4417}
4418
4419/* Logic transplanted from tcmu-runner, file_zbc.c */
4420static void zbc_open_all(struct sdebug_dev_info *devip)
4421{
4422 struct sdeb_zone_state *zsp = &devip->zstate[0];
4423 unsigned int i;
4424
4425 for (i = 0; i < devip->nr_zones; i++, zsp++) {
4426 if (zsp->z_cond == ZC4_CLOSED)
4427 zbc_open_zone(devip, &devip->zstate[i], true);
4428 }
4429}
4430
4431static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4432{
4433 int res = 0;
4434 u64 z_id;
4435 enum sdebug_z_cond zc;
4436 u8 *cmd = scp->cmnd;
4437 struct sdeb_zone_state *zsp;
4438 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004439 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004440 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4441
4442 if (!sdebug_dev_is_zoned(devip)) {
4443 mk_sense_invalid_opcode(scp);
4444 return check_condition_result;
4445 }
4446
4447 write_lock(macc_lckp);
4448
4449 if (all) {
4450 /* Check if all closed zones can be open */
4451 if (devip->max_open &&
4452 devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4453 mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4454 INSUFF_ZONE_ASCQ);
4455 res = check_condition_result;
4456 goto fini;
4457 }
4458 /* Open all closed zones */
4459 zbc_open_all(devip);
4460 goto fini;
4461 }
4462
4463 /* Open the specified zone */
4464 z_id = get_unaligned_be64(cmd + 2);
4465 if (z_id >= sdebug_capacity) {
4466 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4467 res = check_condition_result;
4468 goto fini;
4469 }
4470
4471 zsp = zbc_zone(devip, z_id);
4472 if (z_id != zsp->z_start) {
4473 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4474 res = check_condition_result;
4475 goto fini;
4476 }
4477 if (zbc_zone_is_conv(zsp)) {
4478 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4479 res = check_condition_result;
4480 goto fini;
4481 }
4482
4483 zc = zsp->z_cond;
4484 if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4485 goto fini;
4486
4487 if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4488 mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4489 INSUFF_ZONE_ASCQ);
4490 res = check_condition_result;
4491 goto fini;
4492 }
4493
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004494 zbc_open_zone(devip, zsp, true);
4495fini:
4496 write_unlock(macc_lckp);
4497 return res;
4498}
4499
4500static void zbc_close_all(struct sdebug_dev_info *devip)
4501{
4502 unsigned int i;
4503
4504 for (i = 0; i < devip->nr_zones; i++)
4505 zbc_close_zone(devip, &devip->zstate[i]);
4506}
4507
4508static int resp_close_zone(struct scsi_cmnd *scp,
4509 struct sdebug_dev_info *devip)
4510{
4511 int res = 0;
4512 u64 z_id;
4513 u8 *cmd = scp->cmnd;
4514 struct sdeb_zone_state *zsp;
4515 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004516 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004517 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4518
4519 if (!sdebug_dev_is_zoned(devip)) {
4520 mk_sense_invalid_opcode(scp);
4521 return check_condition_result;
4522 }
4523
4524 write_lock(macc_lckp);
4525
4526 if (all) {
4527 zbc_close_all(devip);
4528 goto fini;
4529 }
4530
4531 /* Close specified zone */
4532 z_id = get_unaligned_be64(cmd + 2);
4533 if (z_id >= sdebug_capacity) {
4534 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4535 res = check_condition_result;
4536 goto fini;
4537 }
4538
4539 zsp = zbc_zone(devip, z_id);
4540 if (z_id != zsp->z_start) {
4541 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4542 res = check_condition_result;
4543 goto fini;
4544 }
4545 if (zbc_zone_is_conv(zsp)) {
4546 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4547 res = check_condition_result;
4548 goto fini;
4549 }
4550
4551 zbc_close_zone(devip, zsp);
4552fini:
4553 write_unlock(macc_lckp);
4554 return res;
4555}
4556
4557static void zbc_finish_zone(struct sdebug_dev_info *devip,
4558 struct sdeb_zone_state *zsp, bool empty)
4559{
4560 enum sdebug_z_cond zc = zsp->z_cond;
4561
4562 if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4563 zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4564 if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4565 zbc_close_zone(devip, zsp);
4566 if (zsp->z_cond == ZC4_CLOSED)
4567 devip->nr_closed--;
4568 zsp->z_wp = zsp->z_start + zsp->z_size;
4569 zsp->z_cond = ZC5_FULL;
4570 }
4571}
4572
4573static void zbc_finish_all(struct sdebug_dev_info *devip)
4574{
4575 unsigned int i;
4576
4577 for (i = 0; i < devip->nr_zones; i++)
4578 zbc_finish_zone(devip, &devip->zstate[i], false);
4579}
4580
4581static int resp_finish_zone(struct scsi_cmnd *scp,
4582 struct sdebug_dev_info *devip)
4583{
4584 struct sdeb_zone_state *zsp;
4585 int res = 0;
4586 u64 z_id;
4587 u8 *cmd = scp->cmnd;
4588 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004589 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004590 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4591
4592 if (!sdebug_dev_is_zoned(devip)) {
4593 mk_sense_invalid_opcode(scp);
4594 return check_condition_result;
4595 }
4596
4597 write_lock(macc_lckp);
4598
4599 if (all) {
4600 zbc_finish_all(devip);
4601 goto fini;
4602 }
4603
4604 /* Finish the specified zone */
4605 z_id = get_unaligned_be64(cmd + 2);
4606 if (z_id >= sdebug_capacity) {
4607 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4608 res = check_condition_result;
4609 goto fini;
4610 }
4611
4612 zsp = zbc_zone(devip, z_id);
4613 if (z_id != zsp->z_start) {
4614 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4615 res = check_condition_result;
4616 goto fini;
4617 }
4618 if (zbc_zone_is_conv(zsp)) {
4619 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4620 res = check_condition_result;
4621 goto fini;
4622 }
4623
4624 zbc_finish_zone(devip, zsp, true);
4625fini:
4626 write_unlock(macc_lckp);
4627 return res;
4628}
4629
4630static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4631 struct sdeb_zone_state *zsp)
4632{
4633 enum sdebug_z_cond zc;
4634
4635 if (zbc_zone_is_conv(zsp))
4636 return;
4637
4638 zc = zsp->z_cond;
4639 if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4640 zbc_close_zone(devip, zsp);
4641
4642 if (zsp->z_cond == ZC4_CLOSED)
4643 devip->nr_closed--;
4644
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004645 zsp->z_non_seq_resource = false;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004646 zsp->z_wp = zsp->z_start;
4647 zsp->z_cond = ZC1_EMPTY;
4648}
4649
4650static void zbc_rwp_all(struct sdebug_dev_info *devip)
4651{
4652 unsigned int i;
4653
4654 for (i = 0; i < devip->nr_zones; i++)
4655 zbc_rwp_zone(devip, &devip->zstate[i]);
4656}
4657
4658static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4659{
4660 struct sdeb_zone_state *zsp;
4661 int res = 0;
4662 u64 z_id;
4663 u8 *cmd = scp->cmnd;
4664 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004665 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004666 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4667
4668 if (!sdebug_dev_is_zoned(devip)) {
4669 mk_sense_invalid_opcode(scp);
4670 return check_condition_result;
4671 }
4672
4673 write_lock(macc_lckp);
4674
4675 if (all) {
4676 zbc_rwp_all(devip);
4677 goto fini;
4678 }
4679
4680 z_id = get_unaligned_be64(cmd + 2);
4681 if (z_id >= sdebug_capacity) {
4682 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4683 res = check_condition_result;
4684 goto fini;
4685 }
4686
4687 zsp = zbc_zone(devip, z_id);
4688 if (z_id != zsp->z_start) {
4689 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4690 res = check_condition_result;
4691 goto fini;
4692 }
4693 if (zbc_zone_is_conv(zsp)) {
4694 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4695 res = check_condition_result;
4696 goto fini;
4697 }
4698
4699 zbc_rwp_zone(devip, zsp);
4700fini:
4701 write_unlock(macc_lckp);
4702 return res;
4703}
4704
Douglas Gilbertc4837392016-05-06 00:40:26 -04004705static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4706{
John Garryc10fa552020-07-09 20:23:20 +08004707 u16 hwq;
John Garryf7c4cdc2020-08-19 23:20:33 +08004708 u32 tag = blk_mq_unique_tag(cmnd->request);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004709
John Garryf7c4cdc2020-08-19 23:20:33 +08004710 hwq = blk_mq_unique_tag_to_hwq(tag);
John Garryc10fa552020-07-09 20:23:20 +08004711
John Garryf7c4cdc2020-08-19 23:20:33 +08004712 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4713 if (WARN_ON_ONCE(hwq >= submit_queues))
4714 hwq = 0;
John Garryc10fa552020-07-09 20:23:20 +08004715
Bart Van Assche458df782018-01-26 08:52:19 -08004716 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004717}
4718
John Garryc10fa552020-07-09 20:23:20 +08004719static u32 get_tag(struct scsi_cmnd *cmnd)
4720{
4721 return blk_mq_unique_tag(cmnd->request);
4722}
4723
Douglas Gilbertc4837392016-05-06 00:40:26 -04004724/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004725static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726{
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004727 bool aborted = sd_dp->aborted;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004728 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004729 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004731 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004732 struct sdebug_queued_cmd *sqcp;
4733 struct scsi_cmnd *scp;
4734 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004736 if (unlikely(aborted))
4737 sd_dp->aborted = false;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004738 qc_idx = sd_dp->qc_idx;
4739 sqp = sdebug_q_arr + sd_dp->sqa_idx;
4740 if (sdebug_statistics) {
4741 atomic_inc(&sdebug_completions);
4742 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4743 atomic_inc(&sdebug_miss_cpus);
4744 }
4745 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4746 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 return;
4748 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004749 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05304750 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004751 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004752 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004753 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004754 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
John Garryc10fa552020-07-09 20:23:20 +08004755 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4756 sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 return;
4758 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004759 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004760 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004761 atomic_dec(&devip->num_in_q);
4762 else
Tomas Winklerc12879702015-07-28 16:54:20 +03004763 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004764 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004765 retiring = 1;
4766
4767 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004768 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4769 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03004770 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004771 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004773
4774 if (unlikely(retiring)) { /* user has reduced max_queue */
4775 int k, retval;
4776
4777 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004778 if (qc_idx >= retval) {
4779 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03004780 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004781 return;
4782 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004783 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004784 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004785 atomic_set(&retired_max_queue, 0);
4786 else
4787 atomic_set(&retired_max_queue, k + 1);
4788 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004789 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004790 if (unlikely(aborted)) {
4791 if (sdebug_verbose)
4792 pr_info("bypassing scsi_done() due to aborted cmd\n");
4793 return;
4794 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004795 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796}
4797
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004798/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004799static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004800{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004801 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4802 hrt);
4803 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004804 return HRTIMER_NORESTART;
4805}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806
Douglas Gilberta10bc122016-04-25 12:16:32 -04004807/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004808static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04004809{
4810 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4811 ew.work);
4812 sdebug_q_cmd_complete(sd_dp);
4813}
4814
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004815static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02004816static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004817
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004818static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4819{
4820 struct sdeb_zone_state *zsp;
4821 sector_t capacity = get_sdebug_capacity();
4822 sector_t zstart = 0;
4823 unsigned int i;
4824
4825 /*
Damien Le Moal98e0a682020-04-22 19:42:20 +09004826 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
4827 * a zone size allowing for at least 4 zones on the device. Otherwise,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004828 * use the specified zone size checking that at least 2 zones can be
4829 * created for the device.
4830 */
Damien Le Moal98e0a682020-04-22 19:42:20 +09004831 if (!sdeb_zbc_zone_size_mb) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004832 devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4833 >> ilog2(sdebug_sector_size);
4834 while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4835 devip->zsize >>= 1;
4836 if (devip->zsize < 2) {
4837 pr_err("Device capacity too small\n");
4838 return -EINVAL;
4839 }
4840 } else {
Damien Le Moal108e36f2020-05-07 11:35:26 +09004841 if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4842 pr_err("Zone size is not a power of 2\n");
4843 return -EINVAL;
4844 }
Damien Le Moal98e0a682020-04-22 19:42:20 +09004845 devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004846 >> ilog2(sdebug_sector_size);
4847 if (devip->zsize >= capacity) {
4848 pr_err("Zone size too large for device capacity\n");
4849 return -EINVAL;
4850 }
4851 }
4852
Damien Le Moal108e36f2020-05-07 11:35:26 +09004853 devip->zsize_shift = ilog2(devip->zsize);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004854 devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4855
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09004856 if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4857 pr_err("Number of conventional zones too large\n");
4858 return -EINVAL;
4859 }
4860 devip->nr_conv_zones = sdeb_zbc_nr_conv;
4861
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004862 if (devip->zmodel == BLK_ZONED_HM) {
4863 /* zbc_max_open_zones can be 0, meaning "not reported" */
4864 if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4865 devip->max_open = (devip->nr_zones - 1) / 2;
4866 else
4867 devip->max_open = sdeb_zbc_max_open;
4868 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004869
4870 devip->zstate = kcalloc(devip->nr_zones,
4871 sizeof(struct sdeb_zone_state), GFP_KERNEL);
4872 if (!devip->zstate)
4873 return -ENOMEM;
4874
4875 for (i = 0; i < devip->nr_zones; i++) {
4876 zsp = &devip->zstate[i];
4877
4878 zsp->z_start = zstart;
4879
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09004880 if (i < devip->nr_conv_zones) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004881 zsp->z_type = ZBC_ZONE_TYPE_CNV;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004882 zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4883 zsp->z_wp = (sector_t)-1;
4884 } else {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004885 if (devip->zmodel == BLK_ZONED_HM)
4886 zsp->z_type = ZBC_ZONE_TYPE_SWR;
4887 else
4888 zsp->z_type = ZBC_ZONE_TYPE_SWP;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004889 zsp->z_cond = ZC1_EMPTY;
4890 zsp->z_wp = zsp->z_start;
4891 }
4892
4893 if (zsp->z_start + devip->zsize < capacity)
4894 zsp->z_size = devip->zsize;
4895 else
4896 zsp->z_size = capacity - zsp->z_start;
4897
4898 zstart += zsp->z_size;
4899 }
4900
4901 return 0;
4902}
4903
Douglas Gilbertfd321192016-04-25 12:16:33 -04004904static struct sdebug_dev_info *sdebug_device_create(
4905 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004906{
4907 struct sdebug_dev_info *devip;
4908
4909 devip = kzalloc(sizeof(*devip), flags);
4910 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004911 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02004912 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004913 else if (sdebug_uuid_ctl == 2) {
4914 if (got_shared_uuid)
4915 devip->lu_name = shared_uuid;
4916 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02004917 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004918 got_shared_uuid = true;
4919 devip->lu_name = shared_uuid;
4920 }
4921 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004922 devip->sdbg_host = sdbg_host;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004923 if (sdeb_zbc_in_use) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004924 devip->zmodel = sdeb_zbc_model;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004925 if (sdebug_device_create_zones(devip)) {
4926 kfree(devip);
4927 return NULL;
4928 }
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004929 } else {
4930 devip->zmodel = BLK_ZONED_NONE;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004931 }
4932 devip->sdbg_host = sdbg_host;
Douglas Gilbertfc136382020-07-24 11:55:31 -04004933 devip->create_ts = ktime_get_boottime();
4934 atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004935 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
4936 }
4937 return devip;
4938}
4939
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004940static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004942 struct sdebug_host_info *sdbg_host;
4943 struct sdebug_dev_info *open_devip = NULL;
4944 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004946 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
4947 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004948 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004950 }
Douglas Gilbertad0c7772020-08-21 00:22:49 -04004951
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
4953 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05004954 (devip->target == sdev->id) &&
4955 (devip->lun == sdev->lun))
4956 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 else {
4958 if ((!devip->used) && (!open_devip))
4959 open_devip = devip;
4960 }
4961 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004962 if (!open_devip) { /* try and make a new one */
4963 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
4964 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004965 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966 return NULL;
4967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09004969
4970 open_devip->channel = sdev->channel;
4971 open_devip->target = sdev->id;
4972 open_devip->lun = sdev->lun;
4973 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004974 atomic_set(&open_devip->num_in_q, 0);
4975 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004976 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09004977 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978}
4979
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004980static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004982 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03004983 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004984 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004985 return 0;
4986}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004988static int scsi_debug_slave_configure(struct scsi_device *sdp)
4989{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004990 struct sdebug_dev_info *devip =
4991 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09004992
Douglas Gilbert773642d2016-04-25 12:16:28 -04004993 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03004994 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004995 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004996 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4997 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4998 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004999 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005000 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005001 return 1; /* no resources, will be marked offline */
5002 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01005003 sdp->hostdata = devip;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005004 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005005 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005006 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005007 return 0;
5008}
5009
5010static void scsi_debug_slave_destroy(struct scsi_device *sdp)
5011{
5012 struct sdebug_dev_info *devip =
5013 (struct sdebug_dev_info *)sdp->hostdata;
5014
Douglas Gilbert773642d2016-04-25 12:16:28 -04005015 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03005016 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005017 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5018 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005019 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005020 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005021 sdp->hostdata = NULL;
5022 }
5023}
5024
Douglas Gilbert10bde982018-01-10 16:57:31 -05005025static void stop_qc_helper(struct sdebug_defer *sd_dp,
5026 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005027{
5028 if (!sd_dp)
5029 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005030 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005031 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005032 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005033 cancel_work_sync(&sd_dp->ew.work);
5034}
5035
Douglas Gilberta10bc122016-04-25 12:16:32 -04005036/* If @cmnd found deletes its timer or work queue and returns true; else
5037 returns false */
5038static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005039{
5040 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005041 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005042 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005043 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005044 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005045 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005046 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005047
Douglas Gilbertc4837392016-05-06 00:40:26 -04005048 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5049 spin_lock_irqsave(&sqp->qc_lock, iflags);
5050 qmax = sdebug_max_queue;
5051 r_qmax = atomic_read(&retired_max_queue);
5052 if (r_qmax > qmax)
5053 qmax = r_qmax;
5054 for (k = 0; k < qmax; ++k) {
5055 if (test_bit(k, sqp->in_use_bm)) {
5056 sqcp = &sqp->qc_arr[k];
5057 if (cmnd != sqcp->a_cmnd)
5058 continue;
5059 /* found */
5060 devip = (struct sdebug_dev_info *)
5061 cmnd->device->hostdata;
5062 if (devip)
5063 atomic_dec(&devip->num_in_q);
5064 sqcp->a_cmnd = NULL;
5065 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005066 if (sd_dp) {
5067 l_defer_t = sd_dp->defer_t;
5068 sd_dp->defer_t = SDEB_DEFER_NONE;
5069 } else
5070 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005071 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005072 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005073 clear_bit(k, sqp->in_use_bm);
5074 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005075 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005076 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005077 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005078 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04005079 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005080}
5081
Douglas Gilberta10bc122016-04-25 12:16:32 -04005082/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005083static void stop_all_queued(void)
5084{
5085 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005086 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005087 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005088 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005089 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005090 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005091 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005092
Douglas Gilbertc4837392016-05-06 00:40:26 -04005093 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5094 spin_lock_irqsave(&sqp->qc_lock, iflags);
5095 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5096 if (test_bit(k, sqp->in_use_bm)) {
5097 sqcp = &sqp->qc_arr[k];
5098 if (sqcp->a_cmnd == NULL)
5099 continue;
5100 devip = (struct sdebug_dev_info *)
5101 sqcp->a_cmnd->device->hostdata;
5102 if (devip)
5103 atomic_dec(&devip->num_in_q);
5104 sqcp->a_cmnd = NULL;
5105 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005106 if (sd_dp) {
5107 l_defer_t = sd_dp->defer_t;
5108 sd_dp->defer_t = SDEB_DEFER_NONE;
5109 } else
5110 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005111 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005112 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005113 clear_bit(k, sqp->in_use_bm);
5114 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005115 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005116 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005117 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119}
5120
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005121/* Free queued command memory on heap */
5122static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005124 int j, k;
5125 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005126 struct sdebug_queued_cmd *sqcp;
5127
Douglas Gilbertc4837392016-05-06 00:40:26 -04005128 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5129 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5130 sqcp = &sqp->qc_arr[k];
5131 kfree(sqcp->sd_dp);
5132 sqcp->sd_dp = NULL;
5133 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135}
5136
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005137static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138{
Douglas Gilberta10bc122016-04-25 12:16:32 -04005139 bool ok;
5140
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005141 ++num_aborts;
5142 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04005143 ok = stop_queued_cmnd(SCpnt);
5144 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5145 sdev_printk(KERN_INFO, SCpnt->device,
5146 "%s: command%s found\n", __func__,
5147 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005149 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150}
5151
John Pittman91d4c752018-02-09 21:12:43 -05005152static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005155 if (SCpnt && SCpnt->device) {
5156 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005157 struct sdebug_dev_info *devip =
5158 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005159
Douglas Gilbert773642d2016-04-25 12:16:28 -04005160 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005161 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005163 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 }
5165 return SUCCESS;
5166}
5167
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005168static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5169{
5170 struct sdebug_host_info *sdbg_host;
5171 struct sdebug_dev_info *devip;
5172 struct scsi_device *sdp;
5173 struct Scsi_Host *hp;
5174 int k = 0;
5175
5176 ++num_target_resets;
5177 if (!SCpnt)
5178 goto lie;
5179 sdp = SCpnt->device;
5180 if (!sdp)
5181 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005182 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005183 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5184 hp = sdp->host;
5185 if (!hp)
5186 goto lie;
5187 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5188 if (sdbg_host) {
5189 list_for_each_entry(devip,
5190 &sdbg_host->dev_info_list,
5191 dev_list)
5192 if (devip->target == sdp->id) {
5193 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5194 ++k;
5195 }
5196 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005197 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005198 sdev_printk(KERN_INFO, sdp,
5199 "%s: %d device(s) found in target\n", __func__, k);
5200lie:
5201 return SUCCESS;
5202}
5203
John Pittman91d4c752018-02-09 21:12:43 -05005204static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205{
5206 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005207 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005208 struct scsi_device *sdp;
5209 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005210 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005213 if (!(SCpnt && SCpnt->device))
5214 goto lie;
5215 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005216 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005217 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5218 hp = sdp->host;
5219 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09005220 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005222 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05005223 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005224 dev_list) {
5225 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5226 ++k;
5227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 }
5229 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005230 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005231 sdev_printk(KERN_INFO, sdp,
5232 "%s: %d device(s) found in host\n", __func__, k);
5233lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 return SUCCESS;
5235}
5236
John Pittman91d4c752018-02-09 21:12:43 -05005237static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238{
John Pittman91d4c752018-02-09 21:12:43 -05005239 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005240 struct sdebug_dev_info *devip;
5241 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005244 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005245 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005246 spin_lock(&sdebug_host_list_lock);
5247 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005248 list_for_each_entry(devip, &sdbg_host->dev_info_list,
5249 dev_list) {
5250 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5251 ++k;
5252 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005253 }
5254 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04005256 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005257 sdev_printk(KERN_INFO, SCpnt->device,
5258 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 return SUCCESS;
5260}
5261
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005262static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263{
Christoph Hellwig1442f762020-03-24 08:25:26 +01005264 struct msdos_partition *pp;
John Pittman979e0dc2020-09-02 17:14:33 -04005265 int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 int sectors_per_part, num_sectors, k;
5267 int heads_by_sects, start_sec, end_sec;
5268
5269 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005270 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005272 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5273 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03005274 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 }
John Pittman8c657232020-09-02 17:14:34 -04005276 num_sectors = (int)get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04005278 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005280 starts[0] = sdebug_sectors_per;
John Pittman979e0dc2020-09-02 17:14:33 -04005281 max_part_secs = sectors_per_part;
5282 for (k = 1; k < sdebug_num_parts; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 starts[k] = ((k * sectors_per_part) / heads_by_sects)
5284 * heads_by_sects;
John Pittman979e0dc2020-09-02 17:14:33 -04005285 if (starts[k] - starts[k - 1] < max_part_secs)
5286 max_part_secs = starts[k] - starts[k - 1];
5287 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005288 starts[sdebug_num_parts] = num_sectors;
5289 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290
5291 ramp[510] = 0x55; /* magic partition markings */
5292 ramp[511] = 0xAA;
Christoph Hellwig1442f762020-03-24 08:25:26 +01005293 pp = (struct msdos_partition *)(ramp + 0x1be);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 for (k = 0; starts[k + 1]; ++k, ++pp) {
5295 start_sec = starts[k];
John Pittman979e0dc2020-09-02 17:14:33 -04005296 end_sec = starts[k] + max_part_secs - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 pp->boot_ind = 0;
5298
5299 pp->cyl = start_sec / heads_by_sects;
5300 pp->head = (start_sec - (pp->cyl * heads_by_sects))
5301 / sdebug_sectors_per;
5302 pp->sector = (start_sec % sdebug_sectors_per) + 1;
5303
5304 pp->end_cyl = end_sec / heads_by_sects;
5305 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
5306 / sdebug_sectors_per;
5307 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
5308
Akinobu Mita150c3542013-08-26 22:08:40 +09005309 pp->start_sect = cpu_to_le32(start_sec);
5310 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 pp->sys_ind = 0x83; /* plain Linux partition */
5312 }
5313}
5314
Douglas Gilbertc4837392016-05-06 00:40:26 -04005315static void block_unblock_all_queues(bool block)
5316{
5317 int j;
5318 struct sdebug_queue *sqp;
5319
5320 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5321 atomic_set(&sqp->blocked, (int)block);
5322}
5323
5324/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5325 * commands will be processed normally before triggers occur.
5326 */
5327static void tweak_cmnd_count(void)
5328{
5329 int count, modulo;
5330
5331 modulo = abs(sdebug_every_nth);
5332 if (modulo < 2)
5333 return;
5334 block_unblock_all_queues(true);
5335 count = atomic_read(&sdebug_cmnd_count);
5336 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5337 block_unblock_all_queues(false);
5338}
5339
5340static void clear_queue_stats(void)
5341{
5342 atomic_set(&sdebug_cmnd_count, 0);
5343 atomic_set(&sdebug_completions, 0);
5344 atomic_set(&sdebug_miss_cpus, 0);
5345 atomic_set(&sdebug_a_tsf, 0);
5346}
5347
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005348static bool inject_on_this_cmd(void)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005349{
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005350 if (sdebug_every_nth == 0)
5351 return false;
5352 return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005353}
5354
Douglas Gilberta2aede92020-04-21 11:14:21 -04005355#define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */
5356
Douglas Gilbertc4837392016-05-06 00:40:26 -04005357/* Complete the processing of the thread that queued a SCSI command to this
5358 * driver. It either completes the command by calling cmnd_done() or
5359 * schedules a hr timer or work queue then returns 0. Returns
5360 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5361 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04005362static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Martin Wilckf66b8512018-02-14 11:05:57 +01005363 int scsi_result,
5364 int (*pfp)(struct scsi_cmnd *,
5365 struct sdebug_dev_info *),
5366 int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367{
Douglas Gilberta2aede92020-04-21 11:14:21 -04005368 bool new_sd_dp;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005369 bool inject = false;
Douglas Gilbert771f7122021-03-03 20:41:07 -05005370 bool hipri = (cmnd->request->cmd_flags & REQ_HIPRI);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005371 int k, num_in_q, qdepth;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005372 unsigned long iflags;
5373 u64 ns_from_boot = 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005374 struct sdebug_queue *sqp;
5375 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03005376 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005377 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005379 if (unlikely(devip == NULL)) {
5380 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005381 scsi_result = DID_NO_CONNECT << 16;
5382 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03005384 sdp = cmnd->device;
5385
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005386 if (delta_jiff == 0)
5387 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Douglas Gilbertc4837392016-05-06 00:40:26 -04005389 sqp = get_queue(cmnd);
5390 spin_lock_irqsave(&sqp->qc_lock, iflags);
5391 if (unlikely(atomic_read(&sqp->blocked))) {
5392 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5393 return SCSI_MLQUEUE_HOST_BUSY;
5394 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005395 num_in_q = atomic_read(&devip->num_in_q);
5396 qdepth = cmnd->device->queue_depth;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005397 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005398 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005399 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005400 goto respond_in_thread;
5401 } else
5402 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005403 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005404 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5405 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005406 if ((num_in_q == (qdepth - 1)) &&
5407 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04005408 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005409 atomic_set(&sdebug_a_tsf, 0);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005410 inject = true;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005411 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005413 }
5414
Douglas Gilbertc4837392016-05-06 00:40:26 -04005415 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005416 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005417 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005418 if (scsi_result)
5419 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005420 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005421 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005422 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005423 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005424 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04005425 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005426 (scsi_result ? "status: TASK SET FULL" :
5427 "report: host busy"));
5428 if (scsi_result)
5429 goto respond_in_thread;
5430 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005431 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 }
Douglas Gilbert74595c02020-07-02 10:53:55 -04005433 set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005434 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005435 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005436 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005437 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005438 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005439 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05305440
Douglas Gilbert74595c02020-07-02 10:53:55 -04005441 if (!sd_dp) {
Douglas Gilbert10bde982018-01-10 16:57:31 -05005442 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
Douglas Gilbert74595c02020-07-02 10:53:55 -04005443 if (!sd_dp) {
5444 atomic_dec(&devip->num_in_q);
5445 clear_bit(k, sqp->in_use_bm);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005446 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilbert74595c02020-07-02 10:53:55 -04005447 }
Douglas Gilberta2aede92020-04-21 11:14:21 -04005448 new_sd_dp = true;
5449 } else {
5450 new_sd_dp = false;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005451 }
Martin Wilckf66b8512018-02-14 11:05:57 +01005452
John Garryc10fa552020-07-09 20:23:20 +08005453 /* Set the hostwide tag */
5454 if (sdebug_host_max_queue)
5455 sd_dp->hc_idx = get_tag(cmnd);
5456
Douglas Gilbert771f7122021-03-03 20:41:07 -05005457 if (hipri)
Douglas Gilberta2aede92020-04-21 11:14:21 -04005458 ns_from_boot = ktime_get_boottime_ns();
5459
5460 /* one of the resp_*() response functions is called here */
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005461 cmnd->result = pfp ? pfp(cmnd, devip) : 0;
Martin Wilckf66b8512018-02-14 11:05:57 +01005462 if (cmnd->result & SDEG_RES_IMMED_MASK) {
Martin Wilckf66b8512018-02-14 11:05:57 +01005463 cmnd->result &= ~SDEG_RES_IMMED_MASK;
5464 delta_jiff = ndelay = 0;
5465 }
5466 if (cmnd->result == 0 && scsi_result != 0)
5467 cmnd->result = scsi_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005468 if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
5469 if (atomic_read(&sdeb_inject_pending)) {
5470 mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
5471 atomic_set(&sdeb_inject_pending, 0);
5472 cmnd->result = check_condition_result;
5473 }
5474 }
Martin Wilckf66b8512018-02-14 11:05:57 +01005475
5476 if (unlikely(sdebug_verbose && cmnd->result))
5477 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5478 __func__, cmnd->result);
5479
Douglas Gilbert10bde982018-01-10 16:57:31 -05005480 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04005481 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005482
Douglas Gilbertb333a812016-04-25 12:16:30 -04005483 if (delta_jiff > 0) {
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005484 u64 ns = jiffies_to_nsecs(delta_jiff);
5485
5486 if (sdebug_random && ns < U32_MAX) {
5487 ns = prandom_u32_max((u32)ns);
5488 } else if (sdebug_random) {
5489 ns >>= 12; /* scale to 4 usec precision */
5490 if (ns < U32_MAX) /* over 4 hours max */
5491 ns = prandom_u32_max((u32)ns);
5492 ns <<= 12;
5493 }
5494 kt = ns_to_ktime(ns);
5495 } else { /* ndelay has a 4.2 second max */
5496 kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
5497 (u32)ndelay;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005498 if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5499 u64 d = ktime_get_boottime_ns() - ns_from_boot;
5500
5501 if (kt <= d) { /* elapsed duration >= kt */
Douglas Gilbert223f91b2020-08-13 11:57:38 -04005502 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005503 sqcp->a_cmnd = NULL;
5504 atomic_dec(&devip->num_in_q);
5505 clear_bit(k, sqp->in_use_bm);
Douglas Gilbert223f91b2020-08-13 11:57:38 -04005506 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005507 if (new_sd_dp)
5508 kfree(sd_dp);
5509 /* call scsi_done() from this thread */
5510 cmnd->scsi_done(cmnd);
5511 return 0;
5512 }
5513 /* otherwise reduce kt by elapsed time */
5514 kt -= d;
5515 }
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005516 }
Douglas Gilbert771f7122021-03-03 20:41:07 -05005517 if (hipri) {
5518 sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305519 spin_lock_irqsave(&sqp->qc_lock, iflags);
5520 if (!sd_dp->init_poll) {
5521 sd_dp->init_poll = true;
5522 sqcp->sd_dp = sd_dp;
5523 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5524 sd_dp->qc_idx = k;
5525 }
5526 sd_dp->defer_t = SDEB_DEFER_POLL;
5527 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5528 } else {
5529 if (!sd_dp->init_hrt) {
5530 sd_dp->init_hrt = true;
5531 sqcp->sd_dp = sd_dp;
5532 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5533 HRTIMER_MODE_REL_PINNED);
5534 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5535 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5536 sd_dp->qc_idx = k;
5537 }
5538 sd_dp->defer_t = SDEB_DEFER_HRT;
5539 /* schedule the invocation of scsi_done() for a later time */
5540 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005541 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005542 if (sdebug_statistics)
5543 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbertc4837392016-05-06 00:40:26 -04005544 } else { /* jdelay < 0, use work queue */
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005545 if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
5546 atomic_read(&sdeb_inject_pending)))
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005547 sd_dp->aborted = true;
Douglas Gilbert771f7122021-03-03 20:41:07 -05005548 if (hipri) {
5549 sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305550 spin_lock_irqsave(&sqp->qc_lock, iflags);
5551 if (!sd_dp->init_poll) {
5552 sd_dp->init_poll = true;
5553 sqcp->sd_dp = sd_dp;
5554 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5555 sd_dp->qc_idx = k;
5556 }
5557 sd_dp->defer_t = SDEB_DEFER_POLL;
5558 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5559 } else {
5560 if (!sd_dp->init_wq) {
5561 sd_dp->init_wq = true;
5562 sqcp->sd_dp = sd_dp;
5563 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5564 sd_dp->qc_idx = k;
5565 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5566 }
5567 sd_dp->defer_t = SDEB_DEFER_WQ;
5568 schedule_work(&sd_dp->ew.work);
5569 }
5570 if (sdebug_statistics)
5571 sd_dp->issuing_cpu = raw_smp_processor_id();
5572 if (unlikely(sd_dp->aborted)) {
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005573 sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", cmnd->request->tag);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005574 blk_abort_request(cmnd->request);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005575 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305576 sd_dp->aborted = false;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005577 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005578 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005579 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
5580 sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
5581 num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005582 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005583
5584respond_in_thread: /* call back to mid-layer using invocation thread */
Martin Wilckf66b8512018-02-14 11:05:57 +01005585 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5586 cmnd->result &= ~SDEG_RES_IMMED_MASK;
5587 if (cmnd->result == 0 && scsi_result != 0)
5588 cmnd->result = scsi_result;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005589 cmnd->scsi_done(cmnd);
5590 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005592
Douglas Gilbert23183912006-09-16 20:30:47 -04005593/* Note: The following macros create attribute files in the
5594 /sys/module/scsi_debug/parameters directory. Unfortunately this
5595 driver is unaware of a change and cannot trigger auxiliary actions
5596 as it can when the corresponding attribute in the
5597 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
5598 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005599module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5600module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005601module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005602module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04005603module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005604module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5605module_param_named(dif, sdebug_dif, int, S_IRUGO);
5606module_param_named(dix, sdebug_dix, int, S_IRUGO);
5607module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5608module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5609module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5610module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5611module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
John Garryc10fa552020-07-09 20:23:20 +08005612module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005613module_param_string(inq_product, sdebug_inq_product_id,
Douglas Gilbert5d807072020-04-21 11:14:23 -04005614 sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005615module_param_string(inq_rev, sdebug_inq_product_rev,
Douglas Gilbert5d807072020-04-21 11:14:23 -04005616 sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
5617module_param_string(inq_vendor, sdebug_inq_vendor_id,
5618 sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
5619module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005620module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5621module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5622module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005623module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04005624module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005625module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5626module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005627module_param_named(medium_error_count, sdebug_medium_error_count, int,
5628 S_IRUGO | S_IWUSR);
5629module_param_named(medium_error_start, sdebug_medium_error_start, int,
5630 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005631module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5632module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5633module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5634module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5635module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5636module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005637module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005638module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005639module_param_named(per_host_store, sdebug_per_host_store, bool,
5640 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005641module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5642module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005643module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005644module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5645module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5646module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005647module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005648module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005649module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05305650module_param_named(poll_queues, poll_queues, int, S_IRUGO);
Douglas Gilbertfc136382020-07-24 11:55:31 -04005651module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005652module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5653module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5654module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5655module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005656module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005657module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005658module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04005659 S_IRUGO | S_IWUSR);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05005660module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005661module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005662 S_IRUGO | S_IWUSR);
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09005663module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
Damien Le Moal380603a2020-04-22 19:42:18 +09005664module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09005665module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
Damien Le Moal98e0a682020-04-22 19:42:20 +09005666module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667
5668MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
5669MODULE_DESCRIPTION("SCSI debug adapter driver");
5670MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005671MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672
Douglas Gilbert5d807072020-04-21 11:14:23 -04005673MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005674MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005675MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09005676MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005677MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005678MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005679MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
5680MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005681MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07005682MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04005683MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005684MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04005685MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
John Garryc10fa552020-07-09 20:23:20 +08005686MODULE_PARM_DESC(host_max_queue,
5687 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005688MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005689MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
5690 SDEBUG_VERSION "\")");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005691MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
5692MODULE_PARM_DESC(lbprz,
5693 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005694MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
5695MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
5696MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
5697MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertad0c7772020-08-21 00:22:49 -04005698MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04005699MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005700MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05005701MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005702MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005703MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005704MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005705MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005707MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05005708MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01005709MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005710MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
5711MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
5712MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04005713MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005715MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
Martin Pittd9867882012-09-06 12:04:33 +02005716MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005717MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005718MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005719MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005720MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005721MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Douglas Gilbertfc136382020-07-24 11:55:31 -04005722MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005723MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
5724MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04005725MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
5726MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005727MODULE_PARM_DESC(uuid_ctl,
5728 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005729MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005730MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05005731MODULE_PARM_DESC(wp, "Write Protect (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005732MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09005733MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
Damien Le Moal380603a2020-04-22 19:42:18 +09005734MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09005735MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
Damien Le Moal98e0a682020-04-22 19:42:20 +09005736MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005738#define SDEBUG_INFO_LEN 256
5739static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740
John Pittman91d4c752018-02-09 21:12:43 -05005741static const char *scsi_debug_info(struct Scsi_Host *shp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005743 int k;
5744
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005745 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5746 my_name, SDEBUG_VERSION, sdebug_version_date);
5747 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005748 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005749 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5750 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5751 sdebug_dev_size_mb, sdebug_opts, submit_queues,
5752 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 return sdebug_info;
5754}
5755
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005756/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04005757static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5758 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759{
Al Viroc8ed5552013-03-31 01:46:06 -04005760 char arr[16];
5761 int opts;
5762 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763
Al Viroc8ed5552013-03-31 01:46:06 -04005764 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
5765 return -EACCES;
5766 memcpy(arr, buffer, minLen);
5767 arr[minLen] = '\0';
5768 if (1 != sscanf(arr, "%d", &opts))
5769 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005770 sdebug_opts = opts;
5771 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5772 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5773 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005774 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04005775 return length;
5776}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005778/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5779 * same for each scsi_debug host (if more than one). Some of the counters
5780 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04005781static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5782{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005783 int f, j, l;
5784 struct sdebug_queue *sqp;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005785 struct sdebug_host_info *sdhp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005786
Douglas Gilbertc4837392016-05-06 00:40:26 -04005787 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5788 SDEBUG_VERSION, sdebug_version_date);
5789 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5790 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5791 sdebug_opts, sdebug_every_nth);
5792 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5793 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5794 sdebug_sector_size, "bytes");
5795 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5796 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5797 num_aborts);
5798 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5799 num_dev_resets, num_target_resets, num_bus_resets,
5800 num_host_resets);
5801 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5802 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08005803 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5804 sdebug_statistics);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305805 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005806 atomic_read(&sdebug_cmnd_count),
5807 atomic_read(&sdebug_completions),
5808 "miss_cpus", atomic_read(&sdebug_miss_cpus),
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305809 atomic_read(&sdebug_a_tsf),
5810 atomic_read(&sdeb_mq_poll_count));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005811
Douglas Gilbertc4837392016-05-06 00:40:26 -04005812 seq_printf(m, "submit_queues=%d\n", submit_queues);
5813 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5814 seq_printf(m, " queue %d:\n", j);
5815 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5816 if (f != sdebug_max_queue) {
5817 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5818 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
5819 "first,last bits", f, l);
5820 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005821 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005822
5823 seq_printf(m, "this host_no=%d\n", host->host_no);
5824 if (!xa_empty(per_store_ap)) {
5825 bool niu;
5826 int idx;
5827 unsigned long l_idx;
5828 struct sdeb_store_info *sip;
5829
5830 seq_puts(m, "\nhost list:\n");
5831 j = 0;
5832 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
5833 idx = sdhp->si_idx;
5834 seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j,
5835 sdhp->shost->host_no, idx);
5836 ++j;
5837 }
5838 seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
5839 sdeb_most_recent_idx);
5840 j = 0;
5841 xa_for_each(per_store_ap, l_idx, sip) {
5842 niu = xa_get_mark(per_store_ap, l_idx,
5843 SDEB_XA_NOT_IN_USE);
5844 idx = (int)l_idx;
5845 seq_printf(m, " %d: idx=%d%s\n", j, idx,
5846 (niu ? " not_in_use" : ""));
5847 ++j;
5848 }
5849 }
Al Viroc8ed5552013-03-31 01:46:06 -04005850 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851}
5852
Akinobu Mita82069372013-10-14 22:48:04 +09005853static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854{
Douglas Gilbertc2206092016-04-25 12:16:31 -04005855 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856}
Douglas Gilbertc4837392016-05-06 00:40:26 -04005857/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5858 * of delay is jiffies.
5859 */
Akinobu Mita82069372013-10-14 22:48:04 +09005860static ssize_t delay_store(struct device_driver *ddp, const char *buf,
5861 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862{
Douglas Gilbertc2206092016-04-25 12:16:31 -04005863 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005865 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005866 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04005867 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005868 int j, k;
5869 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005870
Douglas Gilbertc4837392016-05-06 00:40:26 -04005871 block_unblock_all_queues(true);
5872 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5873 ++j, ++sqp) {
5874 k = find_first_bit(sqp->in_use_bm,
5875 sdebug_max_queue);
5876 if (k != sdebug_max_queue) {
5877 res = -EBUSY; /* queued commands */
5878 break;
5879 }
5880 }
5881 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04005882 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005883 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005884 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005885 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005887 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 }
5889 return -EINVAL;
5890}
Akinobu Mita82069372013-10-14 22:48:04 +09005891static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005893static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5894{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005895 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005896}
5897/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04005898/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005899static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04005900 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005901{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005902 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005903
5904 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04005905 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005906 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005907 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005908 int j, k;
5909 struct sdebug_queue *sqp;
5910
5911 block_unblock_all_queues(true);
5912 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5913 ++j, ++sqp) {
5914 k = find_first_bit(sqp->in_use_bm,
5915 sdebug_max_queue);
5916 if (k != sdebug_max_queue) {
5917 res = -EBUSY; /* queued commands */
5918 break;
5919 }
5920 }
5921 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005922 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04005923 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
5924 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005925 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005926 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005927 }
5928 return res;
5929 }
5930 return -EINVAL;
5931}
5932static DRIVER_ATTR_RW(ndelay);
5933
Akinobu Mita82069372013-10-14 22:48:04 +09005934static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005936 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937}
5938
Akinobu Mita82069372013-10-14 22:48:04 +09005939static ssize_t opts_store(struct device_driver *ddp, const char *buf,
5940 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005942 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943 char work[20];
5944
Douglas Gilbert9a051012017-12-23 12:48:10 -05005945 if (sscanf(buf, "%10s", work) == 1) {
5946 if (strncasecmp(work, "0x", 2) == 0) {
5947 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948 goto opts_done;
5949 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005950 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 goto opts_done;
5952 }
5953 }
5954 return -EINVAL;
5955opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005956 sdebug_opts = opts;
5957 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5958 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005959 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 return count;
5961}
Akinobu Mita82069372013-10-14 22:48:04 +09005962static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963
Akinobu Mita82069372013-10-14 22:48:04 +09005964static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005966 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967}
Akinobu Mita82069372013-10-14 22:48:04 +09005968static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
5969 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005971 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09005973 /* Cannot change from or to TYPE_ZBC with sysfs */
5974 if (sdebug_ptype == TYPE_ZBC)
5975 return -EINVAL;
5976
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09005978 if (n == TYPE_ZBC)
5979 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005980 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 return count;
5982 }
5983 return -EINVAL;
5984}
Akinobu Mita82069372013-10-14 22:48:04 +09005985static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
Akinobu Mita82069372013-10-14 22:48:04 +09005987static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005989 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990}
Akinobu Mita82069372013-10-14 22:48:04 +09005991static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
5992 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005994 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995
5996 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005997 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005998 return count;
5999 }
6000 return -EINVAL;
6001}
Akinobu Mita82069372013-10-14 22:48:04 +09006002static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003
Akinobu Mita82069372013-10-14 22:48:04 +09006004static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04006005{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006006 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04006007}
Akinobu Mita82069372013-10-14 22:48:04 +09006008static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
6009 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04006010{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006011 int n, idx;
Douglas Gilbert23183912006-09-16 20:30:47 -04006012
6013 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006014 bool want_store = (n == 0);
6015 struct sdebug_host_info *sdhp;
6016
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006017 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04006018 sdebug_fake_rw = (sdebug_fake_rw > 0);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006019 if (sdebug_fake_rw == n)
6020 return count; /* not transitioning so do nothing */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006021
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006022 if (want_store) { /* 1 --> 0 transition, set up store */
6023 if (sdeb_first_idx < 0) {
6024 idx = sdebug_add_store();
6025 if (idx < 0)
6026 return idx;
6027 } else {
6028 idx = sdeb_first_idx;
6029 xa_clear_mark(per_store_ap, idx,
6030 SDEB_XA_NOT_IN_USE);
6031 }
6032 /* make all hosts use same store */
6033 list_for_each_entry(sdhp, &sdebug_host_list,
6034 host_list) {
6035 if (sdhp->si_idx != idx) {
6036 xa_set_mark(per_store_ap, sdhp->si_idx,
6037 SDEB_XA_NOT_IN_USE);
6038 sdhp->si_idx = idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006039 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006040 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006041 sdeb_most_recent_idx = idx;
6042 } else { /* 0 --> 1 transition is trigger for shrink */
6043 sdebug_erase_all_stores(true /* apart from first */);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006044 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006045 sdebug_fake_rw = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04006046 return count;
6047 }
6048 return -EINVAL;
6049}
Akinobu Mita82069372013-10-14 22:48:04 +09006050static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04006051
Akinobu Mita82069372013-10-14 22:48:04 +09006052static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006053{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006054 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006055}
Akinobu Mita82069372013-10-14 22:48:04 +09006056static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
6057 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006058{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006059 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006060
6061 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006062 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006063 return count;
6064 }
6065 return -EINVAL;
6066}
Akinobu Mita82069372013-10-14 22:48:04 +09006067static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006068
Akinobu Mita82069372013-10-14 22:48:04 +09006069static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006071 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072}
Akinobu Mita82069372013-10-14 22:48:04 +09006073static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
6074 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006076 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077
6078 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006079 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 sdebug_max_tgts_luns();
6081 return count;
6082 }
6083 return -EINVAL;
6084}
Akinobu Mita82069372013-10-14 22:48:04 +09006085static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086
Akinobu Mita82069372013-10-14 22:48:04 +09006087static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006089 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090}
Akinobu Mita82069372013-10-14 22:48:04 +09006091static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006093static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
6094{
6095 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
6096}
6097
6098static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
6099 size_t count)
6100{
6101 bool v;
6102
6103 if (kstrtobool(buf, &v))
6104 return -EINVAL;
6105
6106 sdebug_per_host_store = v;
6107 return count;
6108}
6109static DRIVER_ATTR_RW(per_host_store);
6110
Akinobu Mita82069372013-10-14 22:48:04 +09006111static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006113 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114}
Akinobu Mita82069372013-10-14 22:48:04 +09006115static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116
Akinobu Mita82069372013-10-14 22:48:04 +09006117static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006119 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120}
Akinobu Mita82069372013-10-14 22:48:04 +09006121static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
6122 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006124 int nth;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006125 char work[20];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006127 if (sscanf(buf, "%10s", work) == 1) {
6128 if (strncasecmp(work, "0x", 2) == 0) {
6129 if (kstrtoint(work + 2, 16, &nth) == 0)
6130 goto every_nth_done;
6131 } else {
6132 if (kstrtoint(work, 10, &nth) == 0)
6133 goto every_nth_done;
Douglas Gilbertc4837392016-05-06 00:40:26 -04006134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 }
6136 return -EINVAL;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006137
6138every_nth_done:
6139 sdebug_every_nth = nth;
6140 if (nth && !sdebug_statistics) {
6141 pr_info("every_nth needs statistics=1, set it\n");
6142 sdebug_statistics = true;
6143 }
6144 tweak_cmnd_count();
6145 return count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146}
Akinobu Mita82069372013-10-14 22:48:04 +09006147static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006149static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6150{
6151 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6152}
6153static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6154 size_t count)
6155{
6156 int n;
6157 bool changed;
6158
6159 if (kstrtoint(buf, 0, &n))
6160 return -EINVAL;
6161 if (n >= 0) {
6162 if (n > (int)SAM_LUN_AM_FLAT) {
6163 pr_warn("only LUN address methods 0 and 1 are supported\n");
6164 return -EINVAL;
6165 }
6166 changed = ((int)sdebug_lun_am != n);
6167 sdebug_lun_am = n;
6168 if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */
6169 struct sdebug_host_info *sdhp;
6170 struct sdebug_dev_info *dp;
6171
6172 spin_lock(&sdebug_host_list_lock);
6173 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6174 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6175 set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6176 }
6177 }
6178 spin_unlock(&sdebug_host_list_lock);
6179 }
6180 return count;
6181 }
6182 return -EINVAL;
6183}
6184static DRIVER_ATTR_RW(lun_format);
6185
Akinobu Mita82069372013-10-14 22:48:04 +09006186static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006188 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189}
Akinobu Mita82069372013-10-14 22:48:04 +09006190static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
6191 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006193 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05006194 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195
6196 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006197 if (n > 256) {
6198 pr_warn("max_luns can be no more than 256\n");
6199 return -EINVAL;
6200 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006201 changed = (sdebug_max_luns != n);
6202 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04006204 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05006205 struct sdebug_host_info *sdhp;
6206 struct sdebug_dev_info *dp;
6207
6208 spin_lock(&sdebug_host_list_lock);
6209 list_for_each_entry(sdhp, &sdebug_host_list,
6210 host_list) {
6211 list_for_each_entry(dp, &sdhp->dev_info_list,
6212 dev_list) {
6213 set_bit(SDEBUG_UA_LUNS_CHANGED,
6214 dp->uas_bm);
6215 }
6216 }
6217 spin_unlock(&sdebug_host_list_lock);
6218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 return count;
6220 }
6221 return -EINVAL;
6222}
Akinobu Mita82069372013-10-14 22:48:04 +09006223static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224
Akinobu Mita82069372013-10-14 22:48:04 +09006225static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006226{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006227 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006228}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006229/* N.B. max_queue can be changed while there are queued commands. In flight
6230 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09006231static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
6232 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006233{
Douglas Gilbertc4837392016-05-06 00:40:26 -04006234 int j, n, k, a;
6235 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006236
6237 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
John Garryc10fa552020-07-09 20:23:20 +08006238 (n <= SDEBUG_CANQUEUE) &&
6239 (sdebug_host_max_queue == 0)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04006240 block_unblock_all_queues(true);
6241 k = 0;
6242 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6243 ++j, ++sqp) {
6244 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6245 if (a > k)
6246 k = a;
6247 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006248 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04006249 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006250 atomic_set(&retired_max_queue, 0);
6251 else if (k >= n)
6252 atomic_set(&retired_max_queue, k + 1);
6253 else
6254 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04006255 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006256 return count;
6257 }
6258 return -EINVAL;
6259}
Akinobu Mita82069372013-10-14 22:48:04 +09006260static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006261
John Garryc10fa552020-07-09 20:23:20 +08006262static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6263{
6264 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6265}
6266
6267/*
6268 * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6269 * in range [0, sdebug_host_max_queue), we can't change it.
6270 */
6271static DRIVER_ATTR_RO(host_max_queue);
6272
Akinobu Mita82069372013-10-14 22:48:04 +09006273static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006274{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006275 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006276}
Akinobu Mita82069372013-10-14 22:48:04 +09006277static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006278
Akinobu Mita82069372013-10-14 22:48:04 +09006279static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006281 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282}
Akinobu Mita82069372013-10-14 22:48:04 +09006283static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284
Akinobu Mita82069372013-10-14 22:48:04 +09006285static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006286{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006287 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006288}
Akinobu Mita82069372013-10-14 22:48:04 +09006289static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
6290 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006291{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006292 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006293 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006294
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006295 /* Ignore capacity change for ZBC drives for now */
6296 if (sdeb_zbc_in_use)
6297 return -ENOTSUPP;
6298
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006299 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006300 changed = (sdebug_virtual_gb != n);
6301 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006302 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006303 if (changed) {
6304 struct sdebug_host_info *sdhp;
6305 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006306
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05006307 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006308 list_for_each_entry(sdhp, &sdebug_host_list,
6309 host_list) {
6310 list_for_each_entry(dp, &sdhp->dev_info_list,
6311 dev_list) {
6312 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
6313 dp->uas_bm);
6314 }
6315 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05006316 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006317 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006318 return count;
6319 }
6320 return -EINVAL;
6321}
Akinobu Mita82069372013-10-14 22:48:04 +09006322static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006323
Akinobu Mita82069372013-10-14 22:48:04 +09006324static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006326 /* absolute number of hosts currently active is what is shown */
6327 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328}
6329
Akinobu Mita82069372013-10-14 22:48:04 +09006330static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
6331 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006333 bool found;
6334 unsigned long idx;
6335 struct sdeb_store_info *sip;
6336 bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09006337 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09006339 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 if (delta_hosts > 0) {
6342 do {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006343 found = false;
6344 if (want_phs) {
6345 xa_for_each_marked(per_store_ap, idx, sip,
6346 SDEB_XA_NOT_IN_USE) {
6347 sdeb_most_recent_idx = (int)idx;
6348 found = true;
6349 break;
6350 }
6351 if (found) /* re-use case */
6352 sdebug_add_host_helper((int)idx);
6353 else
6354 sdebug_do_add_host(true);
6355 } else {
6356 sdebug_do_add_host(false);
6357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 } while (--delta_hosts);
6359 } else if (delta_hosts < 0) {
6360 do {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006361 sdebug_do_remove_host(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362 } while (++delta_hosts);
6363 }
6364 return count;
6365}
Akinobu Mita82069372013-10-14 22:48:04 +09006366static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367
Akinobu Mita82069372013-10-14 22:48:04 +09006368static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04006369{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006370 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04006371}
Akinobu Mita82069372013-10-14 22:48:04 +09006372static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
6373 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04006374{
6375 int n;
6376
6377 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006378 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04006379 return count;
6380 }
6381 return -EINVAL;
6382}
Akinobu Mita82069372013-10-14 22:48:04 +09006383static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04006384
Douglas Gilbertc4837392016-05-06 00:40:26 -04006385static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6386{
6387 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6388}
6389static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6390 size_t count)
6391{
6392 int n;
6393
6394 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6395 if (n > 0)
6396 sdebug_statistics = true;
6397 else {
6398 clear_queue_stats();
6399 sdebug_statistics = false;
6400 }
6401 return count;
6402 }
6403 return -EINVAL;
6404}
6405static DRIVER_ATTR_RW(statistics);
6406
Akinobu Mita82069372013-10-14 22:48:04 +09006407static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006408{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006409 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006410}
Akinobu Mita82069372013-10-14 22:48:04 +09006411static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006412
Douglas Gilbertc4837392016-05-06 00:40:26 -04006413static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6414{
6415 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6416}
6417static DRIVER_ATTR_RO(submit_queues);
6418
Akinobu Mita82069372013-10-14 22:48:04 +09006419static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006420{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006421 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006422}
Akinobu Mita82069372013-10-14 22:48:04 +09006423static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006424
Akinobu Mita82069372013-10-14 22:48:04 +09006425static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006426{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006427 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006428}
Akinobu Mita82069372013-10-14 22:48:04 +09006429static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006430
Akinobu Mita82069372013-10-14 22:48:04 +09006431static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006432{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006433 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006434}
Akinobu Mita82069372013-10-14 22:48:04 +09006435static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006436
Akinobu Mita82069372013-10-14 22:48:04 +09006437static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006438{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006439 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006440}
Akinobu Mita82069372013-10-14 22:48:04 +09006441static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006442
Akinobu Mita82069372013-10-14 22:48:04 +09006443static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04006444{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006445 ssize_t count = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006446
Martin K. Petersen5b94e232011-03-08 02:08:11 -05006447 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04006448 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
6449 sdebug_store_sectors);
6450
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006451 if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
6452 struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
6453
6454 if (sip)
6455 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
6456 (int)map_size, sip->map_storep);
6457 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04006458 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08006459 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04006460
6461 return count;
6462}
Akinobu Mita82069372013-10-14 22:48:04 +09006463static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04006464
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04006465static ssize_t random_show(struct device_driver *ddp, char *buf)
6466{
6467 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
6468}
6469
6470static ssize_t random_store(struct device_driver *ddp, const char *buf,
6471 size_t count)
6472{
6473 bool v;
6474
6475 if (kstrtobool(buf, &v))
6476 return -EINVAL;
6477
6478 sdebug_random = v;
6479 return count;
6480}
6481static DRIVER_ATTR_RW(random);
6482
Akinobu Mita82069372013-10-14 22:48:04 +09006483static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02006484{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006485 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02006486}
Akinobu Mita82069372013-10-14 22:48:04 +09006487static ssize_t removable_store(struct device_driver *ddp, const char *buf,
6488 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02006489{
6490 int n;
6491
6492 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006493 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02006494 return count;
6495 }
6496 return -EINVAL;
6497}
Akinobu Mita82069372013-10-14 22:48:04 +09006498static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02006499
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006500static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6501{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006502 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006503}
Douglas Gilbert185dd232016-04-25 12:16:29 -04006504/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006505static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6506 size_t count)
6507{
Douglas Gilbert185dd232016-04-25 12:16:29 -04006508 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006509
6510 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04006511 sdebug_host_lock = (n > 0);
6512 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006513 }
6514 return -EINVAL;
6515}
6516static DRIVER_ATTR_RW(host_lock);
6517
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006518static ssize_t strict_show(struct device_driver *ddp, char *buf)
6519{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006520 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006521}
6522static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6523 size_t count)
6524{
6525 int n;
6526
6527 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006528 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006529 return count;
6530 }
6531 return -EINVAL;
6532}
6533static DRIVER_ATTR_RW(strict);
6534
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04006535static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
6536{
6537 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
6538}
6539static DRIVER_ATTR_RO(uuid_ctl);
6540
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05006541static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
6542{
6543 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
6544}
6545static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
6546 size_t count)
6547{
6548 int ret, n;
6549
6550 ret = kstrtoint(buf, 0, &n);
6551 if (ret)
6552 return ret;
6553 sdebug_cdb_len = n;
6554 all_config_cdb_len();
6555 return count;
6556}
6557static DRIVER_ATTR_RW(cdb_len);
6558
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006559static const char * const zbc_model_strs_a[] = {
6560 [BLK_ZONED_NONE] = "none",
6561 [BLK_ZONED_HA] = "host-aware",
6562 [BLK_ZONED_HM] = "host-managed",
6563};
6564
6565static const char * const zbc_model_strs_b[] = {
6566 [BLK_ZONED_NONE] = "no",
6567 [BLK_ZONED_HA] = "aware",
6568 [BLK_ZONED_HM] = "managed",
6569};
6570
6571static const char * const zbc_model_strs_c[] = {
6572 [BLK_ZONED_NONE] = "0",
6573 [BLK_ZONED_HA] = "1",
6574 [BLK_ZONED_HM] = "2",
6575};
6576
6577static int sdeb_zbc_model_str(const char *cp)
6578{
6579 int res = sysfs_match_string(zbc_model_strs_a, cp);
6580
6581 if (res < 0) {
6582 res = sysfs_match_string(zbc_model_strs_b, cp);
6583 if (res < 0) {
6584 res = sysfs_match_string(zbc_model_strs_c, cp);
Dan Carpenter47742bd2020-05-09 13:04:08 +03006585 if (res < 0)
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006586 return -EINVAL;
6587 }
6588 }
6589 return res;
6590}
6591
6592static ssize_t zbc_show(struct device_driver *ddp, char *buf)
6593{
6594 return scnprintf(buf, PAGE_SIZE, "%s\n",
6595 zbc_model_strs_a[sdeb_zbc_model]);
6596}
6597static DRIVER_ATTR_RO(zbc);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006598
Douglas Gilbertfc136382020-07-24 11:55:31 -04006599static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6600{
6601 return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6602}
6603static DRIVER_ATTR_RO(tur_ms_to_ready);
6604
Akinobu Mita82069372013-10-14 22:48:04 +09006605/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04006606 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
6607 files (over those found in the /sys/module/scsi_debug/parameters
6608 directory) is that auxiliary actions can be triggered when an attribute
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006609 is changed. For example see: add_host_store() above.
Douglas Gilbert23183912006-09-16 20:30:47 -04006610 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006611
Akinobu Mita82069372013-10-14 22:48:04 +09006612static struct attribute *sdebug_drv_attrs[] = {
6613 &driver_attr_delay.attr,
6614 &driver_attr_opts.attr,
6615 &driver_attr_ptype.attr,
6616 &driver_attr_dsense.attr,
6617 &driver_attr_fake_rw.attr,
John Garryc10fa552020-07-09 20:23:20 +08006618 &driver_attr_host_max_queue.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006619 &driver_attr_no_lun_0.attr,
6620 &driver_attr_num_tgts.attr,
6621 &driver_attr_dev_size_mb.attr,
6622 &driver_attr_num_parts.attr,
6623 &driver_attr_every_nth.attr,
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006624 &driver_attr_lun_format.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006625 &driver_attr_max_luns.attr,
6626 &driver_attr_max_queue.attr,
6627 &driver_attr_no_uld.attr,
6628 &driver_attr_scsi_level.attr,
6629 &driver_attr_virtual_gb.attr,
6630 &driver_attr_add_host.attr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006631 &driver_attr_per_host_store.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006632 &driver_attr_vpd_use_hostno.attr,
6633 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04006634 &driver_attr_statistics.attr,
6635 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006636 &driver_attr_dix.attr,
6637 &driver_attr_dif.attr,
6638 &driver_attr_guard.attr,
6639 &driver_attr_ato.attr,
6640 &driver_attr_map.attr,
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04006641 &driver_attr_random.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006642 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006643 &driver_attr_host_lock.attr,
6644 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006645 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04006646 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05006647 &driver_attr_cdb_len.attr,
Douglas Gilbertfc136382020-07-24 11:55:31 -04006648 &driver_attr_tur_ms_to_ready.attr,
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006649 &driver_attr_zbc.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006650 NULL,
6651};
6652ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653
Akinobu Mita11ddcec2014-02-26 22:56:59 +09006654static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09006655
Linus Torvalds1da177e2005-04-16 15:20:36 -07006656static int __init scsi_debug_init(void)
6657{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006658 bool want_store = (sdebug_fake_rw == 0);
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09006659 unsigned long sz;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006660 int k, ret, hosts_to_add;
6661 int idx = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006662
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006663 ramdisk_lck_a[0] = &atomic_rw;
6664 ramdisk_lck_a[1] = &atomic_rw2;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006665 atomic_set(&retired_max_queue, 0);
6666
Douglas Gilbert773642d2016-04-25 12:16:28 -04006667 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006668 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04006669 sdebug_ndelay = 0;
6670 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04006671 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006672
Douglas Gilbert773642d2016-04-25 12:16:28 -04006673 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006674 case 512:
6675 case 1024:
6676 case 2048:
6677 case 4096:
6678 break;
6679 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04006680 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006681 return -EINVAL;
6682 }
6683
Douglas Gilbert773642d2016-04-25 12:16:28 -04006684 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02006685 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04006686 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02006687 case T10_PI_TYPE1_PROTECTION:
6688 case T10_PI_TYPE2_PROTECTION:
6689 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04006690 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006691 break;
6692
6693 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03006694 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006695 return -EINVAL;
6696 }
6697
Maurizio Lombardiaa5334c2019-11-15 17:37:27 +01006698 if (sdebug_num_tgts < 0) {
6699 pr_err("num_tgts must be >= 0\n");
6700 return -EINVAL;
6701 }
6702
Douglas Gilbert773642d2016-04-25 12:16:28 -04006703 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006704 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006705 return -EINVAL;
6706 }
6707
Douglas Gilbert773642d2016-04-25 12:16:28 -04006708 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006709 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006710 return -EINVAL;
6711 }
6712
Douglas Gilbert773642d2016-04-25 12:16:28 -04006713 if (sdebug_physblk_exp > 15) {
6714 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006715 return -EINVAL;
6716 }
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006717
6718 sdebug_lun_am = sdebug_lun_am_i;
6719 if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6720 pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6721 sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6722 }
6723
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006724 if (sdebug_max_luns > 256) {
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006725 if (sdebug_max_luns > 16384) {
6726 pr_warn("max_luns can be no more than 16384, use default\n");
6727 sdebug_max_luns = DEF_MAX_LUNS;
6728 }
6729 sdebug_lun_am = SAM_LUN_AM_FLAT;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006730 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006731
Douglas Gilbert773642d2016-04-25 12:16:28 -04006732 if (sdebug_lowest_aligned > 0x3fff) {
6733 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006734 return -EINVAL;
6735 }
6736
Douglas Gilbertc4837392016-05-06 00:40:26 -04006737 if (submit_queues < 1) {
6738 pr_err("submit_queues must be 1 or more\n");
6739 return -EINVAL;
6740 }
John Garryc87bf242020-07-09 20:23:19 +08006741
6742 if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6743 pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6744 return -EINVAL;
6745 }
6746
John Garryc10fa552020-07-09 20:23:20 +08006747 if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6748 (sdebug_host_max_queue < 0)) {
6749 pr_err("host_max_queue must be in range [0 %d]\n",
6750 SDEBUG_CANQUEUE);
6751 return -EINVAL;
6752 }
6753
6754 if (sdebug_host_max_queue &&
6755 (sdebug_max_queue != sdebug_host_max_queue)) {
6756 sdebug_max_queue = sdebug_host_max_queue;
6757 pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6758 sdebug_max_queue);
6759 }
6760
Douglas Gilbertc4837392016-05-06 00:40:26 -04006761 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6762 GFP_KERNEL);
6763 if (sdebug_q_arr == NULL)
6764 return -ENOMEM;
6765 for (k = 0; k < submit_queues; ++k)
6766 spin_lock_init(&sdebug_q_arr[k].qc_lock);
6767
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006768 /*
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006769 * check for host managed zoned block device specified with
6770 * ptype=0x14 or zbc=XXX.
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006771 */
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006772 if (sdebug_ptype == TYPE_ZBC) {
6773 sdeb_zbc_model = BLK_ZONED_HM;
6774 } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
6775 k = sdeb_zbc_model_str(sdeb_zbc_model_s);
6776 if (k < 0) {
6777 ret = k;
Dinghao Liu3b01d7e2020-12-26 14:15:03 +08006778 goto free_q_arr;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006779 }
6780 sdeb_zbc_model = k;
6781 switch (sdeb_zbc_model) {
6782 case BLK_ZONED_NONE:
Damien Le Moal64e14ec2020-04-22 19:42:21 +09006783 case BLK_ZONED_HA:
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006784 sdebug_ptype = TYPE_DISK;
6785 break;
6786 case BLK_ZONED_HM:
6787 sdebug_ptype = TYPE_ZBC;
6788 break;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006789 default:
6790 pr_err("Invalid ZBC model\n");
Dinghao Liu3b01d7e2020-12-26 14:15:03 +08006791 ret = -EINVAL;
6792 goto free_q_arr;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006793 }
6794 }
6795 if (sdeb_zbc_model != BLK_ZONED_NONE) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006796 sdeb_zbc_in_use = true;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006797 if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
6798 sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
6799 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006800
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006801 if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
6802 sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006803 if (sdebug_dev_size_mb < 1)
6804 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
6805 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6806 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006807 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808
6809 /* play around with geometry, don't waste too much on track 0 */
6810 sdebug_heads = 8;
6811 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006812 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006814 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02006815 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
6817 (sdebug_sectors_per * sdebug_heads);
6818 if (sdebug_cylinders_per >= 1024) {
6819 /* other LLDs do this; implies >= 1GB ram disk ... */
6820 sdebug_heads = 255;
6821 sdebug_sectors_per = 63;
6822 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
6823 (sdebug_sectors_per * sdebug_heads);
6824 }
Martin K. Petersen5b94e232011-03-08 02:08:11 -05006825 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006826 sdebug_unmap_max_blocks =
6827 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04006828
Douglas Gilbert773642d2016-04-25 12:16:28 -04006829 sdebug_unmap_max_desc =
6830 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04006831
Douglas Gilbert773642d2016-04-25 12:16:28 -04006832 sdebug_unmap_granularity =
6833 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04006834
Douglas Gilbert773642d2016-04-25 12:16:28 -04006835 if (sdebug_unmap_alignment &&
6836 sdebug_unmap_granularity <=
6837 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006838 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04006839 ret = -EINVAL;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006840 goto free_q_arr;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006841 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006842 }
6843 xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
6844 if (want_store) {
6845 idx = sdebug_add_store();
6846 if (idx < 0) {
6847 ret = idx;
6848 goto free_q_arr;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006849 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04006850 }
6851
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006852 pseudo_primary = root_device_register("pseudo_0");
6853 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006854 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006855 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006856 goto free_vm;
6857 }
6858 ret = bus_register(&pseudo_lld_bus);
6859 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006860 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006861 goto dev_unreg;
6862 }
6863 ret = driver_register(&sdebug_driverfs_driver);
6864 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006865 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006866 goto bus_unreg;
6867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006869 hosts_to_add = sdebug_add_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006870 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006871
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006872 for (k = 0; k < hosts_to_add; k++) {
6873 if (want_store && k == 0) {
6874 ret = sdebug_add_host_helper(idx);
6875 if (ret < 0) {
6876 pr_err("add_host_helper k=%d, error=%d\n",
6877 k, -ret);
6878 break;
6879 }
6880 } else {
6881 ret = sdebug_do_add_host(want_store &&
6882 sdebug_per_host_store);
6883 if (ret < 0) {
6884 pr_err("add_host k=%d error=%d\n", k, -ret);
6885 break;
6886 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05006887 }
6888 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006889 if (sdebug_verbose)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006890 pr_info("built %d host(s)\n", sdebug_num_hosts);
Tomas Winklerc12879702015-07-28 16:54:20 +03006891
Linus Torvalds1da177e2005-04-16 15:20:36 -07006892 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006893
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006894bus_unreg:
6895 bus_unregister(&pseudo_lld_bus);
6896dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006897 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006898free_vm:
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006899 sdebug_erase_store(idx, NULL);
Douglas Gilbertc4837392016-05-06 00:40:26 -04006900free_q_arr:
6901 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006902 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006903}
6904
6905static void __exit scsi_debug_exit(void)
6906{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006907 int k = sdebug_num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006908
6909 stop_all_queued();
6910 for (; k; k--)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006911 sdebug_do_remove_host(true);
Luis Henriques52ab9762018-06-18 17:08:03 +01006912 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006913 driver_unregister(&sdebug_driverfs_driver);
6914 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006915 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006916
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006917 sdebug_erase_all_stores(false);
6918 xa_destroy(per_store_ap);
Maurizio Lombardif852c592021-02-08 12:17:34 +01006919 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006920}
6921
6922device_initcall(scsi_debug_init);
6923module_exit(scsi_debug_exit);
6924
John Pittman91d4c752018-02-09 21:12:43 -05006925static void sdebug_release_adapter(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006926{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006927 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006928
6929 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05006930 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006931}
6932
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006933/* idx must be valid, if sip is NULL then it will be obtained using idx */
6934static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006936 if (idx < 0)
6937 return;
6938 if (!sip) {
6939 if (xa_empty(per_store_ap))
6940 return;
6941 sip = xa_load(per_store_ap, idx);
6942 if (!sip)
6943 return;
6944 }
6945 vfree(sip->map_storep);
6946 vfree(sip->dif_storep);
6947 vfree(sip->storep);
6948 xa_erase(per_store_ap, idx);
6949 kfree(sip);
6950}
6951
6952/* Assume apart_from_first==false only in shutdown case. */
6953static void sdebug_erase_all_stores(bool apart_from_first)
6954{
6955 unsigned long idx;
6956 struct sdeb_store_info *sip = NULL;
6957
6958 xa_for_each(per_store_ap, idx, sip) {
6959 if (apart_from_first)
6960 apart_from_first = false;
6961 else
6962 sdebug_erase_store(idx, sip);
6963 }
6964 if (apart_from_first)
6965 sdeb_most_recent_idx = sdeb_first_idx;
6966}
6967
6968/*
6969 * Returns store xarray new element index (idx) if >=0 else negated errno.
6970 * Limit the number of stores to 65536.
6971 */
6972static int sdebug_add_store(void)
6973{
6974 int res;
6975 u32 n_idx;
6976 unsigned long iflags;
6977 unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6978 struct sdeb_store_info *sip = NULL;
6979 struct xa_limit xal = { .max = 1 << 16, .min = 0 };
6980
6981 sip = kzalloc(sizeof(*sip), GFP_KERNEL);
6982 if (!sip)
6983 return -ENOMEM;
6984
6985 xa_lock_irqsave(per_store_ap, iflags);
6986 res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
6987 if (unlikely(res < 0)) {
6988 xa_unlock_irqrestore(per_store_ap, iflags);
6989 kfree(sip);
6990 pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
6991 return res;
6992 }
6993 sdeb_most_recent_idx = n_idx;
6994 if (sdeb_first_idx < 0)
6995 sdeb_first_idx = n_idx;
6996 xa_unlock_irqrestore(per_store_ap, iflags);
6997
6998 res = -ENOMEM;
6999 sip->storep = vzalloc(sz);
7000 if (!sip->storep) {
7001 pr_err("user data oom\n");
7002 goto err;
7003 }
7004 if (sdebug_num_parts > 0)
7005 sdebug_build_parts(sip->storep, sz);
7006
7007 /* DIF/DIX: what T10 calls Protection Information (PI) */
7008 if (sdebug_dix) {
7009 int dif_size;
7010
7011 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
7012 sip->dif_storep = vmalloc(dif_size);
7013
7014 pr_info("dif_storep %u bytes @ %pK\n", dif_size,
7015 sip->dif_storep);
7016
7017 if (!sip->dif_storep) {
7018 pr_err("DIX oom\n");
7019 goto err;
7020 }
7021 memset(sip->dif_storep, 0xff, dif_size);
7022 }
7023 /* Logical Block Provisioning */
7024 if (scsi_debug_lbp()) {
7025 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
7026 sip->map_storep = vmalloc(array_size(sizeof(long),
7027 BITS_TO_LONGS(map_size)));
7028
7029 pr_info("%lu provisioning blocks\n", map_size);
7030
7031 if (!sip->map_storep) {
7032 pr_err("LBP map oom\n");
7033 goto err;
7034 }
7035
7036 bitmap_zero(sip->map_storep, map_size);
7037
7038 /* Map first 1KB for partition table */
7039 if (sdebug_num_parts)
7040 map_region(sip, 0, 2);
7041 }
7042
7043 rwlock_init(&sip->macc_lck);
7044 return (int)n_idx;
7045err:
7046 sdebug_erase_store((int)n_idx, sip);
7047 pr_warn("%s: failed, errno=%d\n", __func__, -res);
7048 return res;
7049}
7050
7051static int sdebug_add_host_helper(int per_host_idx)
7052{
7053 int k, devs_per_host, idx;
7054 int error = -ENOMEM;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007055 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007056 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007057
Douglas Gilbert9a051012017-12-23 12:48:10 -05007058 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007059 if (!sdbg_host)
Douglas Gilbert9a051012017-12-23 12:48:10 -05007060 return -ENOMEM;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007061 idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
7062 if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
7063 xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
7064 sdbg_host->si_idx = idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065
Douglas Gilbert9a051012017-12-23 12:48:10 -05007066 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007067
Douglas Gilbert773642d2016-04-25 12:16:28 -04007068 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007069 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09007070 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007071 if (!sdbg_devinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007072 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007074
Douglas Gilbert9a051012017-12-23 12:48:10 -05007075 spin_lock(&sdebug_host_list_lock);
7076 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
7077 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007078
Douglas Gilbert9a051012017-12-23 12:48:10 -05007079 sdbg_host->dev.bus = &pseudo_lld_bus;
7080 sdbg_host->dev.parent = pseudo_primary;
7081 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007082 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007083
Douglas Gilbert9a051012017-12-23 12:48:10 -05007084 error = device_register(&sdbg_host->dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007085 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007086 goto clean;
7087
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007088 ++sdebug_num_hosts;
7089 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090
7091clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007092 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
7093 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007094 list_del(&sdbg_devinfo->dev_list);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09007095 kfree(sdbg_devinfo->zstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007096 kfree(sdbg_devinfo);
7097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098 kfree(sdbg_host);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007099 pr_warn("%s: failed, errno=%d\n", __func__, -error);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007100 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101}
7102
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007103static int sdebug_do_add_host(bool mk_new_store)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007104{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007105 int ph_idx = sdeb_most_recent_idx;
7106
7107 if (mk_new_store) {
7108 ph_idx = sdebug_add_store();
7109 if (ph_idx < 0)
7110 return ph_idx;
7111 }
7112 return sdebug_add_host_helper(ph_idx);
7113}
7114
7115static void sdebug_do_remove_host(bool the_end)
7116{
7117 int idx = -1;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007118 struct sdebug_host_info *sdbg_host = NULL;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007119 struct sdebug_host_info *sdbg_host2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007120
Douglas Gilbert9a051012017-12-23 12:48:10 -05007121 spin_lock(&sdebug_host_list_lock);
7122 if (!list_empty(&sdebug_host_list)) {
7123 sdbg_host = list_entry(sdebug_host_list.prev,
7124 struct sdebug_host_info, host_list);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007125 idx = sdbg_host->si_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007126 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007127 if (!the_end && idx >= 0) {
7128 bool unique = true;
7129
7130 list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
7131 if (sdbg_host2 == sdbg_host)
7132 continue;
7133 if (idx == sdbg_host2->si_idx) {
7134 unique = false;
7135 break;
7136 }
7137 }
7138 if (unique) {
7139 xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
7140 if (idx == sdeb_most_recent_idx)
7141 --sdeb_most_recent_idx;
7142 }
7143 }
7144 if (sdbg_host)
7145 list_del(&sdbg_host->host_list);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007146 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147
7148 if (!sdbg_host)
7149 return;
7150
Douglas Gilbert773642d2016-04-25 12:16:28 -04007151 device_unregister(&sdbg_host->dev);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007152 --sdebug_num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153}
7154
Douglas Gilbertfd321192016-04-25 12:16:33 -04007155static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007156{
7157 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007158 struct sdebug_dev_info *devip;
7159
Douglas Gilbertc4837392016-05-06 00:40:26 -04007160 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007161 devip = (struct sdebug_dev_info *)sdev->hostdata;
7162 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007163 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007164 return -ENODEV;
7165 }
7166 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007167
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007168 if (qdepth > SDEBUG_CANQUEUE) {
7169 qdepth = SDEBUG_CANQUEUE;
7170 pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7171 qdepth, SDEBUG_CANQUEUE);
7172 }
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007173 if (qdepth < 1)
7174 qdepth = 1;
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007175 if (qdepth != sdev->queue_depth)
7176 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007177
Douglas Gilbert773642d2016-04-25 12:16:28 -04007178 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007179 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007180 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007181 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007182 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007183 return sdev->queue_depth;
7184}
7185
Douglas Gilbertc4837392016-05-06 00:40:26 -04007186static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05007187{
Douglas Gilbertc4837392016-05-06 00:40:26 -04007188 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04007189 if (sdebug_every_nth < -1)
7190 sdebug_every_nth = -1;
7191 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04007192 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04007193 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05007194 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04007195 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05007196 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007197 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05007198}
7199
Douglas Gilbertfc136382020-07-24 11:55:31 -04007200/* Response to TUR or media access command when device stopped */
7201static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7202{
7203 int stopped_state;
7204 u64 diff_ns = 0;
7205 ktime_t now_ts = ktime_get_boottime();
7206 struct scsi_device *sdp = scp->device;
7207
7208 stopped_state = atomic_read(&devip->stopped);
7209 if (stopped_state == 2) {
7210 if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7211 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7212 if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7213 /* tur_ms_to_ready timer extinguished */
7214 atomic_set(&devip->stopped, 0);
7215 return 0;
7216 }
7217 }
7218 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7219 if (sdebug_verbose)
7220 sdev_printk(KERN_INFO, sdp,
7221 "%s: Not ready: in process of becoming ready\n", my_name);
7222 if (scp->cmnd[0] == TEST_UNIT_READY) {
7223 u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7224
7225 if (diff_ns <= tur_nanosecs_to_ready)
7226 diff_ns = tur_nanosecs_to_ready - diff_ns;
7227 else
7228 diff_ns = tur_nanosecs_to_ready;
7229 /* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7230 do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */
7231 scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7232 diff_ns);
7233 return check_condition_result;
7234 }
7235 }
7236 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7237 if (sdebug_verbose)
7238 sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7239 my_name);
7240 return check_condition_result;
7241}
7242
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307243static int sdebug_map_queues(struct Scsi_Host *shost)
7244{
7245 int i, qoff;
7246
7247 if (shost->nr_hw_queues == 1)
7248 return 0;
7249
7250 for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7251 struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7252
7253 map->nr_queues = 0;
7254
7255 if (i == HCTX_TYPE_DEFAULT)
7256 map->nr_queues = submit_queues - poll_queues;
7257 else if (i == HCTX_TYPE_POLL)
7258 map->nr_queues = poll_queues;
7259
7260 if (!map->nr_queues) {
7261 BUG_ON(i == HCTX_TYPE_DEFAULT);
7262 continue;
7263 }
7264
7265 map->queue_offset = qoff;
7266 blk_mq_map_queues(map);
7267
7268 qoff += map->nr_queues;
7269 }
7270
7271 return 0;
7272
7273}
7274
7275static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7276{
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307277 bool first;
7278 bool retiring = false;
7279 int num_entries = 0;
7280 unsigned int qc_idx = 0;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307281 unsigned long iflags;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307282 ktime_t kt_from_boot = ktime_get_boottime();
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307283 struct sdebug_queue *sqp;
7284 struct sdebug_queued_cmd *sqcp;
7285 struct scsi_cmnd *scp;
7286 struct sdebug_dev_info *devip;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307287 struct sdebug_defer *sd_dp;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307288
7289 sqp = sdebug_q_arr + queue_num;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307290 spin_lock_irqsave(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307291
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307292 for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) {
7293 if (first) {
7294 qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
7295 first = false;
7296 } else {
7297 qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
7298 }
7299 if (unlikely(qc_idx >= sdebug_max_queue))
7300 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307301
7302 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307303 sd_dp = sqcp->sd_dp;
7304 if (unlikely(!sd_dp))
7305 continue;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307306 scp = sqcp->a_cmnd;
7307 if (unlikely(scp == NULL)) {
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307308 pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307309 queue_num, qc_idx, __func__);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307310 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307311 }
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307312 if (sd_dp->defer_t == SDEB_DEFER_POLL) {
7313 if (kt_from_boot < sd_dp->cmpl_ts)
7314 continue;
7315
7316 } else /* ignoring non REQ_HIPRI requests */
7317 continue;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307318 devip = (struct sdebug_dev_info *)scp->device->hostdata;
7319 if (likely(devip))
7320 atomic_dec(&devip->num_in_q);
7321 else
7322 pr_err("devip=NULL from %s\n", __func__);
7323 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307324 retiring = true;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307325
7326 sqcp->a_cmnd = NULL;
7327 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307328 pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307329 sqp, queue_num, qc_idx, __func__);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307330 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307331 }
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307332 if (unlikely(retiring)) { /* user has reduced max_queue */
7333 int k, retval;
7334
7335 retval = atomic_read(&retired_max_queue);
7336 if (qc_idx >= retval) {
7337 pr_err("index %d too large\n", retval);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307338 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307339 }
7340 k = find_last_bit(sqp->in_use_bm, retval);
7341 if ((k < sdebug_max_queue) || (k == retval))
7342 atomic_set(&retired_max_queue, 0);
7343 else
7344 atomic_set(&retired_max_queue, k + 1);
7345 }
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307346 sd_dp->defer_t = SDEB_DEFER_NONE;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307347 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
7348 scp->scsi_done(scp); /* callback to mid level */
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307349 spin_lock_irqsave(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307350 num_entries++;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307351 }
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307352 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307353 if (num_entries > 0)
7354 atomic_add(num_entries, &sdeb_mq_poll_count);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307355 return num_entries;
7356}
7357
Douglas Gilbertfd321192016-04-25 12:16:33 -04007358static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7359 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007360{
7361 u8 sdeb_i;
7362 struct scsi_device *sdp = scp->device;
7363 const struct opcode_info_t *oip;
7364 const struct opcode_info_t *r_oip;
7365 struct sdebug_dev_info *devip;
7366 u8 *cmd = scp->cmnd;
7367 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
Martin Wilckf66b8512018-02-14 11:05:57 +01007368 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007369 int k, na;
7370 int errsts = 0;
Douglas Gilbertad0c7772020-08-21 00:22:49 -04007371 u64 lun_index = sdp->lun & 0x3FFF;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007372 u32 flags;
7373 u16 sa;
7374 u8 opcode = cmd[0];
7375 bool has_wlun_rl;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007376 bool inject_now;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007377
7378 scsi_set_resid(scp, 0);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007379 if (sdebug_statistics) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007380 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007381 inject_now = inject_on_this_cmd();
7382 } else {
7383 inject_now = false;
7384 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007385 if (unlikely(sdebug_verbose &&
7386 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007387 char b[120];
7388 int n, len, sb;
7389
7390 len = scp->cmd_len;
7391 sb = (int)sizeof(b);
7392 if (len > 32)
7393 strcpy(b, "too long, over 32 bytes");
7394 else {
7395 for (k = 0, n = 0; k < len && n < sb; ++k)
7396 n += scnprintf(b + n, sb - n, "%02x ",
7397 (u32)cmd[k]);
7398 }
Bart Van Assche458df782018-01-26 08:52:19 -08007399 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7400 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007401 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007402 if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08007403 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03007404 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04007405 if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007406 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007407
7408 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
7409 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
7410 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007411 if (unlikely(!devip)) {
7412 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007413 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007414 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007415 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007416 if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
7417 atomic_set(&sdeb_inject_pending, 1);
7418
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007419 na = oip->num_attached;
7420 r_pfp = oip->pfp;
7421 if (na) { /* multiple commands with this opcode */
7422 r_oip = oip;
7423 if (FF_SA & r_oip->flags) {
7424 if (F_SA_LOW & oip->flags)
7425 sa = 0x1f & cmd[1];
7426 else
7427 sa = get_unaligned_be16(cmd + 8);
7428 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7429 if (opcode == oip->opcode && sa == oip->sa)
7430 break;
7431 }
7432 } else { /* since no service action only check opcode */
7433 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7434 if (opcode == oip->opcode)
7435 break;
7436 }
7437 }
7438 if (k > na) {
7439 if (F_SA_LOW & r_oip->flags)
7440 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7441 else if (F_SA_HIGH & r_oip->flags)
7442 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7443 else
7444 mk_sense_invalid_opcode(scp);
7445 goto check_cond;
7446 }
7447 } /* else (when na==0) we assume the oip is a match */
7448 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007449 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007450 mk_sense_invalid_opcode(scp);
7451 goto check_cond;
7452 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007453 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04007454 if (sdebug_verbose)
7455 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7456 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007457 mk_sense_invalid_opcode(scp);
7458 goto check_cond;
7459 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007460 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007461 u8 rem;
7462 int j;
7463
7464 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7465 rem = ~oip->len_mask[k] & cmd[k];
7466 if (rem) {
7467 for (j = 7; j >= 0; --j, rem <<= 1) {
7468 if (0x80 & rem)
7469 break;
7470 }
7471 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7472 goto check_cond;
7473 }
7474 }
7475 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007476 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04007477 find_first_bit(devip->uas_bm,
7478 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007479 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007480 if (errsts)
7481 goto check_cond;
7482 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04007483 if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7484 atomic_read(&devip->stopped))) {
7485 errsts = resp_not_ready(scp, devip);
7486 if (errsts)
7487 goto fini;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007488 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04007489 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007490 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007491 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007492 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007493 return 0; /* ignore command: make trouble */
7494 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007495 if (likely(oip->pfp))
Martin Wilckf66b8512018-02-14 11:05:57 +01007496 pfp = oip->pfp; /* calls a resp_* function */
7497 else
7498 pfp = r_pfp; /* if leaf function ptr NULL, try the root's */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007499
7500fini:
Douglas Gilbert67da4132020-04-21 11:14:20 -04007501 if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */
Martin Wilckf66b8512018-02-14 11:05:57 +01007502 return schedule_resp(scp, devip, errsts, pfp, 0, 0);
Douglas Gilbert75aa3202018-07-12 13:35:42 -04007503 else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
7504 sdebug_ndelay > 10000)) {
Douglas Gilbert80c49562018-02-09 21:36:39 -05007505 /*
Douglas Gilbert75aa3202018-07-12 13:35:42 -04007506 * Skip long delays if ndelay <= 10 microseconds. Otherwise
7507 * for Start Stop Unit (SSU) want at least 1 second delay and
7508 * if sdebug_jdelay>1 want a long delay of that many seconds.
7509 * For Synchronize Cache want 1/20 of SSU's delay.
Douglas Gilbert80c49562018-02-09 21:36:39 -05007510 */
7511 int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04007512 int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
Douglas Gilbert80c49562018-02-09 21:36:39 -05007513
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04007514 jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
Martin Wilckf66b8512018-02-14 11:05:57 +01007515 return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05007516 } else
Martin Wilckf66b8512018-02-14 11:05:57 +01007517 return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
Douglas Gilbert10bde982018-01-10 16:57:31 -05007518 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007519check_cond:
Martin Wilckf66b8512018-02-14 11:05:57 +01007520 return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007521err_out:
Martin Wilckf66b8512018-02-14 11:05:57 +01007522 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007523}
7524
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007525static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04007526 .show_info = scsi_debug_show_info,
7527 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007528 .proc_name = sdebug_proc_name,
7529 .name = "SCSI DEBUG",
7530 .info = scsi_debug_info,
7531 .slave_alloc = scsi_debug_slave_alloc,
7532 .slave_configure = scsi_debug_slave_configure,
7533 .slave_destroy = scsi_debug_slave_destroy,
7534 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04007535 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007536 .change_queue_depth = sdebug_change_qdepth,
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307537 .map_queues = sdebug_map_queues,
7538 .mq_poll = sdebug_blk_mq_poll,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007539 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007540 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007541 .eh_target_reset_handler = scsi_debug_target_reset,
7542 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007543 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04007544 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007545 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07007546 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007547 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09007548 .max_sectors = -1U,
Christoph Hellwig50c2e912018-12-13 16:17:03 +01007549 .max_segment_size = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007550 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007551 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007552};
7553
John Pittman91d4c752018-02-09 21:12:43 -05007554static int sdebug_driver_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007555{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05007556 int error = 0;
7557 struct sdebug_host_info *sdbg_host;
7558 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007559 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007560
7561 sdbg_host = to_sdebug_host(dev);
7562
John Garryf7c4cdc2020-08-19 23:20:33 +08007563 sdebug_driver_template.can_queue = sdebug_max_queue;
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007564 sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
Christoph Hellwig2a3d4eb2018-12-13 16:17:02 +01007565 if (!sdebug_clustering)
Christoph Hellwig4af14d12018-12-13 16:17:09 +01007566 sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
7567
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007568 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
7569 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007570 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007571 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007572 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007573 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007574 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07007575 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04007576 my_name, submit_queues, nr_cpu_ids);
7577 submit_queues = nr_cpu_ids;
7578 }
John Garryc10fa552020-07-09 20:23:20 +08007579 /*
7580 * Decide whether to tell scsi subsystem that we want mq. The
John Garryf7c4cdc2020-08-19 23:20:33 +08007581 * following should give the same answer for each host.
John Garryc10fa552020-07-09 20:23:20 +08007582 */
John Garryf7c4cdc2020-08-19 23:20:33 +08007583 hpnt->nr_hw_queues = submit_queues;
7584 if (sdebug_host_max_queue)
7585 hpnt->host_tagset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007586
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307587 /* poll queues are possible for nr_hw_queues > 1 */
7588 if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7589 pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7590 my_name, poll_queues, hpnt->nr_hw_queues);
7591 poll_queues = 0;
7592 }
7593
7594 /*
7595 * Poll queues don't need interrupts, but we need at least one I/O queue
7596 * left over for non-polled I/O.
7597 * If condition not met, trim poll_queues to 1 (just for simplicity).
7598 */
7599 if (poll_queues >= submit_queues) {
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007600 if (submit_queues < 3)
7601 pr_warn("%s: trim poll_queues to 1\n", my_name);
7602 else
7603 pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7604 my_name, submit_queues - 1);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307605 poll_queues = 1;
7606 }
7607 if (poll_queues)
7608 hpnt->nr_maps = 3;
7609
Douglas Gilbert9a051012017-12-23 12:48:10 -05007610 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007611 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007612 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7613 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007614 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04007615 hpnt->max_id = sdebug_num_tgts;
7616 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03007617 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007618
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007619 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007620
Douglas Gilbert773642d2016-04-25 12:16:28 -04007621 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007622
Christoph Hellwig8475c812016-09-11 19:35:41 +02007623 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007624 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007625 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007626 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007627 break;
7628
Christoph Hellwig8475c812016-09-11 19:35:41 +02007629 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007630 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007631 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007632 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007633 break;
7634
Christoph Hellwig8475c812016-09-11 19:35:41 +02007635 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007636 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007637 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007638 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007639 break;
7640
7641 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04007642 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007643 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007644 break;
7645 }
7646
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007647 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007648
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007649 if (have_dif_prot || sdebug_dix)
7650 pr_info("host protection%s%s%s%s%s%s%s\n",
7651 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7652 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7653 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7654 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7655 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7656 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7657 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007658
Douglas Gilbert773642d2016-04-25 12:16:28 -04007659 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007660 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7661 else
7662 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7663
Douglas Gilbert773642d2016-04-25 12:16:28 -04007664 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7665 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04007666 if (sdebug_every_nth) /* need stats counters for every_nth */
7667 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007668 error = scsi_add_host(hpnt, &sdbg_host->dev);
7669 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007670 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05007671 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007672 scsi_host_put(hpnt);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007673 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674 scsi_scan_host(hpnt);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007676
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007677 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678}
7679
John Pittman91d4c752018-02-09 21:12:43 -05007680static int sdebug_driver_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007681{
Douglas Gilbert9a051012017-12-23 12:48:10 -05007682 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007683 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684
7685 sdbg_host = to_sdebug_host(dev);
7686
7687 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007688 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007689 return -ENODEV;
7690 }
7691
Douglas Gilbert9a051012017-12-23 12:48:10 -05007692 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007693
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007694 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
7695 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05007696 list_del(&sdbg_devinfo->dev_list);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09007697 kfree(sdbg_devinfo->zstate);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007698 kfree(sdbg_devinfo);
7699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007700
Douglas Gilbert9a051012017-12-23 12:48:10 -05007701 scsi_host_put(sdbg_host->shost);
7702 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703}
7704
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007705static int pseudo_lld_bus_match(struct device *dev,
7706 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007708 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007709}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007710
7711static struct bus_type pseudo_lld_bus = {
7712 .name = "pseudo",
7713 .match = pseudo_lld_bus_match,
7714 .probe = sdebug_driver_probe,
7715 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09007716 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007717};