blob: 58f69366bdccc3dfc2ef54613899297ec3bc5344 [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 =
Hannes Reinecke464a00c2021-04-27 10:30:15 +0200854 SAM_STAT_CHECK_CONDITION;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500856static const int illegal_condition_result =
Hannes Reinecke464a00c2021-04-27 10:30:15 +0200857 (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500858
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);
Hannes Reineckef2b1e9c2021-04-27 10:30:13 +0200934 scsi_build_sense(scp, sdebug_dsense, 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{
Hannes Reineckef2b1e9c2021-04-27 10:30:13 +0200960 if (!scp->sense_buffer) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400961 sdev_printk(KERN_ERR, scp->device,
962 "%s: sense_buffer is NULL\n", __func__);
963 return;
964 }
Hannes Reineckef2b1e9c2021-04-27 10:30:13 +0200965 memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900966
Hannes Reineckef2b1e9c2021-04-27 10:30:13 +0200967 scsi_build_sense(scp, sdebug_dsense, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900968
Douglas Gilbert773642d2016-04-25 12:16:28 -0400969 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400970 sdev_printk(KERN_INFO, scp->device,
971 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
972 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900973}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Douglas Gilbertfd321192016-04-25 12:16:33 -0400975static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500976{
977 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
978}
979
Nathan Chancellor6f4e6262019-02-07 09:07:20 -0700980static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
981 void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400983 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400984 if (0x1261 == cmd)
985 sdev_printk(KERN_INFO, dev,
986 "%s: BLKFLSBUF [0x1261]\n", __func__);
987 else if (0x5331 == cmd)
988 sdev_printk(KERN_INFO, dev,
989 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
990 __func__);
991 else
992 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
993 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 }
995 return -EINVAL;
996 /* return -ENOTTY; // correct return but upsets fdisk */
997}
998
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500999static void config_cdb_len(struct scsi_device *sdev)
1000{
1001 switch (sdebug_cdb_len) {
1002 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
1003 sdev->use_10_for_rw = false;
1004 sdev->use_16_for_rw = false;
1005 sdev->use_10_for_ms = false;
1006 break;
1007 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
1008 sdev->use_10_for_rw = true;
1009 sdev->use_16_for_rw = false;
1010 sdev->use_10_for_ms = false;
1011 break;
1012 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
1013 sdev->use_10_for_rw = true;
1014 sdev->use_16_for_rw = false;
1015 sdev->use_10_for_ms = true;
1016 break;
1017 case 16:
1018 sdev->use_10_for_rw = false;
1019 sdev->use_16_for_rw = true;
1020 sdev->use_10_for_ms = true;
1021 break;
1022 case 32: /* No knobs to suggest this so same as 16 for now */
1023 sdev->use_10_for_rw = false;
1024 sdev->use_16_for_rw = true;
1025 sdev->use_10_for_ms = true;
1026 break;
1027 default:
1028 pr_warn("unexpected cdb_len=%d, force to 10\n",
1029 sdebug_cdb_len);
1030 sdev->use_10_for_rw = true;
1031 sdev->use_16_for_rw = false;
1032 sdev->use_10_for_ms = false;
1033 sdebug_cdb_len = 10;
1034 break;
1035 }
1036}
1037
1038static void all_config_cdb_len(void)
1039{
1040 struct sdebug_host_info *sdbg_host;
1041 struct Scsi_Host *shost;
1042 struct scsi_device *sdev;
1043
1044 spin_lock(&sdebug_host_list_lock);
1045 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1046 shost = sdbg_host->shost;
1047 shost_for_each_device(sdev, shost) {
1048 config_cdb_len(sdev);
1049 }
1050 }
1051 spin_unlock(&sdebug_host_list_lock);
1052}
1053
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001054static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
1055{
1056 struct sdebug_host_info *sdhp;
1057 struct sdebug_dev_info *dp;
1058
1059 spin_lock(&sdebug_host_list_lock);
1060 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
1061 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
1062 if ((devip->sdbg_host == dp->sdbg_host) &&
1063 (devip->target == dp->target))
1064 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
1065 }
1066 }
1067 spin_unlock(&sdebug_host_list_lock);
1068}
1069
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001070static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001072 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001073
1074 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
1075 if (k != SDEBUG_NUM_UAS) {
1076 const char *cp = NULL;
1077
1078 switch (k) {
1079 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001080 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1081 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001082 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001083 cp = "power on reset";
1084 break;
1085 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001086 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
1087 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001088 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001089 cp = "bus reset";
1090 break;
1091 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001092 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1093 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001094 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001095 cp = "mode parameters changed";
1096 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05001097 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001098 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
1099 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001100 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05001101 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -05001102 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001103 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001104 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001105 TARGET_CHANGED_ASC,
1106 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001107 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001108 cp = "microcode has been changed";
1109 break;
1110 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001111 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001112 TARGET_CHANGED_ASC,
1113 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001114 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05001115 cp = "microcode has been changed without reset";
1116 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001117 case SDEBUG_UA_LUNS_CHANGED:
1118 /*
1119 * SPC-3 behavior is to report a UNIT ATTENTION with
1120 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
1121 * on the target, until a REPORT LUNS command is
1122 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -04001123 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001124 * values as struct scsi_device->scsi_level.
1125 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001126 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001127 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001128 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001129 TARGET_CHANGED_ASC,
1130 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001131 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05001132 cp = "reported luns data has changed";
1133 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001134 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04001135 pr_warn("unexpected unit attention code=%d\n", k);
1136 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001137 cp = "unknown";
1138 break;
1139 }
1140 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001141 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001142 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001143 "%s reports: Unit attention: %s\n",
1144 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 return check_condition_result;
1146 }
1147 return 0;
1148}
1149
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001150/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001151static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 int arr_len)
1153{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001154 int act_len;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001155 struct scsi_data_buffer *sdb = &scp->sdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001157 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001159 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbert773642d2016-04-25 12:16:28 -04001160 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001161
1162 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
1163 arr, arr_len);
Bart Van Assche42d387b2019-02-08 13:25:00 -08001164 scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001165
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 return 0;
1167}
1168
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001169/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1170 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1171 * calls, not required to write in ascending offset order. Assumes resid
1172 * set to scsi_bufflen() prior to any calls.
1173 */
1174static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1175 int arr_len, unsigned int off_dst)
1176{
Damien Le Moal9237f042019-10-30 18:08:47 +09001177 unsigned int act_len, n;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001178 struct scsi_data_buffer *sdb = &scp->sdb;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001179 off_t skip = off_dst;
1180
1181 if (sdb->length <= off_dst)
1182 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001183 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001184 return DID_ERROR << 16;
1185
1186 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1187 arr, arr_len, skip);
1188 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
Bart Van Assche42d387b2019-02-08 13:25:00 -08001189 __func__, off_dst, scsi_bufflen(scp), act_len,
1190 scsi_get_resid(scp));
Damien Le Moal9237f042019-10-30 18:08:47 +09001191 n = scsi_bufflen(scp) - (off_dst + act_len);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001192 scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n));
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001193 return 0;
1194}
1195
1196/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1197 * 'arr' or -1 if error.
1198 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001199static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1200 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001202 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001204 if (scp->sc_data_direction != DMA_TO_DEVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001206
1207 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208}
1209
1210
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001211static char sdebug_inq_vendor_id[9] = "Linux ";
1212static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001213static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001214/* Use some locally assigned NAAs for SAS addresses. */
1215static const u64 naa3_comp_a = 0x3222222000000000ULL;
1216static const u64 naa3_comp_b = 0x3333333000000000ULL;
1217static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001219/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001220static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1221 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001222 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001223 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001225 int num, port_a;
1226 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001228 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 /* T10 vendor identifier field format (faked) */
1230 arr[0] = 0x2; /* ASCII */
1231 arr[1] = 0x1;
1232 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001233 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1234 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1236 num = 8 + 16 + dev_id_str_len;
1237 arr[3] = num;
1238 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001239 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001240 if (sdebug_uuid_ctl) {
1241 /* Locally assigned UUID */
1242 arr[num++] = 0x1; /* binary (not necessarily sas) */
1243 arr[num++] = 0xa; /* PIV=0, lu, naa */
1244 arr[num++] = 0x0;
1245 arr[num++] = 0x12;
1246 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1247 arr[num++] = 0x0;
1248 memcpy(arr + num, lu_name, 16);
1249 num += 16;
1250 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001251 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001252 arr[num++] = 0x1; /* binary (not necessarily sas) */
1253 arr[num++] = 0x3; /* PIV=0, lu, naa */
1254 arr[num++] = 0x0;
1255 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001256 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001257 num += 8;
1258 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001259 /* Target relative port number */
1260 arr[num++] = 0x61; /* proto=sas, binary */
1261 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1262 arr[num++] = 0x0; /* reserved */
1263 arr[num++] = 0x4; /* length */
1264 arr[num++] = 0x0; /* reserved */
1265 arr[num++] = 0x0; /* reserved */
1266 arr[num++] = 0x0;
1267 arr[num++] = 0x1; /* relative port A */
1268 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001269 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001270 arr[num++] = 0x61; /* proto=sas, binary */
1271 arr[num++] = 0x93; /* piv=1, target port, naa */
1272 arr[num++] = 0x0;
1273 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001274 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001275 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001276 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001277 arr[num++] = 0x61; /* proto=sas, binary */
1278 arr[num++] = 0x95; /* piv=1, target port group id */
1279 arr[num++] = 0x0;
1280 arr[num++] = 0x4;
1281 arr[num++] = 0;
1282 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001283 put_unaligned_be16(port_group_id, arr + num);
1284 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001285 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001286 arr[num++] = 0x61; /* proto=sas, binary */
1287 arr[num++] = 0xa3; /* piv=1, target device, naa */
1288 arr[num++] = 0x0;
1289 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001290 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001291 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001292 /* SCSI name string: Target device identifier */
1293 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1294 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1295 arr[num++] = 0x0;
1296 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001297 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001298 num += 12;
1299 snprintf(b, sizeof(b), "%08X", target_dev_id);
1300 memcpy(arr + num, b, 8);
1301 num += 8;
1302 memset(arr + num, 0, 4);
1303 num += 4;
1304 return num;
1305}
1306
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001307static unsigned char vpd84_data[] = {
1308/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1309 0x22,0x22,0x22,0x0,0xbb,0x1,
1310 0x22,0x22,0x22,0x0,0xbb,0x2,
1311};
1312
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001313/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001314static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001315{
1316 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1317 return sizeof(vpd84_data);
1318}
1319
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001320/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001321static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001322{
1323 int num = 0;
John Pittman91d4c752018-02-09 21:12:43 -05001324 const char *na1 = "https://www.kernel.org/config";
1325 const char *na2 = "http://www.kernel.org/log";
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001326 int plen, olen;
1327
1328 arr[num++] = 0x1; /* lu, storage config */
1329 arr[num++] = 0x0; /* reserved */
1330 arr[num++] = 0x0;
1331 olen = strlen(na1);
1332 plen = olen + 1;
1333 if (plen % 4)
1334 plen = ((plen / 4) + 1) * 4;
1335 arr[num++] = plen; /* length, null termianted, padded */
1336 memcpy(arr + num, na1, olen);
1337 memset(arr + num + olen, 0, plen - olen);
1338 num += plen;
1339
1340 arr[num++] = 0x4; /* lu, logging */
1341 arr[num++] = 0x0; /* reserved */
1342 arr[num++] = 0x0;
1343 olen = strlen(na2);
1344 plen = olen + 1;
1345 if (plen % 4)
1346 plen = ((plen / 4) + 1) * 4;
1347 arr[num++] = plen; /* length, null terminated, padded */
1348 memcpy(arr + num, na2, olen);
1349 memset(arr + num + olen, 0, plen - olen);
1350 num += plen;
1351
1352 return num;
1353}
1354
1355/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001356static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001357{
1358 int num = 0;
1359 int port_a, port_b;
1360
1361 port_a = target_dev_id + 1;
1362 port_b = port_a + 1;
1363 arr[num++] = 0x0; /* reserved */
1364 arr[num++] = 0x0; /* reserved */
1365 arr[num++] = 0x0;
1366 arr[num++] = 0x1; /* relative port 1 (primary) */
1367 memset(arr + num, 0, 6);
1368 num += 6;
1369 arr[num++] = 0x0;
1370 arr[num++] = 12; /* length tp descriptor */
1371 /* naa-5 target port identifier (A) */
1372 arr[num++] = 0x61; /* proto=sas, binary */
1373 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1374 arr[num++] = 0x0; /* reserved */
1375 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001376 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001377 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001378 arr[num++] = 0x0; /* reserved */
1379 arr[num++] = 0x0; /* reserved */
1380 arr[num++] = 0x0;
1381 arr[num++] = 0x2; /* relative port 2 (secondary) */
1382 memset(arr + num, 0, 6);
1383 num += 6;
1384 arr[num++] = 0x0;
1385 arr[num++] = 12; /* length tp descriptor */
1386 /* naa-5 target port identifier (B) */
1387 arr[num++] = 0x61; /* proto=sas, binary */
1388 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1389 arr[num++] = 0x0; /* reserved */
1390 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001391 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001392 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001393
1394 return num;
1395}
1396
1397
1398static unsigned char vpd89_data[] = {
1399/* from 4th byte */ 0,0,0,0,
1400'l','i','n','u','x',' ',' ',' ',
1401'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1402'1','2','3','4',
14030x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
14040xec,0,0,0,
14050x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
14060,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
14070x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
14080x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
14090x53,0x41,
14100x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
14110x20,0x20,
14120x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
14130x10,0x80,
14140,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
14150x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
14160x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
14170,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
14180x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
14190x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
14200,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
14210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14240x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
14250,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
14260xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
14270,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
14280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14370,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14380,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14390,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1440};
1441
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001442/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001443static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001444{
1445 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1446 return sizeof(vpd89_data);
1447}
1448
1449
1450static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001451 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1452 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1453 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1454 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001455};
1456
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001457/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001458static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001459{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001460 unsigned int gran;
1461
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001463
1464 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001465 if (sdebug_opt_xferlen_exp != 0 &&
1466 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1467 gran = 1 << sdebug_opt_xferlen_exp;
1468 else
1469 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001470 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001471
1472 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001473 if (sdebug_store_sectors > 0x400)
1474 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001475
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001476 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001477 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001478
Douglas Gilbert773642d2016-04-25 12:16:28 -04001479 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001480 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001481 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001482
1483 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001484 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001485 }
1486
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001487 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001488 if (sdebug_unmap_alignment) {
1489 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001490 arr[28] |= 0x80; /* UGAVALID */
1491 }
1492
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001493 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001494 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001495
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001496 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001497 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001498
1499 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001500
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001501 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502}
1503
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001504/* Block device characteristics VPD page (SBC-3) */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001505static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001506{
1507 memset(arr, 0, 0x3c);
1508 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001509 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1510 arr[2] = 0;
1511 arr[3] = 5; /* less than 1.8" */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001512 if (devip->zmodel == BLK_ZONED_HA)
1513 arr[4] = 1 << 4; /* zoned field = 01b */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001514
1515 return 0x3c;
1516}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001518/* Logical block provisioning VPD page (SBC-4) */
1519static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001520{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001521 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001522 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001523 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001524 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001525 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001526 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001527 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001528 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001529 if (sdebug_lbprz && scsi_debug_lbp())
1530 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1531 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1532 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1533 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001534 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001535}
1536
Douglas Gilbertd36da302020-04-22 19:42:15 +09001537/* Zoned block device characteristics VPD page (ZBC mandatory) */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001538static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
Douglas Gilbertd36da302020-04-22 19:42:15 +09001539{
1540 memset(arr, 0, 0x3c);
1541 arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
1542 /*
1543 * Set Optimal number of open sequential write preferred zones and
1544 * Optimal number of non-sequentially written sequential write
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001545 * preferred zones fields to 'not reported' (0xffffffff). Leave other
1546 * fields set to zero, apart from Max. number of open swrz_s field.
Douglas Gilbertd36da302020-04-22 19:42:15 +09001547 */
1548 put_unaligned_be32(0xffffffff, &arr[4]);
1549 put_unaligned_be32(0xffffffff, &arr[8]);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001550 if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001551 put_unaligned_be32(devip->max_open, &arr[12]);
1552 else
1553 put_unaligned_be32(0xffffffff, &arr[12]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001554 return 0x3c;
1555}
1556
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001558#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001560static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561{
1562 unsigned char pq_pdt;
John Pittman91d4c752018-02-09 21:12:43 -05001563 unsigned char *arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001564 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001565 int alloc_len, n, ret;
Douglas Gilbertd36da302020-04-22 19:42:15 +09001566 bool have_wlun, is_disk, is_zbc, is_disk_zbc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Douglas Gilbert773642d2016-04-25 12:16:28 -04001568 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001569 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1570 if (! arr)
1571 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001572 is_disk = (sdebug_ptype == TYPE_DISK);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001573 is_zbc = (devip->zmodel != BLK_ZONED_NONE);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001574 is_disk_zbc = (is_disk || is_zbc);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001575 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001576 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001577 pq_pdt = TYPE_WLUN; /* present, wlun */
1578 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1579 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001580 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001581 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 arr[0] = pq_pdt;
1583 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001584 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001585 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 return check_condition_result;
1587 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001588 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001589 char lu_id_str[6];
1590 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001592 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1593 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001594 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001595 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001596 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001597 (devip->target * 1000) + devip->lun);
1598 target_dev_id = ((host_no + 1) * 2000) +
1599 (devip->target * 1000) - 3;
1600 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001602 arr[1] = cmd[2]; /*sanity */
1603 n = 4;
1604 arr[n++] = 0x0; /* this page */
1605 arr[n++] = 0x80; /* unit serial number */
1606 arr[n++] = 0x83; /* device identification */
1607 arr[n++] = 0x84; /* software interface ident. */
1608 arr[n++] = 0x85; /* management network addresses */
1609 arr[n++] = 0x86; /* extended inquiry */
1610 arr[n++] = 0x87; /* mode page policy */
1611 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbertd36da302020-04-22 19:42:15 +09001612 if (is_disk_zbc) { /* SBC or ZBC */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001613 arr[n++] = 0x89; /* ATA information */
1614 arr[n++] = 0xb0; /* Block limits */
1615 arr[n++] = 0xb1; /* Block characteristics */
Douglas Gilbertd36da302020-04-22 19:42:15 +09001616 if (is_disk)
1617 arr[n++] = 0xb2; /* LB Provisioning */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001618 if (is_zbc)
Douglas Gilbertd36da302020-04-22 19:42:15 +09001619 arr[n++] = 0xb6; /* ZB dev. char. */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001620 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001621 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001623 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001625 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001628 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1629 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001630 lu_id_str, len,
1631 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001632 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1633 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001634 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001635 } else if (0x85 == cmd[2]) { /* Management network addresses */
1636 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001637 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001638 } else if (0x86 == cmd[2]) { /* extended inquiry */
1639 arr[1] = cmd[2]; /*sanity */
1640 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001641 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001642 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001643 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001644 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1645 else
1646 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001647 arr[5] = 0x7; /* head of q, ordered + simple q's */
1648 } else if (0x87 == cmd[2]) { /* mode page policy */
1649 arr[1] = cmd[2]; /*sanity */
1650 arr[3] = 0x8; /* number of following entries */
1651 arr[4] = 0x2; /* disconnect-reconnect mp */
1652 arr[6] = 0x80; /* mlus, shared */
1653 arr[8] = 0x18; /* protocol specific lu */
1654 arr[10] = 0x82; /* mlus, per initiator port */
1655 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1656 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001657 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001658 } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001659 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001660 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001661 put_unaligned_be16(n, arr + 2);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001662 } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001663 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001664 arr[3] = inquiry_vpd_b0(&arr[4]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001665 } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001666 arr[1] = cmd[2]; /*sanity */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09001667 arr[3] = inquiry_vpd_b1(devip, &arr[4]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001668 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001669 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001670 arr[3] = inquiry_vpd_b2(&arr[4]);
Douglas Gilbertd36da302020-04-22 19:42:15 +09001671 } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
1672 arr[1] = cmd[2]; /*sanity */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09001673 arr[3] = inquiry_vpd_b6(devip, &arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001675 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001676 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 return check_condition_result;
1678 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001679 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001680 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001681 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001682 kfree(arr);
1683 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 }
1685 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001686 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1687 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 arr[3] = 2; /* response_data_format==2 */
1689 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001690 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001691 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001692 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001693 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001695 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001696 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1697 memcpy(&arr[16], sdebug_inq_product_id, 16);
1698 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001699 /* Use Vendor Specific area to place driver date in ASCII hex */
1700 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001702 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1703 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001704 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001705 if (is_disk) { /* SBC-4 no version claimed */
1706 put_unaligned_be16(0x600, arr + n);
1707 n += 2;
1708 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1709 put_unaligned_be16(0x525, arr + n);
1710 n += 2;
Douglas Gilbertd36da302020-04-22 19:42:15 +09001711 } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */
1712 put_unaligned_be16(0x624, arr + n);
1713 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001715 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001716 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001717 min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001718 kfree(arr);
1719 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720}
1721
Douglas Gilbert84905d32020-07-23 15:48:19 -04001722/* See resp_iec_m_pg() for how this data is manipulated */
Douglas Gilbertfd321192016-04-25 12:16:33 -04001723static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1724 0, 0, 0x0, 0x0};
1725
John Pittman91d4c752018-02-09 21:12:43 -05001726static int resp_requests(struct scsi_cmnd *scp,
1727 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001729 unsigned char *cmd = scp->cmnd;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001730 unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */
1731 bool dsense = !!(cmd[1] & 1);
1732 int alloc_len = cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 int len = 18;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001734 int stopped_state = atomic_read(&devip->stopped);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001736 memset(arr, 0, sizeof(arr));
Douglas Gilbert84905d32020-07-23 15:48:19 -04001737 if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */
1738 if (dsense) {
1739 arr[0] = 0x72;
1740 arr[1] = NOT_READY;
1741 arr[2] = LOGICAL_UNIT_NOT_READY;
1742 arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
1743 len = 8;
1744 } else {
1745 arr[0] = 0x70;
1746 arr[2] = NOT_READY; /* NO_SENSE in sense_key */
1747 arr[7] = 0xa; /* 18 byte sense buffer */
1748 arr[12] = LOGICAL_UNIT_NOT_READY;
1749 arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
1750 }
1751 } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1752 /* Information exceptions control mode page: TEST=1, MRIE=6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001753 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001754 arr[0] = 0x72;
1755 arr[1] = 0x0; /* NO_SENSE in sense_key */
1756 arr[2] = THRESHOLD_EXCEEDED;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001757 arr[3] = 0xff; /* Failure prediction(false) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001758 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001759 } else {
1760 arr[0] = 0x70;
1761 arr[2] = 0x0; /* NO_SENSE in sense_key */
1762 arr[7] = 0xa; /* 18 byte sense buffer */
1763 arr[12] = THRESHOLD_EXCEEDED;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001764 arr[13] = 0xff; /* Failure prediction(false) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001765 }
Douglas Gilbert84905d32020-07-23 15:48:19 -04001766 } else { /* nothing to report */
1767 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001768 len = 8;
Douglas Gilbert84905d32020-07-23 15:48:19 -04001769 memset(arr, 0, len);
1770 arr[0] = 0x72;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001771 } else {
Douglas Gilbert84905d32020-07-23 15:48:19 -04001772 memset(arr, 0, len);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001773 arr[0] = 0x70;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001774 arr[7] = 0xa;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001775 }
1776 }
Douglas Gilbert84905d32020-07-23 15:48:19 -04001777 return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778}
1779
Douglas Gilbertfc136382020-07-24 11:55:31 -04001780static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001781{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001782 unsigned char *cmd = scp->cmnd;
Douglas Gilbertfc136382020-07-24 11:55:31 -04001783 int power_cond, want_stop, stopped_state;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001784 bool changing;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001785
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001786 power_cond = (cmd[4] & 0xf0) >> 4;
1787 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001788 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001789 return check_condition_result;
1790 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04001791 want_stop = !(cmd[4] & 1);
1792 stopped_state = atomic_read(&devip->stopped);
1793 if (stopped_state == 2) {
1794 ktime_t now_ts = ktime_get_boottime();
1795
1796 if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
1797 u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
1798
1799 if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
1800 /* tur_ms_to_ready timer extinguished */
1801 atomic_set(&devip->stopped, 0);
1802 stopped_state = 0;
1803 }
1804 }
1805 if (stopped_state == 2) {
1806 if (want_stop) {
1807 stopped_state = 1; /* dummy up success */
1808 } else { /* Disallow tur_ms_to_ready delay to be overridden */
1809 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
1810 return check_condition_result;
1811 }
1812 }
1813 }
1814 changing = (stopped_state != want_stop);
1815 if (changing)
1816 atomic_xchg(&devip->stopped, want_stop);
1817 if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001818 return SDEG_RES_IMMED_MASK;
1819 else
1820 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001821}
1822
FUJITA Tomonori28898872008-03-30 00:59:55 +09001823static sector_t get_sdebug_capacity(void)
1824{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001825 static const unsigned int gibibyte = 1073741824;
1826
1827 if (sdebug_virtual_gb > 0)
1828 return (sector_t)sdebug_virtual_gb *
1829 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001830 else
1831 return sdebug_store_sectors;
1832}
1833
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834#define SDEBUG_READCAP_ARR_SZ 8
John Pittman91d4c752018-02-09 21:12:43 -05001835static int resp_readcap(struct scsi_cmnd *scp,
1836 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837{
1838 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001839 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001841 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001842 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001844 if (sdebug_capacity < 0xffffffff) {
1845 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001846 put_unaligned_be32(capac, arr + 0);
1847 } else
1848 put_unaligned_be32(0xffffffff, arr + 0);
1849 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1851}
1852
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001853#define SDEBUG_READCAP16_ARR_SZ 32
John Pittman91d4c752018-02-09 21:12:43 -05001854static int resp_readcap16(struct scsi_cmnd *scp,
1855 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001856{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001857 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001858 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001859 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001860
Douglas Gilbert773642d2016-04-25 12:16:28 -04001861 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001862 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001863 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001864 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001865 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1866 put_unaligned_be32(sdebug_sector_size, arr + 8);
1867 arr[13] = sdebug_physblk_exp & 0xf;
1868 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001869
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001870 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001871 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001872 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1873 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1874 * in the wider field maps to 0 in this field.
1875 */
1876 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1877 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001878 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001879
Douglas Gilbert773642d2016-04-25 12:16:28 -04001880 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001881
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001882 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001883 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001884 arr[12] |= 1; /* PROT_EN */
1885 }
1886
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001887 return fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001888 min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001889}
1890
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001891#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1892
John Pittman91d4c752018-02-09 21:12:43 -05001893static int resp_report_tgtpgs(struct scsi_cmnd *scp,
1894 struct sdebug_dev_info *devip)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001895{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001896 unsigned char *cmd = scp->cmnd;
John Pittman91d4c752018-02-09 21:12:43 -05001897 unsigned char *arr;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001898 int host_no = devip->sdbg_host->shost->host_no;
1899 int n, ret, alen, rlen;
1900 int port_group_a, port_group_b, port_a, port_b;
1901
Douglas Gilbert773642d2016-04-25 12:16:28 -04001902 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001903 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1904 if (! arr)
1905 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001906 /*
1907 * EVPD page 0x88 states we have two ports, one
1908 * real and a fake port with no device connected.
1909 * So we create two port groups with one port each
1910 * and set the group with port B to unavailable.
1911 */
1912 port_a = 0x1; /* relative port A */
1913 port_b = 0x2; /* relative port B */
1914 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001915 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001916 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001917 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001918
1919 /*
1920 * The asymmetric access state is cycled according to the host_id.
1921 */
1922 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001923 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001924 arr[n++] = host_no % 3; /* Asymm access state */
1925 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001926 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001927 arr[n++] = 0x0; /* Active/Optimized path */
1928 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001929 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001930 put_unaligned_be16(port_group_a, arr + n);
1931 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001932 arr[n++] = 0; /* Reserved */
1933 arr[n++] = 0; /* Status code */
1934 arr[n++] = 0; /* Vendor unique */
1935 arr[n++] = 0x1; /* One port per group */
1936 arr[n++] = 0; /* Reserved */
1937 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001938 put_unaligned_be16(port_a, arr + n);
1939 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001940 arr[n++] = 3; /* Port unavailable */
1941 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001942 put_unaligned_be16(port_group_b, arr + n);
1943 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001944 arr[n++] = 0; /* Reserved */
1945 arr[n++] = 0; /* Status code */
1946 arr[n++] = 0; /* Vendor unique */
1947 arr[n++] = 0x1; /* One port per group */
1948 arr[n++] = 0; /* Reserved */
1949 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001950 put_unaligned_be16(port_b, arr + n);
1951 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001952
1953 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001954 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001955
1956 /*
1957 * Return the smallest value of either
1958 * - The allocated length
1959 * - The constructed command length
1960 * - The maximum array size
1961 */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001962 rlen = min_t(int, alen, n);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001963 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04001964 min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001965 kfree(arr);
1966 return ret;
1967}
1968
Douglas Gilbertfd321192016-04-25 12:16:33 -04001969static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1970 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001971{
1972 bool rctd;
1973 u8 reporting_opts, req_opcode, sdeb_i, supp;
1974 u16 req_sa, u;
1975 u32 alloc_len, a_len;
1976 int k, offset, len, errsts, count, bump, na;
1977 const struct opcode_info_t *oip;
1978 const struct opcode_info_t *r_oip;
1979 u8 *arr;
1980 u8 *cmd = scp->cmnd;
1981
1982 rctd = !!(cmd[2] & 0x80);
1983 reporting_opts = cmd[2] & 0x7;
1984 req_opcode = cmd[3];
1985 req_sa = get_unaligned_be16(cmd + 4);
1986 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001987 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001988 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1989 return check_condition_result;
1990 }
1991 if (alloc_len > 8192)
1992 a_len = 8192;
1993 else
1994 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001995 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001996 if (NULL == arr) {
1997 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1998 INSUFF_RES_ASCQ);
1999 return check_condition_result;
2000 }
2001 switch (reporting_opts) {
2002 case 0: /* all commands */
2003 /* count number of commands */
2004 for (count = 0, oip = opcode_info_arr;
2005 oip->num_attached != 0xff; ++oip) {
2006 if (F_INV_OP & oip->flags)
2007 continue;
2008 count += (oip->num_attached + 1);
2009 }
2010 bump = rctd ? 20 : 8;
2011 put_unaligned_be32(count * bump, arr);
2012 for (offset = 4, oip = opcode_info_arr;
2013 oip->num_attached != 0xff && offset < a_len; ++oip) {
2014 if (F_INV_OP & oip->flags)
2015 continue;
2016 na = oip->num_attached;
2017 arr[offset] = oip->opcode;
2018 put_unaligned_be16(oip->sa, arr + offset + 2);
2019 if (rctd)
2020 arr[offset + 5] |= 0x2;
2021 if (FF_SA & oip->flags)
2022 arr[offset + 5] |= 0x1;
2023 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
2024 if (rctd)
2025 put_unaligned_be16(0xa, arr + offset + 8);
2026 r_oip = oip;
2027 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
2028 if (F_INV_OP & oip->flags)
2029 continue;
2030 offset += bump;
2031 arr[offset] = oip->opcode;
2032 put_unaligned_be16(oip->sa, arr + offset + 2);
2033 if (rctd)
2034 arr[offset + 5] |= 0x2;
2035 if (FF_SA & oip->flags)
2036 arr[offset + 5] |= 0x1;
2037 put_unaligned_be16(oip->len_mask[0],
2038 arr + offset + 6);
2039 if (rctd)
2040 put_unaligned_be16(0xa,
2041 arr + offset + 8);
2042 }
2043 oip = r_oip;
2044 offset += bump;
2045 }
2046 break;
2047 case 1: /* one command: opcode only */
2048 case 2: /* one command: opcode plus service action */
2049 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
2050 sdeb_i = opcode_ind_arr[req_opcode];
2051 oip = &opcode_info_arr[sdeb_i];
2052 if (F_INV_OP & oip->flags) {
2053 supp = 1;
2054 offset = 4;
2055 } else {
2056 if (1 == reporting_opts) {
2057 if (FF_SA & oip->flags) {
2058 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
2059 2, 2);
2060 kfree(arr);
2061 return check_condition_result;
2062 }
2063 req_sa = 0;
2064 } else if (2 == reporting_opts &&
2065 0 == (FF_SA & oip->flags)) {
2066 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
2067 kfree(arr); /* point at requested sa */
2068 return check_condition_result;
2069 }
2070 if (0 == (FF_SA & oip->flags) &&
2071 req_opcode == oip->opcode)
2072 supp = 3;
2073 else if (0 == (FF_SA & oip->flags)) {
2074 na = oip->num_attached;
2075 for (k = 0, oip = oip->arrp; k < na;
2076 ++k, ++oip) {
2077 if (req_opcode == oip->opcode)
2078 break;
2079 }
2080 supp = (k >= na) ? 1 : 3;
2081 } else if (req_sa != oip->sa) {
2082 na = oip->num_attached;
2083 for (k = 0, oip = oip->arrp; k < na;
2084 ++k, ++oip) {
2085 if (req_sa == oip->sa)
2086 break;
2087 }
2088 supp = (k >= na) ? 1 : 3;
2089 } else
2090 supp = 3;
2091 if (3 == supp) {
2092 u = oip->len_mask[0];
2093 put_unaligned_be16(u, arr + 2);
2094 arr[4] = oip->opcode;
2095 for (k = 1; k < u; ++k)
2096 arr[4 + k] = (k < 16) ?
2097 oip->len_mask[k] : 0xff;
2098 offset = 4 + u;
2099 } else
2100 offset = 4;
2101 }
2102 arr[1] = (rctd ? 0x80 : 0) | supp;
2103 if (rctd) {
2104 put_unaligned_be16(0xa, arr + offset);
2105 offset += 12;
2106 }
2107 break;
2108 default:
2109 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
2110 kfree(arr);
2111 return check_condition_result;
2112 }
2113 offset = (offset < a_len) ? offset : a_len;
2114 len = (offset < alloc_len) ? offset : alloc_len;
2115 errsts = fill_from_dev_buffer(scp, arr, len);
2116 kfree(arr);
2117 return errsts;
2118}
2119
Douglas Gilbertfd321192016-04-25 12:16:33 -04002120static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2121 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002122{
2123 bool repd;
2124 u32 alloc_len, len;
2125 u8 arr[16];
2126 u8 *cmd = scp->cmnd;
2127
2128 memset(arr, 0, sizeof(arr));
2129 repd = !!(cmd[2] & 0x80);
2130 alloc_len = get_unaligned_be32(cmd + 6);
2131 if (alloc_len < 4) {
2132 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
2133 return check_condition_result;
2134 }
2135 arr[0] = 0xc8; /* ATS | ATSS | LURS */
2136 arr[1] = 0x1; /* ITNRS */
2137 if (repd) {
2138 arr[3] = 0xc;
2139 len = 16;
2140 } else
2141 len = 4;
2142
2143 len = (len < alloc_len) ? len : alloc_len;
2144 return fill_from_dev_buffer(scp, arr, len);
2145}
2146
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147/* <<Following mode page info copied from ST318451LW>> */
2148
John Pittman91d4c752018-02-09 21:12:43 -05002149static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150{ /* Read-Write Error Recovery page for mode_sense */
2151 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
2152 5, 0, 0xff, 0xff};
2153
2154 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
2155 if (1 == pcontrol)
2156 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
2157 return sizeof(err_recov_pg);
2158}
2159
John Pittman91d4c752018-02-09 21:12:43 -05002160static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161{ /* Disconnect-Reconnect page for mode_sense */
2162 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
2163 0, 0, 0, 0, 0, 0, 0, 0};
2164
2165 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
2166 if (1 == pcontrol)
2167 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
2168 return sizeof(disconnect_pg);
2169}
2170
John Pittman91d4c752018-02-09 21:12:43 -05002171static int resp_format_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172{ /* Format device page for mode_sense */
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002173 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
2174 0, 0, 0, 0, 0, 0, 0, 0,
2175 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002177 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002178 put_unaligned_be16(sdebug_sectors_per, p + 10);
2179 put_unaligned_be16(sdebug_sector_size, p + 12);
2180 if (sdebug_removable)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002181 p[20] |= 0x20; /* should agree with INQUIRY */
2182 if (1 == pcontrol)
2183 memset(p + 2, 0, sizeof(format_pg) - 2);
2184 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185}
2186
Douglas Gilbertfd321192016-04-25 12:16:33 -04002187static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2188 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2189 0, 0, 0, 0};
2190
John Pittman91d4c752018-02-09 21:12:43 -05002191static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002193 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2194 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2195 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
2197
Douglas Gilbert773642d2016-04-25 12:16:28 -04002198 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002199 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 memcpy(p, caching_pg, sizeof(caching_pg));
2201 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002202 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2203 else if (2 == pcontrol)
2204 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 return sizeof(caching_pg);
2206}
2207
Douglas Gilbertfd321192016-04-25 12:16:33 -04002208static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2209 0, 0, 0x2, 0x4b};
2210
John Pittman91d4c752018-02-09 21:12:43 -05002211static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002213 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05002214 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002215 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 0, 0, 0x2, 0x4b};
2217
Douglas Gilbert773642d2016-04-25 12:16:28 -04002218 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002220 else
2221 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002222
Douglas Gilbert773642d2016-04-25 12:16:28 -04002223 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002224 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2225
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2227 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002228 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2229 else if (2 == pcontrol)
2230 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 return sizeof(ctrl_m_pg);
2232}
2233
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002234
John Pittman91d4c752018-02-09 21:12:43 -05002235static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002237 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2238 0, 0, 0x0, 0x0};
2239 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2240 0, 0, 0x0, 0x0};
2241
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2243 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002244 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2245 else if (2 == pcontrol)
2246 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 return sizeof(iec_m_pg);
2248}
2249
John Pittman91d4c752018-02-09 21:12:43 -05002250static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002251{ /* SAS SSP mode page - short format for mode_sense */
2252 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2253 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2254
2255 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2256 if (1 == pcontrol)
2257 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2258 return sizeof(sas_sf_m_pg);
2259}
2260
2261
John Pittman91d4c752018-02-09 21:12:43 -05002262static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002263 int target_dev_id)
2264{ /* SAS phy control and discover mode page for mode_sense */
2265 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2266 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002267 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2268 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002269 0x2, 0, 0, 0, 0, 0, 0, 0,
2270 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2271 0, 0, 0, 0, 0, 0, 0, 0,
2272 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002273 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2274 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002275 0x3, 0, 0, 0, 0, 0, 0, 0,
2276 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2277 0, 0, 0, 0, 0, 0, 0, 0,
2278 };
2279 int port_a, port_b;
2280
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002281 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2282 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2283 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2284 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002285 port_a = target_dev_id + 1;
2286 port_b = port_a + 1;
2287 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002288 put_unaligned_be32(port_a, p + 20);
2289 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002290 if (1 == pcontrol)
2291 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2292 return sizeof(sas_pcd_m_pg);
2293}
2294
John Pittman91d4c752018-02-09 21:12:43 -05002295static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002296{ /* SAS SSP shared protocol specific port mode subpage */
2297 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2298 0, 0, 0, 0, 0, 0, 0, 0,
2299 };
2300
2301 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2302 if (1 == pcontrol)
2303 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2304 return sizeof(sas_sha_m_pg);
2305}
2306
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307#define SDEBUG_MAX_MSENSE_SZ 256
2308
Douglas Gilbertfd321192016-04-25 12:16:33 -04002309static int resp_mode_sense(struct scsi_cmnd *scp,
2310 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311{
Douglas Gilbert23183912006-09-16 20:30:47 -04002312 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002314 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002315 int target = scp->device->id;
John Pittman91d4c752018-02-09 21:12:43 -05002316 unsigned char *ap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002318 unsigned char *cmd = scp->cmnd;
Douglas Gilbertd36da302020-04-22 19:42:15 +09002319 bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002321 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 pcontrol = (cmd[2] & 0xc0) >> 6;
2323 pcode = cmd[2] & 0x3f;
2324 subpcode = cmd[3];
2325 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002326 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2327 is_disk = (sdebug_ptype == TYPE_DISK);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002328 is_zbc = (devip->zmodel != BLK_ZONED_NONE);
Douglas Gilbertd36da302020-04-22 19:42:15 +09002329 if ((is_disk || is_zbc) && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002330 bd_len = llbaa ? 16 : 8;
2331 else
2332 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002333 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2335 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002336 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 return check_condition_result;
2338 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002339 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2340 (devip->target * 1000) - 3;
Douglas Gilbertd36da302020-04-22 19:42:15 +09002341 /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2342 if (is_disk || is_zbc) {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002343 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002344 if (sdebug_wp)
2345 dev_spec |= 0x80;
2346 } else
Douglas Gilbert23183912006-09-16 20:30:47 -04002347 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 if (msense_6) {
2349 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002350 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 offset = 4;
2352 } else {
2353 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002354 if (16 == bd_len)
2355 arr[4] = 0x1; /* set LONGLBA bit */
2356 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 offset = 8;
2358 }
2359 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002360 if ((bd_len > 0) && (!sdebug_capacity))
2361 sdebug_capacity = get_sdebug_capacity();
2362
Douglas Gilbert23183912006-09-16 20:30:47 -04002363 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002364 if (sdebug_capacity > 0xfffffffe)
2365 put_unaligned_be32(0xffffffff, ap + 0);
2366 else
2367 put_unaligned_be32(sdebug_capacity, ap + 0);
2368 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002369 offset += bd_len;
2370 ap = arr + offset;
2371 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002372 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2373 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002374 offset += bd_len;
2375 ap = arr + offset;
2376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002378 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2379 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002380 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 return check_condition_result;
2382 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002383 bad_pcode = false;
2384
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 switch (pcode) {
2386 case 0x1: /* Read-Write error recovery page, direct access */
2387 len = resp_err_recov_pg(ap, pcontrol, target);
2388 offset += len;
2389 break;
2390 case 0x2: /* Disconnect-Reconnect page, all devices */
2391 len = resp_disconnect_pg(ap, pcontrol, target);
2392 offset += len;
2393 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002394 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002395 if (is_disk) {
2396 len = resp_format_pg(ap, pcontrol, target);
2397 offset += len;
2398 } else
2399 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002400 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 case 0x8: /* Caching page, direct access */
Douglas Gilbertd36da302020-04-22 19:42:15 +09002402 if (is_disk || is_zbc) {
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002403 len = resp_caching_pg(ap, pcontrol, target);
2404 offset += len;
2405 } else
2406 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 break;
2408 case 0xa: /* Control Mode page, all devices */
2409 len = resp_ctrl_m_pg(ap, pcontrol, target);
2410 offset += len;
2411 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002412 case 0x19: /* if spc==1 then sas phy, control+discover */
2413 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002414 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002415 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002416 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002417 len = 0;
2418 if ((0x0 == subpcode) || (0xff == subpcode))
2419 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2420 if ((0x1 == subpcode) || (0xff == subpcode))
2421 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2422 target_dev_id);
2423 if ((0x2 == subpcode) || (0xff == subpcode))
2424 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2425 offset += len;
2426 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 case 0x1c: /* Informational Exceptions Mode page, all devices */
2428 len = resp_iec_m_pg(ap, pcontrol, target);
2429 offset += len;
2430 break;
2431 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002432 if ((0 == subpcode) || (0xff == subpcode)) {
2433 len = resp_err_recov_pg(ap, pcontrol, target);
2434 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002435 if (is_disk) {
2436 len += resp_format_pg(ap + len, pcontrol,
2437 target);
2438 len += resp_caching_pg(ap + len, pcontrol,
2439 target);
Douglas Gilbertd36da302020-04-22 19:42:15 +09002440 } else if (is_zbc) {
2441 len += resp_caching_pg(ap + len, pcontrol,
2442 target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002443 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002444 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2445 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2446 if (0xff == subpcode) {
2447 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2448 target, target_dev_id);
2449 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2450 }
2451 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002452 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002453 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002454 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002455 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 break;
2458 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002459 bad_pcode = true;
2460 break;
2461 }
2462 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002463 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 return check_condition_result;
2465 }
2466 if (msense_6)
2467 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002468 else
2469 put_unaligned_be16((offset - 2), arr + 0);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002470 return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471}
2472
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002473#define SDEBUG_MAX_MSELECT_SZ 512
2474
Douglas Gilbertfd321192016-04-25 12:16:33 -04002475static int resp_mode_select(struct scsi_cmnd *scp,
2476 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002477{
2478 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002479 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002480 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002481 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002482 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002483
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002484 memset(arr, 0, sizeof(arr));
2485 pf = cmd[1] & 0x10;
2486 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002487 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002488 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002489 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002490 return check_condition_result;
2491 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002492 res = fetch_to_dev_buffer(scp, arr, param_len);
2493 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002494 return DID_ERROR << 16;
2495 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002496 sdev_printk(KERN_INFO, scp->device,
2497 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2498 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002499 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2500 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002501 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002502 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002503 return check_condition_result;
2504 }
2505 off = bd_len + (mselect6 ? 4 : 8);
2506 mpage = arr[off] & 0x3f;
2507 ps = !!(arr[off] & 0x80);
2508 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002509 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002510 return check_condition_result;
2511 }
2512 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002513 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002514 (arr[off + 1] + 2);
2515 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002516 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002517 PARAMETER_LIST_LENGTH_ERR, 0);
2518 return check_condition_result;
2519 }
2520 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002521 case 0x8: /* Caching Mode page */
2522 if (caching_pg[1] == arr[off + 1]) {
2523 memcpy(caching_pg + 2, arr + off + 2,
2524 sizeof(caching_pg) - 2);
2525 goto set_mode_changed_ua;
2526 }
2527 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002528 case 0xa: /* Control Mode page */
2529 if (ctrl_m_pg[1] == arr[off + 1]) {
2530 memcpy(ctrl_m_pg + 2, arr + off + 2,
2531 sizeof(ctrl_m_pg) - 2);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002532 if (ctrl_m_pg[4] & 0x8)
2533 sdebug_wp = true;
2534 else
2535 sdebug_wp = false;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002536 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002537 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002538 }
2539 break;
2540 case 0x1c: /* Informational Exceptions Mode page */
2541 if (iec_m_pg[1] == arr[off + 1]) {
2542 memcpy(iec_m_pg + 2, arr + off + 2,
2543 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002544 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002545 }
2546 break;
2547 default:
2548 break;
2549 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002550 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002551 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002552set_mode_changed_ua:
2553 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2554 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002555}
2556
John Pittman91d4c752018-02-09 21:12:43 -05002557static int resp_temp_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002558{
2559 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2560 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2561 };
2562
Douglas Gilbert9a051012017-12-23 12:48:10 -05002563 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2564 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002565}
2566
John Pittman91d4c752018-02-09 21:12:43 -05002567static int resp_ie_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002568{
2569 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2570 };
2571
Douglas Gilbert9a051012017-12-23 12:48:10 -05002572 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002573 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2574 arr[4] = THRESHOLD_EXCEEDED;
2575 arr[5] = 0xff;
2576 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002577 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002578}
2579
2580#define SDEBUG_MAX_LSENSE_SZ 512
2581
Douglas Gilbert9a051012017-12-23 12:48:10 -05002582static int resp_log_sense(struct scsi_cmnd *scp,
2583 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002584{
Bart Van Asscheab172412017-08-25 13:46:42 -07002585 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002586 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002587 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002588
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002589 memset(arr, 0, sizeof(arr));
2590 ppc = cmd[1] & 0x2;
2591 sp = cmd[1] & 0x1;
2592 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002593 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002594 return check_condition_result;
2595 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002596 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002597 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002598 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002599 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002600 if (0 == subpcode) {
2601 switch (pcode) {
2602 case 0x0: /* Supported log pages log page */
2603 n = 4;
2604 arr[n++] = 0x0; /* this page */
2605 arr[n++] = 0xd; /* Temperature */
2606 arr[n++] = 0x2f; /* Informational exceptions */
2607 arr[3] = n - 4;
2608 break;
2609 case 0xd: /* Temperature log page */
2610 arr[3] = resp_temp_l_pg(arr + 4);
2611 break;
2612 case 0x2f: /* Informational exceptions log page */
2613 arr[3] = resp_ie_l_pg(arr + 4);
2614 break;
2615 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002616 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002617 return check_condition_result;
2618 }
2619 } else if (0xff == subpcode) {
2620 arr[0] |= 0x40;
2621 arr[1] = subpcode;
2622 switch (pcode) {
2623 case 0x0: /* Supported log pages and subpages log page */
2624 n = 4;
2625 arr[n++] = 0x0;
2626 arr[n++] = 0x0; /* 0,0 page */
2627 arr[n++] = 0x0;
2628 arr[n++] = 0xff; /* this page */
2629 arr[n++] = 0xd;
2630 arr[n++] = 0x0; /* Temperature */
2631 arr[n++] = 0x2f;
2632 arr[n++] = 0x0; /* Informational exceptions */
2633 arr[3] = n - 4;
2634 break;
2635 case 0xd: /* Temperature subpages */
2636 n = 4;
2637 arr[n++] = 0xd;
2638 arr[n++] = 0x0; /* Temperature */
2639 arr[3] = n - 4;
2640 break;
2641 case 0x2f: /* Informational exceptions subpages */
2642 n = 4;
2643 arr[n++] = 0x2f;
2644 arr[n++] = 0x0; /* Informational exceptions */
2645 arr[3] = n - 4;
2646 break;
2647 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002648 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002649 return check_condition_result;
2650 }
2651 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002652 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002653 return check_condition_result;
2654 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002655 len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002656 return fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002657 min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002658}
2659
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002660static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661{
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002662 return devip->nr_zones != 0;
2663}
2664
2665static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2666 unsigned long long lba)
2667{
Damien Le Moal108e36f2020-05-07 11:35:26 +09002668 return &devip->zstate[lba >> devip->zsize_shift];
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002669}
2670
2671static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2672{
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002673 return zsp->z_type == ZBC_ZONE_TYPE_CNV;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002674}
2675
2676static void zbc_close_zone(struct sdebug_dev_info *devip,
2677 struct sdeb_zone_state *zsp)
2678{
2679 enum sdebug_z_cond zc;
2680
2681 if (zbc_zone_is_conv(zsp))
2682 return;
2683
2684 zc = zsp->z_cond;
2685 if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2686 return;
2687
2688 if (zc == ZC2_IMPLICIT_OPEN)
2689 devip->nr_imp_open--;
2690 else
2691 devip->nr_exp_open--;
2692
2693 if (zsp->z_wp == zsp->z_start) {
2694 zsp->z_cond = ZC1_EMPTY;
2695 } else {
2696 zsp->z_cond = ZC4_CLOSED;
2697 devip->nr_closed++;
2698 }
2699}
2700
2701static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2702{
2703 struct sdeb_zone_state *zsp = &devip->zstate[0];
2704 unsigned int i;
2705
2706 for (i = 0; i < devip->nr_zones; i++, zsp++) {
2707 if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2708 zbc_close_zone(devip, zsp);
2709 return;
2710 }
2711 }
2712}
2713
2714static void zbc_open_zone(struct sdebug_dev_info *devip,
2715 struct sdeb_zone_state *zsp, bool explicit)
2716{
2717 enum sdebug_z_cond zc;
2718
2719 if (zbc_zone_is_conv(zsp))
2720 return;
2721
2722 zc = zsp->z_cond;
2723 if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2724 (!explicit && zc == ZC2_IMPLICIT_OPEN))
2725 return;
2726
2727 /* Close an implicit open zone if necessary */
2728 if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2729 zbc_close_zone(devip, zsp);
2730 else if (devip->max_open &&
2731 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2732 zbc_close_imp_open_zone(devip);
2733
2734 if (zsp->z_cond == ZC4_CLOSED)
2735 devip->nr_closed--;
2736 if (explicit) {
2737 zsp->z_cond = ZC3_EXPLICIT_OPEN;
2738 devip->nr_exp_open++;
2739 } else {
2740 zsp->z_cond = ZC2_IMPLICIT_OPEN;
2741 devip->nr_imp_open++;
2742 }
2743}
2744
2745static void zbc_inc_wp(struct sdebug_dev_info *devip,
2746 unsigned long long lba, unsigned int num)
2747{
2748 struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002749 unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002750
2751 if (zbc_zone_is_conv(zsp))
2752 return;
2753
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002754 if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2755 zsp->z_wp += num;
2756 if (zsp->z_wp >= zend)
2757 zsp->z_cond = ZC5_FULL;
2758 return;
2759 }
2760
2761 while (num) {
2762 if (lba != zsp->z_wp)
2763 zsp->z_non_seq_resource = true;
2764
2765 end = lba + num;
2766 if (end >= zend) {
2767 n = zend - lba;
2768 zsp->z_wp = zend;
2769 } else if (end > zsp->z_wp) {
2770 n = num;
2771 zsp->z_wp = end;
2772 } else {
2773 n = num;
2774 }
2775 if (zsp->z_wp >= zend)
2776 zsp->z_cond = ZC5_FULL;
2777
2778 num -= n;
2779 lba += n;
2780 if (num) {
2781 zsp++;
2782 zend = zsp->z_start + zsp->z_size;
2783 }
2784 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002785}
2786
2787static int check_zbc_access_params(struct scsi_cmnd *scp,
2788 unsigned long long lba, unsigned int num, bool write)
2789{
2790 struct scsi_device *sdp = scp->device;
2791 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2792 struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2793 struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2794
2795 if (!write) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002796 if (devip->zmodel == BLK_ZONED_HA)
2797 return 0;
2798 /* For host-managed, reads cannot cross zone types boundaries */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002799 if (zsp_end != zsp &&
2800 zbc_zone_is_conv(zsp) &&
2801 !zbc_zone_is_conv(zsp_end)) {
2802 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2803 LBA_OUT_OF_RANGE,
2804 READ_INVDATA_ASCQ);
2805 return check_condition_result;
2806 }
2807 return 0;
2808 }
2809
2810 /* No restrictions for writes within conventional zones */
2811 if (zbc_zone_is_conv(zsp)) {
2812 if (!zbc_zone_is_conv(zsp_end)) {
2813 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2814 LBA_OUT_OF_RANGE,
2815 WRITE_BOUNDARY_ASCQ);
2816 return check_condition_result;
2817 }
2818 return 0;
2819 }
2820
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002821 if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2822 /* Writes cannot cross sequential zone boundaries */
2823 if (zsp_end != zsp) {
2824 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2825 LBA_OUT_OF_RANGE,
2826 WRITE_BOUNDARY_ASCQ);
2827 return check_condition_result;
2828 }
2829 /* Cannot write full zones */
2830 if (zsp->z_cond == ZC5_FULL) {
2831 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2832 INVALID_FIELD_IN_CDB, 0);
2833 return check_condition_result;
2834 }
2835 /* Writes must be aligned to the zone WP */
2836 if (lba != zsp->z_wp) {
2837 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2838 LBA_OUT_OF_RANGE,
2839 UNALIGNED_WRITE_ASCQ);
2840 return check_condition_result;
2841 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002842 }
2843
2844 /* Handle implicit open of closed and empty zones */
2845 if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2846 if (devip->max_open &&
2847 devip->nr_exp_open >= devip->max_open) {
2848 mk_sense_buffer(scp, DATA_PROTECT,
2849 INSUFF_RES_ASC,
2850 INSUFF_ZONE_ASCQ);
2851 return check_condition_result;
2852 }
2853 zbc_open_zone(devip, zsp, false);
2854 }
2855
2856 return 0;
2857}
2858
2859static inline int check_device_access_params
2860 (struct scsi_cmnd *scp, unsigned long long lba,
2861 unsigned int num, bool write)
2862{
2863 struct scsi_device *sdp = scp->device;
2864 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2865
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002866 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002867 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 return check_condition_result;
2869 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002870 /* transfer length excessive (tie in to block limits VPD page) */
2871 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002872 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002873 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002874 return check_condition_result;
2875 }
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002876 if (write && unlikely(sdebug_wp)) {
2877 mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
2878 return check_condition_result;
2879 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002880 if (sdebug_dev_is_zoned(devip))
2881 return check_zbc_access_params(scp, lba, num, write);
2882
FUJITA Tomonori19789102008-03-30 00:59:56 +09002883 return 0;
2884}
2885
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04002886/*
2887 * Note: if BUG_ON() fires it usually indicates a problem with the parser
2888 * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2889 * that access any of the "stores" in struct sdeb_store_info should call this
2890 * function with bug_if_fake_rw set to true.
2891 */
2892static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2893 bool bug_if_fake_rw)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002894{
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04002895 if (sdebug_fake_rw) {
2896 BUG_ON(bug_if_fake_rw); /* See note above */
2897 return NULL;
2898 }
2899 return xa_load(per_store_ap, devip->sdbg_host->si_idx);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002900}
2901
Akinobu Mitaa4517512013-07-08 16:01:57 -07002902/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002903static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
2904 u32 sg_skip, u64 lba, u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002905{
2906 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002907 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002908 enum dma_data_direction dir;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002909 struct scsi_data_buffer *sdb = &scp->sdb;
2910 u8 *fsp;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002911
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002912 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002913 dir = DMA_TO_DEVICE;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04002914 write_since_sync = true;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002915 } else {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002916 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002917 }
2918
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002919 if (!sdb->length || !sip)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002920 return 0;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002921 if (scp->sc_data_direction != dir)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002922 return -1;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002923 fsp = sip->storep;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002924
2925 block = do_div(lba, sdebug_store_sectors);
2926 if (block + num > sdebug_store_sectors)
2927 rest = block + num - sdebug_store_sectors;
2928
Dave Gordon386ecb12015-06-30 14:58:57 -07002929 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002930 fsp + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002931 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002932 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002933 return ret;
2934
2935 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002936 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002937 fsp, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002938 sg_skip + ((num - rest) * sdebug_sector_size),
2939 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002940 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002941
2942 return ret;
2943}
2944
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002945/* Returns number of bytes copied or -1 if error. */
2946static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
2947{
2948 struct scsi_data_buffer *sdb = &scp->sdb;
2949
2950 if (!sdb->length)
2951 return 0;
2952 if (scp->sc_data_direction != DMA_TO_DEVICE)
2953 return -1;
2954 return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
2955 num * sdebug_sector_size, 0, true);
2956}
2957
2958/* If sip->storep+lba compares equal to arr(num), then copy top half of
2959 * arr into sip->storep+lba and return true. If comparison fails then
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002960 * return false. */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002961static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04002962 const u8 *arr, bool compare_only)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002963{
2964 bool res;
2965 u64 block, rest = 0;
2966 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002967 u32 lb_size = sdebug_sector_size;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002968 u8 *fsp = sip->storep;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002969
2970 block = do_div(lba, store_blks);
2971 if (block + num > store_blks)
2972 rest = block + num - store_blks;
2973
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002974 res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002975 if (!res)
2976 return res;
2977 if (rest)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002978 res = memcmp(fsp, arr + ((num - rest) * lb_size),
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002979 rest * lb_size);
2980 if (!res)
2981 return res;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04002982 if (compare_only)
2983 return true;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002984 arr += num * lb_size;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002985 memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002986 if (rest)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002987 memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002988 return res;
2989}
2990
Akinobu Mita51d648a2013-09-18 21:27:28 +09002991static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002992{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002993 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002994
Douglas Gilbert773642d2016-04-25 12:16:28 -04002995 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002996 csum = (__force __be16)ip_compute_csum(buf, len);
2997 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002998 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002999
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003000 return csum;
3001}
3002
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003003static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003004 sector_t sector, u32 ei_lba)
3005{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003006 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003007
3008 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003009 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003010 (unsigned long)sector,
3011 be16_to_cpu(sdt->guard_tag),
3012 be16_to_cpu(csum));
3013 return 0x01;
3014 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003015 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003016 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003017 pr_err("REF check failed on sector %lu\n",
3018 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003019 return 0x03;
3020 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003021 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003022 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003023 pr_err("REF check failed on sector %lu\n",
3024 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003025 return 0x03;
3026 }
3027 return 0;
3028}
3029
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003030static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003031 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003032{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003033 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003034 void *paddr;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003035 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003036 scp->device->hostdata, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003037 struct t10_pi_tuple *dif_storep = sip->dif_storep;
Akinobu Mita14faa942013-09-18 21:27:24 +09003038 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003039 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003040
Akinobu Mitae18d8be2013-06-29 17:59:18 +09003041 /* Bytes of protection data to copy into sgl */
3042 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003043
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003044 sg_miter_start(&miter, scsi_prot_sglist(scp),
3045 scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3046 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003047
3048 while (sg_miter_next(&miter) && resid > 0) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003049 size_t len = min_t(size_t, miter.length, resid);
3050 void *start = dif_store(sip, sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003051 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09003052
3053 if (dif_store_end < start + len)
3054 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003055
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003056 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09003057
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003058 if (read)
3059 memcpy(paddr, start, len - rest);
3060 else
3061 memcpy(start, paddr, len - rest);
3062
3063 if (rest) {
3064 if (read)
3065 memcpy(paddr + len - rest, dif_storep, rest);
3066 else
3067 memcpy(dif_storep, paddr + len - rest, rest);
3068 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003069
Akinobu Mitae18d8be2013-06-29 17:59:18 +09003070 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003071 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003072 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003073 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003074}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003075
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003076static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003077 unsigned int sectors, u32 ei_lba)
3078{
3079 unsigned int i;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003080 sector_t sector;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003081 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003082 scp->device->hostdata, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003083 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003084
Akinobu Mitac45eabec2014-02-26 22:56:58 +09003085 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003086 int ret;
3087
3088 sector = start_sec + i;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003089 sdt = dif_store(sip, sector);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003090
Akinobu Mita51d648a2013-09-18 21:27:28 +09003091 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003092 continue;
3093
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003094 ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
3095 ei_lba);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003096 if (ret) {
3097 dif_errors++;
3098 return ret;
3099 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003100 }
3101
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003102 dif_copy_prot(scp, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003103 dix_reads++;
3104
3105 return 0;
3106}
3107
Douglas Gilbertfd321192016-04-25 12:16:33 -04003108static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09003109{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003110 bool check_prot;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003111 u32 num;
3112 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003113 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003114 u64 lba;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003115 struct sdeb_store_info *sip = devip2sip(devip, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003116 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3117 u8 *cmd = scp->cmnd;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003118
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003119 switch (cmd[0]) {
3120 case READ_16:
3121 ei_lba = 0;
3122 lba = get_unaligned_be64(cmd + 2);
3123 num = get_unaligned_be32(cmd + 10);
3124 check_prot = true;
3125 break;
3126 case READ_10:
3127 ei_lba = 0;
3128 lba = get_unaligned_be32(cmd + 2);
3129 num = get_unaligned_be16(cmd + 7);
3130 check_prot = true;
3131 break;
3132 case READ_6:
3133 ei_lba = 0;
3134 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3135 (u32)(cmd[1] & 0x1f) << 16;
3136 num = (0 == cmd[4]) ? 256 : cmd[4];
3137 check_prot = true;
3138 break;
3139 case READ_12:
3140 ei_lba = 0;
3141 lba = get_unaligned_be32(cmd + 2);
3142 num = get_unaligned_be32(cmd + 6);
3143 check_prot = true;
3144 break;
3145 case XDWRITEREAD_10:
3146 ei_lba = 0;
3147 lba = get_unaligned_be32(cmd + 2);
3148 num = get_unaligned_be16(cmd + 7);
3149 check_prot = false;
3150 break;
3151 default: /* assume READ(32) */
3152 lba = get_unaligned_be64(cmd + 12);
3153 ei_lba = get_unaligned_be32(cmd + 20);
3154 num = get_unaligned_be32(cmd + 28);
3155 check_prot = false;
3156 break;
3157 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003158 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003159 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003160 (cmd[1] & 0xe0)) {
3161 mk_sense_invalid_opcode(scp);
3162 return check_condition_result;
3163 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003164 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3165 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003166 (cmd[1] & 0xe0) == 0)
3167 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3168 "to DIF device\n");
3169 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003170 if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
3171 atomic_read(&sdeb_inject_pending))) {
3172 num /= 2;
3173 atomic_set(&sdeb_inject_pending, 0);
3174 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003175
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003176 ret = check_device_access_params(scp, lba, num, false);
3177 if (ret)
3178 return ret;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003179 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05003180 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3181 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003182 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003183 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003184 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003185 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3186 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05003187 ret = (lba < OPT_MEDIUM_ERR_ADDR)
3188 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003189 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003190 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003191 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 return check_condition_result;
3193 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003194
Douglas Gilbert67da4132020-04-21 11:14:20 -04003195 read_lock(macc_lckp);
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003196
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003197 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003198 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003199 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003200
3201 if (prot_ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003202 read_unlock(macc_lckp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003203 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003204 return illegal_condition_result;
3205 }
3206 }
3207
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003208 ret = do_device_access(sip, scp, 0, lba, num, false);
Douglas Gilbert67da4132020-04-21 11:14:20 -04003209 read_unlock(macc_lckp);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003210 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07003211 return DID_ERROR << 16;
3212
Bart Van Assche42d387b2019-02-08 13:25:00 -08003213 scsi_set_resid(scp, scsi_bufflen(scp) - ret);
Akinobu Mitaa4517512013-07-08 16:01:57 -07003214
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003215 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3216 atomic_read(&sdeb_inject_pending))) {
3217 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3218 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3219 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003220 return check_condition_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003221 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003222 /* Logical block guard check failed */
3223 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003224 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003225 return illegal_condition_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003226 } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003227 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003228 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003229 return illegal_condition_result;
3230 }
3231 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07003232 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233}
3234
Tomas Winkler58a86352015-07-28 16:54:23 +03003235static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003236{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003237 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003238
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003239 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003240 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003241 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003242
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003243 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003244 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003245
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003246 if (c >= 0x20 && c < 0x7e)
3247 n += scnprintf(b + n, sizeof(b) - n,
3248 " %c ", buf[i+j]);
3249 else
3250 n += scnprintf(b + n, sizeof(b) - n,
3251 "%02x ", buf[i+j]);
3252 }
3253 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003254 }
3255}
3256
3257static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04003258 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003259{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003260 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003261 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003262 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003263 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003264 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003265 int dpage_offset;
3266 struct sg_mapping_iter diter;
3267 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003268
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003269 BUG_ON(scsi_sg_count(SCpnt) == 0);
3270 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3271
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003272 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3273 scsi_prot_sg_count(SCpnt),
3274 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3275 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3276 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003277
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003278 /* For each protection page */
3279 while (sg_miter_next(&piter)) {
3280 dpage_offset = 0;
3281 if (WARN_ON(!sg_miter_next(&diter))) {
3282 ret = 0x01;
3283 goto out;
3284 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003285
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003286 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003287 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003288 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003289 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003290 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003291 if (dpage_offset >= diter.length) {
3292 if (WARN_ON(!sg_miter_next(&diter))) {
3293 ret = 0x01;
3294 goto out;
3295 }
3296 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003297 }
3298
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003299 sdt = piter.addr + ppage_offset;
3300 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003301
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003302 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003303 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003304 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04003305 goto out;
3306 }
3307
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003308 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003309 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003310 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003311 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003312 diter.consumed = dpage_offset;
3313 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003314 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003315 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003316
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003317 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003318 dix_writes++;
3319
3320 return 0;
3321
3322out:
3323 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003324 sg_miter_stop(&diter);
3325 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003326 return ret;
3327}
3328
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003329static unsigned long lba_to_map_index(sector_t lba)
3330{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003331 if (sdebug_unmap_alignment)
3332 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3333 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003334 return lba;
3335}
3336
3337static sector_t map_index_to_lba(unsigned long index)
3338{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003339 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09003340
Douglas Gilbert773642d2016-04-25 12:16:28 -04003341 if (sdebug_unmap_alignment)
3342 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09003343 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003344}
3345
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003346static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
3347 unsigned int *num)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003348{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003349 sector_t end;
3350 unsigned int mapped;
3351 unsigned long index;
3352 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003353
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003354 index = lba_to_map_index(lba);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003355 mapped = test_bit(index, sip->map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003356
3357 if (mapped)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003358 next = find_next_zero_bit(sip->map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003359 else
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003360 next = find_next_bit(sip->map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003361
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003362 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003363 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003364 return mapped;
3365}
3366
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003367static void map_region(struct sdeb_store_info *sip, sector_t lba,
3368 unsigned int len)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003369{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003370 sector_t end = lba + len;
3371
Martin K. Petersen44d92692009-10-15 14:45:27 -04003372 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003373 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003374
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003375 if (index < map_size)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003376 set_bit(index, sip->map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003377
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003378 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003379 }
3380}
3381
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003382static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
3383 unsigned int len)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003384{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003385 sector_t end = lba + len;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003386 u8 *fsp = sip->storep;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003387
Martin K. Petersen44d92692009-10-15 14:45:27 -04003388 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003389 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003390
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003391 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04003392 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003393 index < map_size) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003394 clear_bit(index, sip->map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04003395 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003396 memset(fsp + lba * sdebug_sector_size,
Douglas Gilbert760f3b02016-05-06 00:40:27 -04003397 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04003398 sdebug_sector_size *
3399 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003400 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003401 if (sip->dif_storep) {
3402 memset(sip->dif_storep + lba, 0xff,
3403 sizeof(*sip->dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04003404 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09003405 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003406 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003407 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003408 }
3409}
3410
Douglas Gilbertfd321192016-04-25 12:16:33 -04003411static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003413 bool check_prot;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003414 u32 num;
3415 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003416 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003417 u64 lba;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003418 struct sdeb_store_info *sip = devip2sip(devip, true);
3419 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003420 u8 *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003422 switch (cmd[0]) {
3423 case WRITE_16:
3424 ei_lba = 0;
3425 lba = get_unaligned_be64(cmd + 2);
3426 num = get_unaligned_be32(cmd + 10);
3427 check_prot = true;
3428 break;
3429 case WRITE_10:
3430 ei_lba = 0;
3431 lba = get_unaligned_be32(cmd + 2);
3432 num = get_unaligned_be16(cmd + 7);
3433 check_prot = true;
3434 break;
3435 case WRITE_6:
3436 ei_lba = 0;
3437 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3438 (u32)(cmd[1] & 0x1f) << 16;
3439 num = (0 == cmd[4]) ? 256 : cmd[4];
3440 check_prot = true;
3441 break;
3442 case WRITE_12:
3443 ei_lba = 0;
3444 lba = get_unaligned_be32(cmd + 2);
3445 num = get_unaligned_be32(cmd + 6);
3446 check_prot = true;
3447 break;
3448 case 0x53: /* XDWRITEREAD(10) */
3449 ei_lba = 0;
3450 lba = get_unaligned_be32(cmd + 2);
3451 num = get_unaligned_be16(cmd + 7);
3452 check_prot = false;
3453 break;
3454 default: /* assume WRITE(32) */
3455 lba = get_unaligned_be64(cmd + 12);
3456 ei_lba = get_unaligned_be32(cmd + 20);
3457 num = get_unaligned_be32(cmd + 28);
3458 check_prot = false;
3459 break;
3460 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003461 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003462 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003463 (cmd[1] & 0xe0)) {
3464 mk_sense_invalid_opcode(scp);
3465 return check_condition_result;
3466 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003467 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3468 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003469 (cmd[1] & 0xe0) == 0)
3470 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3471 "to DIF device\n");
3472 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003473
Douglas Gilbert67da4132020-04-21 11:14:20 -04003474 write_lock(macc_lckp);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003475 ret = check_device_access_params(scp, lba, num, true);
3476 if (ret) {
3477 write_unlock(macc_lckp);
3478 return ret;
3479 }
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003480
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003481 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003482 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003483 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003484
3485 if (prot_ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003486 write_unlock(macc_lckp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003487 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003488 return illegal_condition_result;
3489 }
3490 }
3491
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003492 ret = do_device_access(sip, scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003493 if (unlikely(scsi_debug_lbp()))
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003494 map_region(sip, lba, num);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003495 /* If ZBC zone then bump its write pointer */
3496 if (sdebug_dev_is_zoned(devip))
3497 zbc_inc_wp(devip, lba, num);
Douglas Gilbert67da4132020-04-21 11:14:20 -04003498 write_unlock(macc_lckp);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003499 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003500 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003501 else if (unlikely(sdebug_verbose &&
3502 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003503 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003504 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003505 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003506
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003507 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3508 atomic_read(&sdeb_inject_pending))) {
3509 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3510 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3511 atomic_set(&sdeb_inject_pending, 0);
3512 return check_condition_result;
3513 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3514 /* Logical block guard check failed */
3515 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3516 atomic_set(&sdeb_inject_pending, 0);
3517 return illegal_condition_result;
3518 } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3519 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3520 atomic_set(&sdeb_inject_pending, 0);
3521 return illegal_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003522 }
3523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 return 0;
3525}
3526
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003527/*
3528 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3529 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3530 */
3531static int resp_write_scat(struct scsi_cmnd *scp,
3532 struct sdebug_dev_info *devip)
3533{
3534 u8 *cmd = scp->cmnd;
3535 u8 *lrdp = NULL;
3536 u8 *up;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003537 struct sdeb_store_info *sip = devip2sip(devip, true);
3538 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003539 u8 wrprotect;
3540 u16 lbdof, num_lrd, k;
3541 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3542 u32 lb_size = sdebug_sector_size;
3543 u32 ei_lba;
3544 u64 lba;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003545 int ret, res;
3546 bool is_16;
3547 static const u32 lrd_size = 32; /* + parameter list header size */
3548
3549 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3550 is_16 = false;
3551 wrprotect = (cmd[10] >> 5) & 0x7;
3552 lbdof = get_unaligned_be16(cmd + 12);
3553 num_lrd = get_unaligned_be16(cmd + 16);
3554 bt_len = get_unaligned_be32(cmd + 28);
3555 } else { /* that leaves WRITE SCATTERED(16) */
3556 is_16 = true;
3557 wrprotect = (cmd[2] >> 5) & 0x7;
3558 lbdof = get_unaligned_be16(cmd + 4);
3559 num_lrd = get_unaligned_be16(cmd + 8);
3560 bt_len = get_unaligned_be32(cmd + 10);
3561 if (unlikely(have_dif_prot)) {
3562 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3563 wrprotect) {
3564 mk_sense_invalid_opcode(scp);
3565 return illegal_condition_result;
3566 }
3567 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3568 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3569 wrprotect == 0)
3570 sdev_printk(KERN_ERR, scp->device,
3571 "Unprotected WR to DIF device\n");
3572 }
3573 }
3574 if ((num_lrd == 0) || (bt_len == 0))
3575 return 0; /* T10 says these do-nothings are not errors */
3576 if (lbdof == 0) {
3577 if (sdebug_verbose)
3578 sdev_printk(KERN_INFO, scp->device,
3579 "%s: %s: LB Data Offset field bad\n",
3580 my_name, __func__);
3581 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3582 return illegal_condition_result;
3583 }
3584 lbdof_blen = lbdof * lb_size;
3585 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3586 if (sdebug_verbose)
3587 sdev_printk(KERN_INFO, scp->device,
3588 "%s: %s: LBA range descriptors don't fit\n",
3589 my_name, __func__);
3590 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3591 return illegal_condition_result;
3592 }
3593 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3594 if (lrdp == NULL)
3595 return SCSI_MLQUEUE_HOST_BUSY;
3596 if (sdebug_verbose)
3597 sdev_printk(KERN_INFO, scp->device,
3598 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3599 my_name, __func__, lbdof_blen);
3600 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3601 if (res == -1) {
3602 ret = DID_ERROR << 16;
3603 goto err_out;
3604 }
3605
Douglas Gilbert67da4132020-04-21 11:14:20 -04003606 write_lock(macc_lckp);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003607 sg_off = lbdof_blen;
3608 /* Spec says Buffer xfer Length field in number of LBs in dout */
3609 cum_lb = 0;
3610 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3611 lba = get_unaligned_be64(up + 0);
3612 num = get_unaligned_be32(up + 8);
3613 if (sdebug_verbose)
3614 sdev_printk(KERN_INFO, scp->device,
3615 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3616 my_name, __func__, k, lba, num, sg_off);
3617 if (num == 0)
3618 continue;
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003619 ret = check_device_access_params(scp, lba, num, true);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003620 if (ret)
3621 goto err_out_unlock;
3622 num_by = num * lb_size;
3623 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3624
3625 if ((cum_lb + num) > bt_len) {
3626 if (sdebug_verbose)
3627 sdev_printk(KERN_INFO, scp->device,
3628 "%s: %s: sum of blocks > data provided\n",
3629 my_name, __func__);
3630 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3631 0);
3632 ret = illegal_condition_result;
3633 goto err_out_unlock;
3634 }
3635
3636 /* DIX + T10 DIF */
3637 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3638 int prot_ret = prot_verify_write(scp, lba, num,
3639 ei_lba);
3640
3641 if (prot_ret) {
3642 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3643 prot_ret);
3644 ret = illegal_condition_result;
3645 goto err_out_unlock;
3646 }
3647 }
3648
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003649 ret = do_device_access(sip, scp, sg_off, lba, num, true);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003650 /* If ZBC zone then bump its write pointer */
3651 if (sdebug_dev_is_zoned(devip))
3652 zbc_inc_wp(devip, lba, num);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003653 if (unlikely(scsi_debug_lbp()))
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003654 map_region(sip, lba, num);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003655 if (unlikely(-1 == ret)) {
3656 ret = DID_ERROR << 16;
3657 goto err_out_unlock;
3658 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3659 sdev_printk(KERN_INFO, scp->device,
3660 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3661 my_name, num_by, ret);
3662
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003663 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3664 atomic_read(&sdeb_inject_pending))) {
3665 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3666 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3667 atomic_set(&sdeb_inject_pending, 0);
3668 ret = check_condition_result;
3669 goto err_out_unlock;
3670 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3671 /* Logical block guard check failed */
3672 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3673 atomic_set(&sdeb_inject_pending, 0);
3674 ret = illegal_condition_result;
3675 goto err_out_unlock;
3676 } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3677 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3678 atomic_set(&sdeb_inject_pending, 0);
3679 ret = illegal_condition_result;
3680 goto err_out_unlock;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003681 }
3682 }
3683 sg_off += num_by;
3684 cum_lb += num;
3685 }
3686 ret = 0;
3687err_out_unlock:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003688 write_unlock(macc_lckp);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003689err_out:
3690 kfree(lrdp);
3691 return ret;
3692}
3693
Douglas Gilbertfd321192016-04-25 12:16:33 -04003694static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3695 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003696{
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003697 struct scsi_device *sdp = scp->device;
3698 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003699 unsigned long long i;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003700 u64 block, lbaa;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003701 u32 lb_size = sdebug_sector_size;
3702 int ret;
3703 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003704 scp->device->hostdata, true);
3705 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003706 u8 *fs1p;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003707 u8 *fsp;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003708
Douglas Gilbert67da4132020-04-21 11:14:20 -04003709 write_lock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003710
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003711 ret = check_device_access_params(scp, lba, num, true);
3712 if (ret) {
3713 write_unlock(macc_lckp);
3714 return ret;
3715 }
3716
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003717 if (unmap && scsi_debug_lbp()) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003718 unmap_region(sip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003719 goto out;
3720 }
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003721 lbaa = lba;
3722 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003723 /* if ndob then zero 1 logical block, else fetch 1 logical block */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003724 fsp = sip->storep;
3725 fs1p = fsp + (block * lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003726 if (ndob) {
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003727 memset(fs1p, 0, lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003728 ret = 0;
3729 } else
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003730 ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003731
3732 if (-1 == ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003733 write_unlock(&sip->macc_lck);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003734 return DID_ERROR << 16;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003735 } else if (sdebug_verbose && !ndob && (ret < lb_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003736 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003737 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003738 my_name, "write same", lb_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003739
3740 /* Copy first sector to remaining blocks */
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003741 for (i = 1 ; i < num ; i++) {
3742 lbaa = lba + i;
3743 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003744 memmove(fsp + (block * lb_size), fs1p, lb_size);
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003745 }
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003746 if (scsi_debug_lbp())
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003747 map_region(sip, lba, num);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003748 /* If ZBC zone then bump its write pointer */
3749 if (sdebug_dev_is_zoned(devip))
3750 zbc_inc_wp(devip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003751out:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003752 write_unlock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003753
3754 return 0;
3755}
3756
Douglas Gilbertfd321192016-04-25 12:16:33 -04003757static int resp_write_same_10(struct scsi_cmnd *scp,
3758 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003759{
3760 u8 *cmd = scp->cmnd;
3761 u32 lba;
3762 u16 num;
3763 u32 ei_lba = 0;
3764 bool unmap = false;
3765
3766 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003767 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003768 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3769 return check_condition_result;
3770 } else
3771 unmap = true;
3772 }
3773 lba = get_unaligned_be32(cmd + 2);
3774 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003775 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003776 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3777 return check_condition_result;
3778 }
3779 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3780}
3781
Douglas Gilbertfd321192016-04-25 12:16:33 -04003782static int resp_write_same_16(struct scsi_cmnd *scp,
3783 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003784{
3785 u8 *cmd = scp->cmnd;
3786 u64 lba;
3787 u32 num;
3788 u32 ei_lba = 0;
3789 bool unmap = false;
3790 bool ndob = false;
3791
3792 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003793 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003794 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3795 return check_condition_result;
3796 } else
3797 unmap = true;
3798 }
3799 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3800 ndob = true;
3801 lba = get_unaligned_be64(cmd + 2);
3802 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003803 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003804 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3805 return check_condition_result;
3806 }
3807 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3808}
3809
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003810/* Note the mode field is in the same position as the (lower) service action
3811 * field. For the Report supported operation codes command, SPC-4 suggests
3812 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003813static int resp_write_buffer(struct scsi_cmnd *scp,
3814 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003815{
3816 u8 *cmd = scp->cmnd;
3817 struct scsi_device *sdp = scp->device;
3818 struct sdebug_dev_info *dp;
3819 u8 mode;
3820
3821 mode = cmd[1] & 0x1f;
3822 switch (mode) {
3823 case 0x4: /* download microcode (MC) and activate (ACT) */
3824 /* set UAs on this device only */
3825 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3826 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3827 break;
3828 case 0x5: /* download MC, save and ACT */
3829 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3830 break;
3831 case 0x6: /* download MC with offsets and ACT */
3832 /* set UAs on most devices (LUs) in this target */
3833 list_for_each_entry(dp,
3834 &devip->sdbg_host->dev_info_list,
3835 dev_list)
3836 if (dp->target == sdp->id) {
3837 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3838 if (devip != dp)
3839 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3840 dp->uas_bm);
3841 }
3842 break;
3843 case 0x7: /* download MC with offsets, save, and ACT */
3844 /* set UA on all devices (LUs) in this target */
3845 list_for_each_entry(dp,
3846 &devip->sdbg_host->dev_info_list,
3847 dev_list)
3848 if (dp->target == sdp->id)
3849 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3850 dp->uas_bm);
3851 break;
3852 default:
3853 /* do nothing for this command for other mode values */
3854 break;
3855 }
3856 return 0;
3857}
3858
Douglas Gilbertfd321192016-04-25 12:16:33 -04003859static int resp_comp_write(struct scsi_cmnd *scp,
3860 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003861{
3862 u8 *cmd = scp->cmnd;
3863 u8 *arr;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003864 struct sdeb_store_info *sip = devip2sip(devip, true);
3865 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003866 u64 lba;
3867 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003868 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003869 u8 num;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003870 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003871 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003872
Douglas Gilbertd467d312014-11-26 12:33:48 -05003873 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003874 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3875 if (0 == num)
3876 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003877 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003878 (cmd[1] & 0xe0)) {
3879 mk_sense_invalid_opcode(scp);
3880 return check_condition_result;
3881 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003882 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3883 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003884 (cmd[1] & 0xe0) == 0)
3885 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3886 "to DIF device\n");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003887 ret = check_device_access_params(scp, lba, num, false);
3888 if (ret)
3889 return ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003890 dnum = 2 * num;
Kees Cook6396bb22018-06-12 14:03:40 -07003891 arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003892 if (NULL == arr) {
3893 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3894 INSUFF_RES_ASCQ);
3895 return check_condition_result;
3896 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003897
Douglas Gilbert67da4132020-04-21 11:14:20 -04003898 write_lock(macc_lckp);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003899
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003900 ret = do_dout_fetch(scp, dnum, arr);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003901 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003902 retval = DID_ERROR << 16;
3903 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003904 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003905 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3906 "indicated=%u, IO sent=%d bytes\n", my_name,
3907 dnum * lb_size, ret);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04003908 if (!comp_write_worker(sip, lba, num, arr, false)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003909 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003910 retval = check_condition_result;
3911 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003912 }
3913 if (scsi_debug_lbp())
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003914 map_region(sip, lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003915cleanup:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003916 write_unlock(macc_lckp);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003917 kfree(arr);
3918 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003919}
3920
Martin K. Petersen44d92692009-10-15 14:45:27 -04003921struct unmap_block_desc {
3922 __be64 lba;
3923 __be32 blocks;
3924 __be32 __reserved;
3925};
3926
Douglas Gilbertfd321192016-04-25 12:16:33 -04003927static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003928{
3929 unsigned char *buf;
3930 struct unmap_block_desc *desc;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003931 struct sdeb_store_info *sip = devip2sip(devip, true);
3932 rwlock_t *macc_lckp = &sip->macc_lck;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003933 unsigned int i, payload_len, descriptors;
3934 int ret;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003935
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003936 if (!scsi_debug_lbp())
3937 return 0; /* fib and say its done */
3938 payload_len = get_unaligned_be16(scp->cmnd + 7);
3939 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003940
3941 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003942 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003943 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003944 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003945 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003946
Douglas Gilbertb333a812016-04-25 12:16:30 -04003947 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003948 if (!buf) {
3949 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3950 INSUFF_RES_ASCQ);
3951 return check_condition_result;
3952 }
3953
3954 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003955
3956 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3957 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3958
3959 desc = (void *)&buf[8];
3960
Douglas Gilbert67da4132020-04-21 11:14:20 -04003961 write_lock(macc_lckp);
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003962
Martin K. Petersen44d92692009-10-15 14:45:27 -04003963 for (i = 0 ; i < descriptors ; i++) {
3964 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3965 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3966
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003967 ret = check_device_access_params(scp, lba, num, true);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003968 if (ret)
3969 goto out;
3970
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003971 unmap_region(sip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003972 }
3973
3974 ret = 0;
3975
3976out:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003977 write_unlock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003978 kfree(buf);
3979
3980 return ret;
3981}
3982
3983#define SDEBUG_GET_LBA_STATUS_LEN 32
3984
Douglas Gilbertfd321192016-04-25 12:16:33 -04003985static int resp_get_lba_status(struct scsi_cmnd *scp,
3986 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003987{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003988 u8 *cmd = scp->cmnd;
3989 u64 lba;
3990 u32 alloc_len, mapped, num;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003991 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003992 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003993
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003994 lba = get_unaligned_be64(cmd + 2);
3995 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003996
3997 if (alloc_len < 24)
3998 return 0;
3999
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05004000 ret = check_device_access_params(scp, lba, 1, false);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004001 if (ret)
4002 return ret;
4003
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004004 if (scsi_debug_lbp()) {
4005 struct sdeb_store_info *sip = devip2sip(devip, true);
4006
Douglas Gilbert87c715d2020-04-21 11:14:18 -04004007 mapped = map_state(sip, lba, &num);
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004008 } else {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004009 mapped = 1;
4010 /* following just in case virtual_gb changed */
4011 sdebug_capacity = get_sdebug_capacity();
4012 if (sdebug_capacity - lba <= 0xffffffff)
4013 num = sdebug_capacity - lba;
4014 else
4015 num = 0xffffffff;
4016 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04004017
4018 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004019 put_unaligned_be32(20, arr); /* Parameter Data Length */
4020 put_unaligned_be64(lba, arr + 8); /* LBA */
4021 put_unaligned_be32(num, arr + 16); /* Number of blocks */
4022 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04004023
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004024 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004025}
4026
Douglas Gilbert80c49562018-02-09 21:36:39 -05004027static int resp_sync_cache(struct scsi_cmnd *scp,
4028 struct sdebug_dev_info *devip)
4029{
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04004030 int res = 0;
Douglas Gilbert80c49562018-02-09 21:36:39 -05004031 u64 lba;
4032 u32 num_blocks;
4033 u8 *cmd = scp->cmnd;
4034
4035 if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
4036 lba = get_unaligned_be32(cmd + 2);
4037 num_blocks = get_unaligned_be16(cmd + 7);
4038 } else { /* SYNCHRONIZE_CACHE(16) */
4039 lba = get_unaligned_be64(cmd + 2);
4040 num_blocks = get_unaligned_be32(cmd + 10);
4041 }
4042 if (lba + num_blocks > sdebug_capacity) {
4043 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4044 return check_condition_result;
4045 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04004046 if (!write_since_sync || (cmd[1] & 0x2))
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04004047 res = SDEG_RES_IMMED_MASK;
4048 else /* delay if write_since_sync and IMMED clear */
4049 write_since_sync = false;
4050 return res;
Douglas Gilbert80c49562018-02-09 21:36:39 -05004051}
4052
Douglas Gilberted9f3e22020-04-21 11:14:22 -04004053/*
4054 * Assuming the LBA+num_blocks is not out-of-range, this function will return
4055 * CONDITION MET if the specified blocks will/have fitted in the cache, and
4056 * a GOOD status otherwise. Model a disk with a big cache and yield
4057 * CONDITION MET. Actually tries to bring range in main memory into the
4058 * cache associated with the CPU(s).
4059 */
4060static int resp_pre_fetch(struct scsi_cmnd *scp,
4061 struct sdebug_dev_info *devip)
4062{
4063 int res = 0;
4064 u64 lba;
4065 u64 block, rest = 0;
4066 u32 nblks;
4067 u8 *cmd = scp->cmnd;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004068 struct sdeb_store_info *sip = devip2sip(devip, true);
4069 rwlock_t *macc_lckp = &sip->macc_lck;
4070 u8 *fsp = sip->storep;
Douglas Gilberted9f3e22020-04-21 11:14:22 -04004071
4072 if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */
4073 lba = get_unaligned_be32(cmd + 2);
4074 nblks = get_unaligned_be16(cmd + 7);
4075 } else { /* PRE-FETCH(16) */
4076 lba = get_unaligned_be64(cmd + 2);
4077 nblks = get_unaligned_be32(cmd + 10);
4078 }
4079 if (lba + nblks > sdebug_capacity) {
4080 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4081 return check_condition_result;
4082 }
4083 if (!fsp)
4084 goto fini;
4085 /* PRE-FETCH spec says nothing about LBP or PI so skip them */
4086 block = do_div(lba, sdebug_store_sectors);
4087 if (block + nblks > sdebug_store_sectors)
4088 rest = block + nblks - sdebug_store_sectors;
4089
4090 /* Try to bring the PRE-FETCH range into CPU's cache */
4091 read_lock(macc_lckp);
4092 prefetch_range(fsp + (sdebug_sector_size * block),
4093 (nblks - rest) * sdebug_sector_size);
4094 if (rest)
4095 prefetch_range(fsp, rest * sdebug_sector_size);
4096 read_unlock(macc_lckp);
4097fini:
4098 if (cmd[1] & 0x2)
4099 res = SDEG_RES_IMMED_MASK;
4100 return res | condition_met_result;
4101}
4102
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004103#define RL_BUCKET_ELEMS 8
4104
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004105/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
4106 * (W-LUN), the normal Linux scanning logic does not associate it with a
4107 * device (e.g. /dev/sg7). The following magic will make that association:
4108 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
4109 * where <n> is a host number. If there are multiple targets in a host then
4110 * the above will associate a W-LUN to each target. To only get a W-LUN
4111 * for target 2, then use "echo '- 2 49409' > scan" .
4112 */
4113static int resp_report_luns(struct scsi_cmnd *scp,
4114 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02004116 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004117 unsigned int alloc_len;
4118 unsigned char select_report;
4119 u64 lun;
4120 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004121 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004122 unsigned int lun_cnt; /* normal LUN count (max: 256) */
4123 unsigned int wlun_cnt; /* report luns W-LUN count */
4124 unsigned int tlun_cnt; /* total LUN count */
4125 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004126 int k, j, n, res;
4127 unsigned int off_rsp = 0;
4128 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004130 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004131
4132 select_report = cmd[2];
4133 alloc_len = get_unaligned_be32(cmd + 6);
4134
4135 if (alloc_len < 4) {
4136 pr_err("alloc len too small %d\n", alloc_len);
4137 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 return check_condition_result;
4139 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004140
4141 switch (select_report) {
4142 case 0: /* all LUNs apart from W-LUNs */
4143 lun_cnt = sdebug_max_luns;
4144 wlun_cnt = 0;
4145 break;
4146 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004147 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004148 wlun_cnt = 1;
4149 break;
4150 case 2: /* all LUNs */
4151 lun_cnt = sdebug_max_luns;
4152 wlun_cnt = 1;
4153 break;
4154 case 0x10: /* only administrative LUs */
4155 case 0x11: /* see SPC-5 */
4156 case 0x12: /* only subsiduary LUs owned by referenced LU */
4157 default:
4158 pr_debug("select report invalid %d\n", select_report);
4159 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
4160 return check_condition_result;
4161 }
4162
4163 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004164 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004165
4166 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004167 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
4168 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004169 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
4170 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
4171
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004172 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004173 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004174 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4175 memset(arr, 0, sizeof(arr));
4176 lun_p = (struct scsi_lun *)&arr[0];
4177 if (k == 0) {
4178 put_unaligned_be32(rlen, &arr[0]);
4179 ++lun_p;
4180 j = 1;
4181 }
4182 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4183 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4184 break;
4185 int_to_scsilun(lun++, lun_p);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04004186 if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4187 lun_p->scsi_lun[0] |= 0x40;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004188 }
4189 if (j < RL_BUCKET_ELEMS)
4190 break;
4191 n = j * sz_lun;
4192 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4193 if (res)
4194 return res;
4195 off_rsp += n;
4196 }
4197 if (wlun_cnt) {
4198 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4199 ++j;
4200 }
4201 if (j > 0)
4202 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004203 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204}
4205
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004206static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4207{
4208 bool is_bytchk3 = false;
4209 u8 bytchk;
4210 int ret, j;
4211 u32 vnum, a_num, off;
4212 const u32 lb_size = sdebug_sector_size;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004213 u64 lba;
4214 u8 *arr;
4215 u8 *cmd = scp->cmnd;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004216 struct sdeb_store_info *sip = devip2sip(devip, true);
4217 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004218
4219 bytchk = (cmd[1] >> 1) & 0x3;
4220 if (bytchk == 0) {
4221 return 0; /* always claim internal verify okay */
4222 } else if (bytchk == 2) {
4223 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4224 return check_condition_result;
4225 } else if (bytchk == 3) {
4226 is_bytchk3 = true; /* 1 block sent, compared repeatedly */
4227 }
4228 switch (cmd[0]) {
4229 case VERIFY_16:
4230 lba = get_unaligned_be64(cmd + 2);
4231 vnum = get_unaligned_be32(cmd + 10);
4232 break;
4233 case VERIFY: /* is VERIFY(10) */
4234 lba = get_unaligned_be32(cmd + 2);
4235 vnum = get_unaligned_be16(cmd + 7);
4236 break;
4237 default:
4238 mk_sense_invalid_opcode(scp);
4239 return check_condition_result;
4240 }
4241 a_num = is_bytchk3 ? 1 : vnum;
4242 /* Treat following check like one for read (i.e. no write) access */
4243 ret = check_device_access_params(scp, lba, a_num, false);
4244 if (ret)
4245 return ret;
4246
4247 arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4248 if (!arr) {
4249 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4250 INSUFF_RES_ASCQ);
4251 return check_condition_result;
4252 }
4253 /* Not changing store, so only need read access */
Douglas Gilbert67da4132020-04-21 11:14:20 -04004254 read_lock(macc_lckp);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004255
4256 ret = do_dout_fetch(scp, a_num, arr);
4257 if (ret == -1) {
4258 ret = DID_ERROR << 16;
4259 goto cleanup;
4260 } else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4261 sdev_printk(KERN_INFO, scp->device,
4262 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4263 my_name, __func__, a_num * lb_size, ret);
4264 }
4265 if (is_bytchk3) {
4266 for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4267 memcpy(arr + off, arr, lb_size);
4268 }
4269 ret = 0;
4270 if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4271 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4272 ret = check_condition_result;
4273 goto cleanup;
4274 }
4275cleanup:
Douglas Gilbert67da4132020-04-21 11:14:20 -04004276 read_unlock(macc_lckp);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004277 kfree(arr);
4278 return ret;
4279}
4280
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004281#define RZONES_DESC_HD 64
4282
4283/* Report zones depending on start LBA nad reporting options */
4284static int resp_report_zones(struct scsi_cmnd *scp,
4285 struct sdebug_dev_info *devip)
4286{
4287 unsigned int i, max_zones, rep_max_zones, nrz = 0;
4288 int ret = 0;
4289 u32 alloc_len, rep_opts, rep_len;
4290 bool partial;
4291 u64 lba, zs_lba;
4292 u8 *arr = NULL, *desc;
4293 u8 *cmd = scp->cmnd;
4294 struct sdeb_zone_state *zsp;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004295 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004296 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4297
4298 if (!sdebug_dev_is_zoned(devip)) {
4299 mk_sense_invalid_opcode(scp);
4300 return check_condition_result;
4301 }
4302 zs_lba = get_unaligned_be64(cmd + 2);
4303 alloc_len = get_unaligned_be32(cmd + 10);
4304 rep_opts = cmd[14] & 0x3f;
4305 partial = cmd[14] & 0x80;
4306
4307 if (zs_lba >= sdebug_capacity) {
4308 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4309 return check_condition_result;
4310 }
4311
Damien Le Moal108e36f2020-05-07 11:35:26 +09004312 max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004313 rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4314 max_zones);
4315
4316 arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4317 if (!arr) {
4318 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4319 INSUFF_RES_ASCQ);
4320 return check_condition_result;
4321 }
4322
4323 read_lock(macc_lckp);
4324
4325 desc = arr + 64;
4326 for (i = 0; i < max_zones; i++) {
4327 lba = zs_lba + devip->zsize * i;
4328 if (lba > sdebug_capacity)
4329 break;
4330 zsp = zbc_zone(devip, lba);
4331 switch (rep_opts) {
4332 case 0x00:
4333 /* All zones */
4334 break;
4335 case 0x01:
4336 /* Empty zones */
4337 if (zsp->z_cond != ZC1_EMPTY)
4338 continue;
4339 break;
4340 case 0x02:
4341 /* Implicit open zones */
4342 if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4343 continue;
4344 break;
4345 case 0x03:
4346 /* Explicit open zones */
4347 if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4348 continue;
4349 break;
4350 case 0x04:
4351 /* Closed zones */
4352 if (zsp->z_cond != ZC4_CLOSED)
4353 continue;
4354 break;
4355 case 0x05:
4356 /* Full zones */
4357 if (zsp->z_cond != ZC5_FULL)
4358 continue;
4359 break;
4360 case 0x06:
4361 case 0x07:
4362 case 0x10:
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004363 /*
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004364 * Read-only, offline, reset WP recommended are
4365 * not emulated: no zones to report;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004366 */
4367 continue;
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004368 case 0x11:
4369 /* non-seq-resource set */
4370 if (!zsp->z_non_seq_resource)
4371 continue;
4372 break;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004373 case 0x3f:
4374 /* Not write pointer (conventional) zones */
4375 if (!zbc_zone_is_conv(zsp))
4376 continue;
4377 break;
4378 default:
4379 mk_sense_buffer(scp, ILLEGAL_REQUEST,
4380 INVALID_FIELD_IN_CDB, 0);
4381 ret = check_condition_result;
4382 goto fini;
4383 }
4384
4385 if (nrz < rep_max_zones) {
4386 /* Fill zone descriptor */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004387 desc[0] = zsp->z_type;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004388 desc[1] = zsp->z_cond << 4;
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004389 if (zsp->z_non_seq_resource)
4390 desc[1] |= 1 << 1;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004391 put_unaligned_be64((u64)zsp->z_size, desc + 8);
4392 put_unaligned_be64((u64)zsp->z_start, desc + 16);
4393 put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4394 desc += 64;
4395 }
4396
4397 if (partial && nrz >= rep_max_zones)
4398 break;
4399
4400 nrz++;
4401 }
4402
4403 /* Report header */
4404 put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4405 put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4406
4407 rep_len = (unsigned long)desc - (unsigned long)arr;
4408 ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4409
4410fini:
4411 read_unlock(macc_lckp);
4412 kfree(arr);
4413 return ret;
4414}
4415
4416/* Logic transplanted from tcmu-runner, file_zbc.c */
4417static void zbc_open_all(struct sdebug_dev_info *devip)
4418{
4419 struct sdeb_zone_state *zsp = &devip->zstate[0];
4420 unsigned int i;
4421
4422 for (i = 0; i < devip->nr_zones; i++, zsp++) {
4423 if (zsp->z_cond == ZC4_CLOSED)
4424 zbc_open_zone(devip, &devip->zstate[i], true);
4425 }
4426}
4427
4428static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4429{
4430 int res = 0;
4431 u64 z_id;
4432 enum sdebug_z_cond zc;
4433 u8 *cmd = scp->cmnd;
4434 struct sdeb_zone_state *zsp;
4435 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004436 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004437 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4438
4439 if (!sdebug_dev_is_zoned(devip)) {
4440 mk_sense_invalid_opcode(scp);
4441 return check_condition_result;
4442 }
4443
4444 write_lock(macc_lckp);
4445
4446 if (all) {
4447 /* Check if all closed zones can be open */
4448 if (devip->max_open &&
4449 devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4450 mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4451 INSUFF_ZONE_ASCQ);
4452 res = check_condition_result;
4453 goto fini;
4454 }
4455 /* Open all closed zones */
4456 zbc_open_all(devip);
4457 goto fini;
4458 }
4459
4460 /* Open the specified zone */
4461 z_id = get_unaligned_be64(cmd + 2);
4462 if (z_id >= sdebug_capacity) {
4463 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4464 res = check_condition_result;
4465 goto fini;
4466 }
4467
4468 zsp = zbc_zone(devip, z_id);
4469 if (z_id != zsp->z_start) {
4470 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4471 res = check_condition_result;
4472 goto fini;
4473 }
4474 if (zbc_zone_is_conv(zsp)) {
4475 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4476 res = check_condition_result;
4477 goto fini;
4478 }
4479
4480 zc = zsp->z_cond;
4481 if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4482 goto fini;
4483
4484 if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4485 mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4486 INSUFF_ZONE_ASCQ);
4487 res = check_condition_result;
4488 goto fini;
4489 }
4490
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004491 zbc_open_zone(devip, zsp, true);
4492fini:
4493 write_unlock(macc_lckp);
4494 return res;
4495}
4496
4497static void zbc_close_all(struct sdebug_dev_info *devip)
4498{
4499 unsigned int i;
4500
4501 for (i = 0; i < devip->nr_zones; i++)
4502 zbc_close_zone(devip, &devip->zstate[i]);
4503}
4504
4505static int resp_close_zone(struct scsi_cmnd *scp,
4506 struct sdebug_dev_info *devip)
4507{
4508 int res = 0;
4509 u64 z_id;
4510 u8 *cmd = scp->cmnd;
4511 struct sdeb_zone_state *zsp;
4512 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004513 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004514 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4515
4516 if (!sdebug_dev_is_zoned(devip)) {
4517 mk_sense_invalid_opcode(scp);
4518 return check_condition_result;
4519 }
4520
4521 write_lock(macc_lckp);
4522
4523 if (all) {
4524 zbc_close_all(devip);
4525 goto fini;
4526 }
4527
4528 /* Close specified zone */
4529 z_id = get_unaligned_be64(cmd + 2);
4530 if (z_id >= sdebug_capacity) {
4531 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4532 res = check_condition_result;
4533 goto fini;
4534 }
4535
4536 zsp = zbc_zone(devip, z_id);
4537 if (z_id != zsp->z_start) {
4538 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4539 res = check_condition_result;
4540 goto fini;
4541 }
4542 if (zbc_zone_is_conv(zsp)) {
4543 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4544 res = check_condition_result;
4545 goto fini;
4546 }
4547
4548 zbc_close_zone(devip, zsp);
4549fini:
4550 write_unlock(macc_lckp);
4551 return res;
4552}
4553
4554static void zbc_finish_zone(struct sdebug_dev_info *devip,
4555 struct sdeb_zone_state *zsp, bool empty)
4556{
4557 enum sdebug_z_cond zc = zsp->z_cond;
4558
4559 if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4560 zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4561 if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4562 zbc_close_zone(devip, zsp);
4563 if (zsp->z_cond == ZC4_CLOSED)
4564 devip->nr_closed--;
4565 zsp->z_wp = zsp->z_start + zsp->z_size;
4566 zsp->z_cond = ZC5_FULL;
4567 }
4568}
4569
4570static void zbc_finish_all(struct sdebug_dev_info *devip)
4571{
4572 unsigned int i;
4573
4574 for (i = 0; i < devip->nr_zones; i++)
4575 zbc_finish_zone(devip, &devip->zstate[i], false);
4576}
4577
4578static int resp_finish_zone(struct scsi_cmnd *scp,
4579 struct sdebug_dev_info *devip)
4580{
4581 struct sdeb_zone_state *zsp;
4582 int res = 0;
4583 u64 z_id;
4584 u8 *cmd = scp->cmnd;
4585 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004586 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004587 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4588
4589 if (!sdebug_dev_is_zoned(devip)) {
4590 mk_sense_invalid_opcode(scp);
4591 return check_condition_result;
4592 }
4593
4594 write_lock(macc_lckp);
4595
4596 if (all) {
4597 zbc_finish_all(devip);
4598 goto fini;
4599 }
4600
4601 /* Finish the specified zone */
4602 z_id = get_unaligned_be64(cmd + 2);
4603 if (z_id >= sdebug_capacity) {
4604 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4605 res = check_condition_result;
4606 goto fini;
4607 }
4608
4609 zsp = zbc_zone(devip, z_id);
4610 if (z_id != zsp->z_start) {
4611 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4612 res = check_condition_result;
4613 goto fini;
4614 }
4615 if (zbc_zone_is_conv(zsp)) {
4616 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4617 res = check_condition_result;
4618 goto fini;
4619 }
4620
4621 zbc_finish_zone(devip, zsp, true);
4622fini:
4623 write_unlock(macc_lckp);
4624 return res;
4625}
4626
4627static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4628 struct sdeb_zone_state *zsp)
4629{
4630 enum sdebug_z_cond zc;
4631
4632 if (zbc_zone_is_conv(zsp))
4633 return;
4634
4635 zc = zsp->z_cond;
4636 if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4637 zbc_close_zone(devip, zsp);
4638
4639 if (zsp->z_cond == ZC4_CLOSED)
4640 devip->nr_closed--;
4641
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004642 zsp->z_non_seq_resource = false;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004643 zsp->z_wp = zsp->z_start;
4644 zsp->z_cond = ZC1_EMPTY;
4645}
4646
4647static void zbc_rwp_all(struct sdebug_dev_info *devip)
4648{
4649 unsigned int i;
4650
4651 for (i = 0; i < devip->nr_zones; i++)
4652 zbc_rwp_zone(devip, &devip->zstate[i]);
4653}
4654
4655static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4656{
4657 struct sdeb_zone_state *zsp;
4658 int res = 0;
4659 u64 z_id;
4660 u8 *cmd = scp->cmnd;
4661 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004662 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004663 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4664
4665 if (!sdebug_dev_is_zoned(devip)) {
4666 mk_sense_invalid_opcode(scp);
4667 return check_condition_result;
4668 }
4669
4670 write_lock(macc_lckp);
4671
4672 if (all) {
4673 zbc_rwp_all(devip);
4674 goto fini;
4675 }
4676
4677 z_id = get_unaligned_be64(cmd + 2);
4678 if (z_id >= sdebug_capacity) {
4679 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4680 res = check_condition_result;
4681 goto fini;
4682 }
4683
4684 zsp = zbc_zone(devip, z_id);
4685 if (z_id != zsp->z_start) {
4686 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4687 res = check_condition_result;
4688 goto fini;
4689 }
4690 if (zbc_zone_is_conv(zsp)) {
4691 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4692 res = check_condition_result;
4693 goto fini;
4694 }
4695
4696 zbc_rwp_zone(devip, zsp);
4697fini:
4698 write_unlock(macc_lckp);
4699 return res;
4700}
4701
Douglas Gilbertc4837392016-05-06 00:40:26 -04004702static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4703{
John Garryc10fa552020-07-09 20:23:20 +08004704 u16 hwq;
John Garryf7c4cdc2020-08-19 23:20:33 +08004705 u32 tag = blk_mq_unique_tag(cmnd->request);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004706
John Garryf7c4cdc2020-08-19 23:20:33 +08004707 hwq = blk_mq_unique_tag_to_hwq(tag);
John Garryc10fa552020-07-09 20:23:20 +08004708
John Garryf7c4cdc2020-08-19 23:20:33 +08004709 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4710 if (WARN_ON_ONCE(hwq >= submit_queues))
4711 hwq = 0;
John Garryc10fa552020-07-09 20:23:20 +08004712
Bart Van Assche458df782018-01-26 08:52:19 -08004713 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004714}
4715
John Garryc10fa552020-07-09 20:23:20 +08004716static u32 get_tag(struct scsi_cmnd *cmnd)
4717{
4718 return blk_mq_unique_tag(cmnd->request);
4719}
4720
Douglas Gilbertc4837392016-05-06 00:40:26 -04004721/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004722static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723{
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004724 bool aborted = sd_dp->aborted;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004725 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004726 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004728 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004729 struct sdebug_queued_cmd *sqcp;
4730 struct scsi_cmnd *scp;
4731 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004733 if (unlikely(aborted))
4734 sd_dp->aborted = false;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004735 qc_idx = sd_dp->qc_idx;
4736 sqp = sdebug_q_arr + sd_dp->sqa_idx;
4737 if (sdebug_statistics) {
4738 atomic_inc(&sdebug_completions);
4739 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4740 atomic_inc(&sdebug_miss_cpus);
4741 }
4742 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4743 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 return;
4745 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004746 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05304747 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004748 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004749 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004750 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004751 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
John Garryc10fa552020-07-09 20:23:20 +08004752 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4753 sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 return;
4755 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004756 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004757 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004758 atomic_dec(&devip->num_in_q);
4759 else
Tomas Winklerc12879702015-07-28 16:54:20 +03004760 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004761 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004762 retiring = 1;
4763
4764 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004765 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4766 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03004767 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004768 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004770
4771 if (unlikely(retiring)) { /* user has reduced max_queue */
4772 int k, retval;
4773
4774 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004775 if (qc_idx >= retval) {
4776 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03004777 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004778 return;
4779 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004780 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004781 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004782 atomic_set(&retired_max_queue, 0);
4783 else
4784 atomic_set(&retired_max_queue, k + 1);
4785 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004786 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004787 if (unlikely(aborted)) {
4788 if (sdebug_verbose)
4789 pr_info("bypassing scsi_done() due to aborted cmd\n");
4790 return;
4791 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004792 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793}
4794
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004795/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004796static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004797{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004798 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4799 hrt);
4800 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004801 return HRTIMER_NORESTART;
4802}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
Douglas Gilberta10bc122016-04-25 12:16:32 -04004804/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004805static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04004806{
4807 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4808 ew.work);
4809 sdebug_q_cmd_complete(sd_dp);
4810}
4811
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004812static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02004813static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004814
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004815static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4816{
4817 struct sdeb_zone_state *zsp;
4818 sector_t capacity = get_sdebug_capacity();
4819 sector_t zstart = 0;
4820 unsigned int i;
4821
4822 /*
Damien Le Moal98e0a682020-04-22 19:42:20 +09004823 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
4824 * a zone size allowing for at least 4 zones on the device. Otherwise,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004825 * use the specified zone size checking that at least 2 zones can be
4826 * created for the device.
4827 */
Damien Le Moal98e0a682020-04-22 19:42:20 +09004828 if (!sdeb_zbc_zone_size_mb) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004829 devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4830 >> ilog2(sdebug_sector_size);
4831 while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4832 devip->zsize >>= 1;
4833 if (devip->zsize < 2) {
4834 pr_err("Device capacity too small\n");
4835 return -EINVAL;
4836 }
4837 } else {
Damien Le Moal108e36f2020-05-07 11:35:26 +09004838 if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4839 pr_err("Zone size is not a power of 2\n");
4840 return -EINVAL;
4841 }
Damien Le Moal98e0a682020-04-22 19:42:20 +09004842 devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004843 >> ilog2(sdebug_sector_size);
4844 if (devip->zsize >= capacity) {
4845 pr_err("Zone size too large for device capacity\n");
4846 return -EINVAL;
4847 }
4848 }
4849
Damien Le Moal108e36f2020-05-07 11:35:26 +09004850 devip->zsize_shift = ilog2(devip->zsize);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004851 devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4852
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09004853 if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4854 pr_err("Number of conventional zones too large\n");
4855 return -EINVAL;
4856 }
4857 devip->nr_conv_zones = sdeb_zbc_nr_conv;
4858
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004859 if (devip->zmodel == BLK_ZONED_HM) {
4860 /* zbc_max_open_zones can be 0, meaning "not reported" */
4861 if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4862 devip->max_open = (devip->nr_zones - 1) / 2;
4863 else
4864 devip->max_open = sdeb_zbc_max_open;
4865 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004866
4867 devip->zstate = kcalloc(devip->nr_zones,
4868 sizeof(struct sdeb_zone_state), GFP_KERNEL);
4869 if (!devip->zstate)
4870 return -ENOMEM;
4871
4872 for (i = 0; i < devip->nr_zones; i++) {
4873 zsp = &devip->zstate[i];
4874
4875 zsp->z_start = zstart;
4876
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09004877 if (i < devip->nr_conv_zones) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004878 zsp->z_type = ZBC_ZONE_TYPE_CNV;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004879 zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4880 zsp->z_wp = (sector_t)-1;
4881 } else {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004882 if (devip->zmodel == BLK_ZONED_HM)
4883 zsp->z_type = ZBC_ZONE_TYPE_SWR;
4884 else
4885 zsp->z_type = ZBC_ZONE_TYPE_SWP;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004886 zsp->z_cond = ZC1_EMPTY;
4887 zsp->z_wp = zsp->z_start;
4888 }
4889
4890 if (zsp->z_start + devip->zsize < capacity)
4891 zsp->z_size = devip->zsize;
4892 else
4893 zsp->z_size = capacity - zsp->z_start;
4894
4895 zstart += zsp->z_size;
4896 }
4897
4898 return 0;
4899}
4900
Douglas Gilbertfd321192016-04-25 12:16:33 -04004901static struct sdebug_dev_info *sdebug_device_create(
4902 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004903{
4904 struct sdebug_dev_info *devip;
4905
4906 devip = kzalloc(sizeof(*devip), flags);
4907 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004908 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02004909 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004910 else if (sdebug_uuid_ctl == 2) {
4911 if (got_shared_uuid)
4912 devip->lu_name = shared_uuid;
4913 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02004914 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004915 got_shared_uuid = true;
4916 devip->lu_name = shared_uuid;
4917 }
4918 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004919 devip->sdbg_host = sdbg_host;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004920 if (sdeb_zbc_in_use) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004921 devip->zmodel = sdeb_zbc_model;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004922 if (sdebug_device_create_zones(devip)) {
4923 kfree(devip);
4924 return NULL;
4925 }
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004926 } else {
4927 devip->zmodel = BLK_ZONED_NONE;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004928 }
4929 devip->sdbg_host = sdbg_host;
Douglas Gilbertfc136382020-07-24 11:55:31 -04004930 devip->create_ts = ktime_get_boottime();
4931 atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004932 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
4933 }
4934 return devip;
4935}
4936
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004937static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004939 struct sdebug_host_info *sdbg_host;
4940 struct sdebug_dev_info *open_devip = NULL;
4941 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004943 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
4944 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004945 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004947 }
Douglas Gilbertad0c7772020-08-21 00:22:49 -04004948
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
4950 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05004951 (devip->target == sdev->id) &&
4952 (devip->lun == sdev->lun))
4953 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954 else {
4955 if ((!devip->used) && (!open_devip))
4956 open_devip = devip;
4957 }
4958 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004959 if (!open_devip) { /* try and make a new one */
4960 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
4961 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004962 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 return NULL;
4964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09004966
4967 open_devip->channel = sdev->channel;
4968 open_devip->target = sdev->id;
4969 open_devip->lun = sdev->lun;
4970 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004971 atomic_set(&open_devip->num_in_q, 0);
4972 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004973 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09004974 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975}
4976
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004977static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004979 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03004980 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004981 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004982 return 0;
4983}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004985static int scsi_debug_slave_configure(struct scsi_device *sdp)
4986{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004987 struct sdebug_dev_info *devip =
4988 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09004989
Douglas Gilbert773642d2016-04-25 12:16:28 -04004990 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03004991 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004992 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004993 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
4994 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
4995 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004996 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004997 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004998 return 1; /* no resources, will be marked offline */
4999 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01005000 sdp->hostdata = devip;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005001 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005002 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005003 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005004 return 0;
5005}
5006
5007static void scsi_debug_slave_destroy(struct scsi_device *sdp)
5008{
5009 struct sdebug_dev_info *devip =
5010 (struct sdebug_dev_info *)sdp->hostdata;
5011
Douglas Gilbert773642d2016-04-25 12:16:28 -04005012 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03005013 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005014 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5015 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005016 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005017 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005018 sdp->hostdata = NULL;
5019 }
5020}
5021
Douglas Gilbert10bde982018-01-10 16:57:31 -05005022static void stop_qc_helper(struct sdebug_defer *sd_dp,
5023 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005024{
5025 if (!sd_dp)
5026 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005027 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005028 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005029 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005030 cancel_work_sync(&sd_dp->ew.work);
5031}
5032
Douglas Gilberta10bc122016-04-25 12:16:32 -04005033/* If @cmnd found deletes its timer or work queue and returns true; else
5034 returns false */
5035static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005036{
5037 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005038 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005039 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005040 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005041 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005042 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005043 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005044
Douglas Gilbertc4837392016-05-06 00:40:26 -04005045 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5046 spin_lock_irqsave(&sqp->qc_lock, iflags);
5047 qmax = sdebug_max_queue;
5048 r_qmax = atomic_read(&retired_max_queue);
5049 if (r_qmax > qmax)
5050 qmax = r_qmax;
5051 for (k = 0; k < qmax; ++k) {
5052 if (test_bit(k, sqp->in_use_bm)) {
5053 sqcp = &sqp->qc_arr[k];
5054 if (cmnd != sqcp->a_cmnd)
5055 continue;
5056 /* found */
5057 devip = (struct sdebug_dev_info *)
5058 cmnd->device->hostdata;
5059 if (devip)
5060 atomic_dec(&devip->num_in_q);
5061 sqcp->a_cmnd = NULL;
5062 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005063 if (sd_dp) {
5064 l_defer_t = sd_dp->defer_t;
5065 sd_dp->defer_t = SDEB_DEFER_NONE;
5066 } else
5067 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005068 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005069 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005070 clear_bit(k, sqp->in_use_bm);
5071 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005072 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005073 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005074 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005075 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04005076 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005077}
5078
Douglas Gilberta10bc122016-04-25 12:16:32 -04005079/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005080static void stop_all_queued(void)
5081{
5082 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005083 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005084 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005085 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005086 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005087 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005088 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005089
Douglas Gilbertc4837392016-05-06 00:40:26 -04005090 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5091 spin_lock_irqsave(&sqp->qc_lock, iflags);
5092 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5093 if (test_bit(k, sqp->in_use_bm)) {
5094 sqcp = &sqp->qc_arr[k];
5095 if (sqcp->a_cmnd == NULL)
5096 continue;
5097 devip = (struct sdebug_dev_info *)
5098 sqcp->a_cmnd->device->hostdata;
5099 if (devip)
5100 atomic_dec(&devip->num_in_q);
5101 sqcp->a_cmnd = NULL;
5102 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005103 if (sd_dp) {
5104 l_defer_t = sd_dp->defer_t;
5105 sd_dp->defer_t = SDEB_DEFER_NONE;
5106 } else
5107 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005108 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005109 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005110 clear_bit(k, sqp->in_use_bm);
5111 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005112 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005113 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005114 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116}
5117
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005118/* Free queued command memory on heap */
5119static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005121 int j, k;
5122 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005123 struct sdebug_queued_cmd *sqcp;
5124
Douglas Gilbertc4837392016-05-06 00:40:26 -04005125 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5126 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5127 sqcp = &sqp->qc_arr[k];
5128 kfree(sqcp->sd_dp);
5129 sqcp->sd_dp = NULL;
5130 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132}
5133
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005134static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135{
Douglas Gilberta10bc122016-04-25 12:16:32 -04005136 bool ok;
5137
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005138 ++num_aborts;
5139 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04005140 ok = stop_queued_cmnd(SCpnt);
5141 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5142 sdev_printk(KERN_INFO, SCpnt->device,
5143 "%s: command%s found\n", __func__,
5144 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005146 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147}
5148
John Pittman91d4c752018-02-09 21:12:43 -05005149static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005152 if (SCpnt && SCpnt->device) {
5153 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005154 struct sdebug_dev_info *devip =
5155 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005156
Douglas Gilbert773642d2016-04-25 12:16:28 -04005157 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005158 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005160 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 }
5162 return SUCCESS;
5163}
5164
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005165static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5166{
5167 struct sdebug_host_info *sdbg_host;
5168 struct sdebug_dev_info *devip;
5169 struct scsi_device *sdp;
5170 struct Scsi_Host *hp;
5171 int k = 0;
5172
5173 ++num_target_resets;
5174 if (!SCpnt)
5175 goto lie;
5176 sdp = SCpnt->device;
5177 if (!sdp)
5178 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005179 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005180 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5181 hp = sdp->host;
5182 if (!hp)
5183 goto lie;
5184 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5185 if (sdbg_host) {
5186 list_for_each_entry(devip,
5187 &sdbg_host->dev_info_list,
5188 dev_list)
5189 if (devip->target == sdp->id) {
5190 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5191 ++k;
5192 }
5193 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005194 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005195 sdev_printk(KERN_INFO, sdp,
5196 "%s: %d device(s) found in target\n", __func__, k);
5197lie:
5198 return SUCCESS;
5199}
5200
John Pittman91d4c752018-02-09 21:12:43 -05005201static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202{
5203 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005204 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005205 struct scsi_device *sdp;
5206 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005207 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005210 if (!(SCpnt && SCpnt->device))
5211 goto lie;
5212 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005213 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005214 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5215 hp = sdp->host;
5216 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09005217 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005219 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05005220 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005221 dev_list) {
5222 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5223 ++k;
5224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 }
5226 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005227 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005228 sdev_printk(KERN_INFO, sdp,
5229 "%s: %d device(s) found in host\n", __func__, k);
5230lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 return SUCCESS;
5232}
5233
John Pittman91d4c752018-02-09 21:12:43 -05005234static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235{
John Pittman91d4c752018-02-09 21:12:43 -05005236 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005237 struct sdebug_dev_info *devip;
5238 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005241 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005242 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005243 spin_lock(&sdebug_host_list_lock);
5244 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005245 list_for_each_entry(devip, &sdbg_host->dev_info_list,
5246 dev_list) {
5247 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5248 ++k;
5249 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005250 }
5251 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04005253 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005254 sdev_printk(KERN_INFO, SCpnt->device,
5255 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 return SUCCESS;
5257}
5258
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005259static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260{
Christoph Hellwig1442f762020-03-24 08:25:26 +01005261 struct msdos_partition *pp;
John Pittman979e0dc2020-09-02 17:14:33 -04005262 int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 int sectors_per_part, num_sectors, k;
5264 int heads_by_sects, start_sec, end_sec;
5265
5266 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005267 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005269 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5270 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03005271 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 }
John Pittman8c657232020-09-02 17:14:34 -04005273 num_sectors = (int)get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04005275 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005277 starts[0] = sdebug_sectors_per;
John Pittman979e0dc2020-09-02 17:14:33 -04005278 max_part_secs = sectors_per_part;
5279 for (k = 1; k < sdebug_num_parts; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 starts[k] = ((k * sectors_per_part) / heads_by_sects)
5281 * heads_by_sects;
John Pittman979e0dc2020-09-02 17:14:33 -04005282 if (starts[k] - starts[k - 1] < max_part_secs)
5283 max_part_secs = starts[k] - starts[k - 1];
5284 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005285 starts[sdebug_num_parts] = num_sectors;
5286 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287
5288 ramp[510] = 0x55; /* magic partition markings */
5289 ramp[511] = 0xAA;
Christoph Hellwig1442f762020-03-24 08:25:26 +01005290 pp = (struct msdos_partition *)(ramp + 0x1be);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 for (k = 0; starts[k + 1]; ++k, ++pp) {
5292 start_sec = starts[k];
John Pittman979e0dc2020-09-02 17:14:33 -04005293 end_sec = starts[k] + max_part_secs - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 pp->boot_ind = 0;
5295
5296 pp->cyl = start_sec / heads_by_sects;
5297 pp->head = (start_sec - (pp->cyl * heads_by_sects))
5298 / sdebug_sectors_per;
5299 pp->sector = (start_sec % sdebug_sectors_per) + 1;
5300
5301 pp->end_cyl = end_sec / heads_by_sects;
5302 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
5303 / sdebug_sectors_per;
5304 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
5305
Akinobu Mita150c3542013-08-26 22:08:40 +09005306 pp->start_sect = cpu_to_le32(start_sec);
5307 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 pp->sys_ind = 0x83; /* plain Linux partition */
5309 }
5310}
5311
Douglas Gilbertc4837392016-05-06 00:40:26 -04005312static void block_unblock_all_queues(bool block)
5313{
5314 int j;
5315 struct sdebug_queue *sqp;
5316
5317 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5318 atomic_set(&sqp->blocked, (int)block);
5319}
5320
5321/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5322 * commands will be processed normally before triggers occur.
5323 */
5324static void tweak_cmnd_count(void)
5325{
5326 int count, modulo;
5327
5328 modulo = abs(sdebug_every_nth);
5329 if (modulo < 2)
5330 return;
5331 block_unblock_all_queues(true);
5332 count = atomic_read(&sdebug_cmnd_count);
5333 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5334 block_unblock_all_queues(false);
5335}
5336
5337static void clear_queue_stats(void)
5338{
5339 atomic_set(&sdebug_cmnd_count, 0);
5340 atomic_set(&sdebug_completions, 0);
5341 atomic_set(&sdebug_miss_cpus, 0);
5342 atomic_set(&sdebug_a_tsf, 0);
5343}
5344
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005345static bool inject_on_this_cmd(void)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005346{
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005347 if (sdebug_every_nth == 0)
5348 return false;
5349 return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005350}
5351
Douglas Gilberta2aede92020-04-21 11:14:21 -04005352#define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */
5353
Douglas Gilbertc4837392016-05-06 00:40:26 -04005354/* Complete the processing of the thread that queued a SCSI command to this
5355 * driver. It either completes the command by calling cmnd_done() or
5356 * schedules a hr timer or work queue then returns 0. Returns
5357 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5358 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04005359static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Martin Wilckf66b8512018-02-14 11:05:57 +01005360 int scsi_result,
5361 int (*pfp)(struct scsi_cmnd *,
5362 struct sdebug_dev_info *),
5363 int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364{
Douglas Gilberta2aede92020-04-21 11:14:21 -04005365 bool new_sd_dp;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005366 bool inject = false;
Douglas Gilbert771f7122021-03-03 20:41:07 -05005367 bool hipri = (cmnd->request->cmd_flags & REQ_HIPRI);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005368 int k, num_in_q, qdepth;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005369 unsigned long iflags;
5370 u64 ns_from_boot = 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005371 struct sdebug_queue *sqp;
5372 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03005373 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005374 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005376 if (unlikely(devip == NULL)) {
5377 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005378 scsi_result = DID_NO_CONNECT << 16;
5379 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03005381 sdp = cmnd->device;
5382
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005383 if (delta_jiff == 0)
5384 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385
Douglas Gilbertc4837392016-05-06 00:40:26 -04005386 sqp = get_queue(cmnd);
5387 spin_lock_irqsave(&sqp->qc_lock, iflags);
5388 if (unlikely(atomic_read(&sqp->blocked))) {
5389 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5390 return SCSI_MLQUEUE_HOST_BUSY;
5391 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005392 num_in_q = atomic_read(&devip->num_in_q);
5393 qdepth = cmnd->device->queue_depth;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005394 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005395 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005396 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005397 goto respond_in_thread;
5398 } else
5399 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005400 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005401 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5402 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005403 if ((num_in_q == (qdepth - 1)) &&
5404 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04005405 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005406 atomic_set(&sdebug_a_tsf, 0);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005407 inject = true;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005408 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005410 }
5411
Douglas Gilbertc4837392016-05-06 00:40:26 -04005412 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005413 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005414 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005415 if (scsi_result)
5416 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005417 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005418 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005419 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005420 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005421 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04005422 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005423 (scsi_result ? "status: TASK SET FULL" :
5424 "report: host busy"));
5425 if (scsi_result)
5426 goto respond_in_thread;
5427 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005428 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 }
Douglas Gilbert74595c02020-07-02 10:53:55 -04005430 set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005431 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005432 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005433 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005434 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005435 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005436 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05305437
Douglas Gilbert74595c02020-07-02 10:53:55 -04005438 if (!sd_dp) {
Douglas Gilbert10bde982018-01-10 16:57:31 -05005439 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
Douglas Gilbert74595c02020-07-02 10:53:55 -04005440 if (!sd_dp) {
5441 atomic_dec(&devip->num_in_q);
5442 clear_bit(k, sqp->in_use_bm);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005443 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilbert74595c02020-07-02 10:53:55 -04005444 }
Douglas Gilberta2aede92020-04-21 11:14:21 -04005445 new_sd_dp = true;
5446 } else {
5447 new_sd_dp = false;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005448 }
Martin Wilckf66b8512018-02-14 11:05:57 +01005449
John Garryc10fa552020-07-09 20:23:20 +08005450 /* Set the hostwide tag */
5451 if (sdebug_host_max_queue)
5452 sd_dp->hc_idx = get_tag(cmnd);
5453
Douglas Gilbert771f7122021-03-03 20:41:07 -05005454 if (hipri)
Douglas Gilberta2aede92020-04-21 11:14:21 -04005455 ns_from_boot = ktime_get_boottime_ns();
5456
5457 /* one of the resp_*() response functions is called here */
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005458 cmnd->result = pfp ? pfp(cmnd, devip) : 0;
Martin Wilckf66b8512018-02-14 11:05:57 +01005459 if (cmnd->result & SDEG_RES_IMMED_MASK) {
Martin Wilckf66b8512018-02-14 11:05:57 +01005460 cmnd->result &= ~SDEG_RES_IMMED_MASK;
5461 delta_jiff = ndelay = 0;
5462 }
5463 if (cmnd->result == 0 && scsi_result != 0)
5464 cmnd->result = scsi_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005465 if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
5466 if (atomic_read(&sdeb_inject_pending)) {
5467 mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
5468 atomic_set(&sdeb_inject_pending, 0);
5469 cmnd->result = check_condition_result;
5470 }
5471 }
Martin Wilckf66b8512018-02-14 11:05:57 +01005472
5473 if (unlikely(sdebug_verbose && cmnd->result))
5474 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5475 __func__, cmnd->result);
5476
Douglas Gilbert10bde982018-01-10 16:57:31 -05005477 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04005478 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005479
Douglas Gilbertb333a812016-04-25 12:16:30 -04005480 if (delta_jiff > 0) {
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005481 u64 ns = jiffies_to_nsecs(delta_jiff);
5482
5483 if (sdebug_random && ns < U32_MAX) {
5484 ns = prandom_u32_max((u32)ns);
5485 } else if (sdebug_random) {
5486 ns >>= 12; /* scale to 4 usec precision */
5487 if (ns < U32_MAX) /* over 4 hours max */
5488 ns = prandom_u32_max((u32)ns);
5489 ns <<= 12;
5490 }
5491 kt = ns_to_ktime(ns);
5492 } else { /* ndelay has a 4.2 second max */
5493 kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
5494 (u32)ndelay;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005495 if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5496 u64 d = ktime_get_boottime_ns() - ns_from_boot;
5497
5498 if (kt <= d) { /* elapsed duration >= kt */
Douglas Gilbert223f91b2020-08-13 11:57:38 -04005499 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005500 sqcp->a_cmnd = NULL;
5501 atomic_dec(&devip->num_in_q);
5502 clear_bit(k, sqp->in_use_bm);
Douglas Gilbert223f91b2020-08-13 11:57:38 -04005503 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005504 if (new_sd_dp)
5505 kfree(sd_dp);
5506 /* call scsi_done() from this thread */
5507 cmnd->scsi_done(cmnd);
5508 return 0;
5509 }
5510 /* otherwise reduce kt by elapsed time */
5511 kt -= d;
5512 }
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005513 }
Douglas Gilbert771f7122021-03-03 20:41:07 -05005514 if (hipri) {
5515 sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305516 spin_lock_irqsave(&sqp->qc_lock, iflags);
5517 if (!sd_dp->init_poll) {
5518 sd_dp->init_poll = true;
5519 sqcp->sd_dp = sd_dp;
5520 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5521 sd_dp->qc_idx = k;
5522 }
5523 sd_dp->defer_t = SDEB_DEFER_POLL;
5524 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5525 } else {
5526 if (!sd_dp->init_hrt) {
5527 sd_dp->init_hrt = true;
5528 sqcp->sd_dp = sd_dp;
5529 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5530 HRTIMER_MODE_REL_PINNED);
5531 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5532 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5533 sd_dp->qc_idx = k;
5534 }
5535 sd_dp->defer_t = SDEB_DEFER_HRT;
5536 /* schedule the invocation of scsi_done() for a later time */
5537 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005538 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005539 if (sdebug_statistics)
5540 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbertc4837392016-05-06 00:40:26 -04005541 } else { /* jdelay < 0, use work queue */
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005542 if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
5543 atomic_read(&sdeb_inject_pending)))
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005544 sd_dp->aborted = true;
Douglas Gilbert771f7122021-03-03 20:41:07 -05005545 if (hipri) {
5546 sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305547 spin_lock_irqsave(&sqp->qc_lock, iflags);
5548 if (!sd_dp->init_poll) {
5549 sd_dp->init_poll = true;
5550 sqcp->sd_dp = sd_dp;
5551 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5552 sd_dp->qc_idx = k;
5553 }
5554 sd_dp->defer_t = SDEB_DEFER_POLL;
5555 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5556 } else {
5557 if (!sd_dp->init_wq) {
5558 sd_dp->init_wq = true;
5559 sqcp->sd_dp = sd_dp;
5560 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5561 sd_dp->qc_idx = k;
5562 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5563 }
5564 sd_dp->defer_t = SDEB_DEFER_WQ;
5565 schedule_work(&sd_dp->ew.work);
5566 }
5567 if (sdebug_statistics)
5568 sd_dp->issuing_cpu = raw_smp_processor_id();
5569 if (unlikely(sd_dp->aborted)) {
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005570 sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", cmnd->request->tag);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005571 blk_abort_request(cmnd->request);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005572 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305573 sd_dp->aborted = false;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005574 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005575 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005576 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
5577 sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
5578 num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005579 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005580
5581respond_in_thread: /* call back to mid-layer using invocation thread */
Martin Wilckf66b8512018-02-14 11:05:57 +01005582 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5583 cmnd->result &= ~SDEG_RES_IMMED_MASK;
5584 if (cmnd->result == 0 && scsi_result != 0)
5585 cmnd->result = scsi_result;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005586 cmnd->scsi_done(cmnd);
5587 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005588}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005589
Douglas Gilbert23183912006-09-16 20:30:47 -04005590/* Note: The following macros create attribute files in the
5591 /sys/module/scsi_debug/parameters directory. Unfortunately this
5592 driver is unaware of a change and cannot trigger auxiliary actions
5593 as it can when the corresponding attribute in the
5594 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
5595 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005596module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5597module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005598module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005599module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04005600module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005601module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5602module_param_named(dif, sdebug_dif, int, S_IRUGO);
5603module_param_named(dix, sdebug_dix, int, S_IRUGO);
5604module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5605module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5606module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5607module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5608module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
John Garryc10fa552020-07-09 20:23:20 +08005609module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005610module_param_string(inq_product, sdebug_inq_product_id,
Douglas Gilbert5d807072020-04-21 11:14:23 -04005611 sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005612module_param_string(inq_rev, sdebug_inq_product_rev,
Douglas Gilbert5d807072020-04-21 11:14:23 -04005613 sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
5614module_param_string(inq_vendor, sdebug_inq_vendor_id,
5615 sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
5616module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005617module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5618module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5619module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005620module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04005621module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005622module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5623module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005624module_param_named(medium_error_count, sdebug_medium_error_count, int,
5625 S_IRUGO | S_IWUSR);
5626module_param_named(medium_error_start, sdebug_medium_error_start, int,
5627 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005628module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5629module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5630module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5631module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5632module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5633module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005634module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005635module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005636module_param_named(per_host_store, sdebug_per_host_store, bool,
5637 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005638module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5639module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005640module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005641module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5642module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5643module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005644module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005645module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005646module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05305647module_param_named(poll_queues, poll_queues, int, S_IRUGO);
Douglas Gilbertfc136382020-07-24 11:55:31 -04005648module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005649module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5650module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5651module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5652module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005653module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005654module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005655module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04005656 S_IRUGO | S_IWUSR);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05005657module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005658module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005659 S_IRUGO | S_IWUSR);
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09005660module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
Damien Le Moal380603a2020-04-22 19:42:18 +09005661module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09005662module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
Damien Le Moal98e0a682020-04-22 19:42:20 +09005663module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664
5665MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
5666MODULE_DESCRIPTION("SCSI debug adapter driver");
5667MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005668MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Douglas Gilbert5d807072020-04-21 11:14:23 -04005670MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005671MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005672MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09005673MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005674MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005675MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005676MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
5677MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005678MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07005679MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04005680MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005681MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04005682MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
John Garryc10fa552020-07-09 20:23:20 +08005683MODULE_PARM_DESC(host_max_queue,
5684 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005685MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005686MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
5687 SDEBUG_VERSION "\")");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005688MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
5689MODULE_PARM_DESC(lbprz,
5690 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005691MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
5692MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
5693MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
5694MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertad0c7772020-08-21 00:22:49 -04005695MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04005696MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005697MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05005698MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005699MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005700MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005701MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005702MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005704MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05005705MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01005706MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005707MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
5708MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
5709MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04005710MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005712MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
Martin Pittd9867882012-09-06 12:04:33 +02005713MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005714MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005715MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005716MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005717MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005718MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Douglas Gilbertfc136382020-07-24 11:55:31 -04005719MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005720MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
5721MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04005722MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
5723MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005724MODULE_PARM_DESC(uuid_ctl,
5725 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005726MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005727MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05005728MODULE_PARM_DESC(wp, "Write Protect (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005729MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09005730MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
Damien Le Moal380603a2020-04-22 19:42:18 +09005731MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09005732MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
Damien Le Moal98e0a682020-04-22 19:42:20 +09005733MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005735#define SDEBUG_INFO_LEN 256
5736static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737
John Pittman91d4c752018-02-09 21:12:43 -05005738static const char *scsi_debug_info(struct Scsi_Host *shp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005740 int k;
5741
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005742 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5743 my_name, SDEBUG_VERSION, sdebug_version_date);
5744 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005745 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005746 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5747 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5748 sdebug_dev_size_mb, sdebug_opts, submit_queues,
5749 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 return sdebug_info;
5751}
5752
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005753/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04005754static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5755 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756{
Al Viroc8ed5552013-03-31 01:46:06 -04005757 char arr[16];
5758 int opts;
5759 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760
Al Viroc8ed5552013-03-31 01:46:06 -04005761 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
5762 return -EACCES;
5763 memcpy(arr, buffer, minLen);
5764 arr[minLen] = '\0';
5765 if (1 != sscanf(arr, "%d", &opts))
5766 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005767 sdebug_opts = opts;
5768 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5769 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5770 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005771 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04005772 return length;
5773}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005775/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5776 * same for each scsi_debug host (if more than one). Some of the counters
5777 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04005778static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5779{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005780 int f, j, l;
5781 struct sdebug_queue *sqp;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005782 struct sdebug_host_info *sdhp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005783
Douglas Gilbertc4837392016-05-06 00:40:26 -04005784 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5785 SDEBUG_VERSION, sdebug_version_date);
5786 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5787 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5788 sdebug_opts, sdebug_every_nth);
5789 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5790 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5791 sdebug_sector_size, "bytes");
5792 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5793 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5794 num_aborts);
5795 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5796 num_dev_resets, num_target_resets, num_bus_resets,
5797 num_host_resets);
5798 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5799 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08005800 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5801 sdebug_statistics);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305802 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005803 atomic_read(&sdebug_cmnd_count),
5804 atomic_read(&sdebug_completions),
5805 "miss_cpus", atomic_read(&sdebug_miss_cpus),
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305806 atomic_read(&sdebug_a_tsf),
5807 atomic_read(&sdeb_mq_poll_count));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005808
Douglas Gilbertc4837392016-05-06 00:40:26 -04005809 seq_printf(m, "submit_queues=%d\n", submit_queues);
5810 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5811 seq_printf(m, " queue %d:\n", j);
5812 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5813 if (f != sdebug_max_queue) {
5814 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5815 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
5816 "first,last bits", f, l);
5817 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005818 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005819
5820 seq_printf(m, "this host_no=%d\n", host->host_no);
5821 if (!xa_empty(per_store_ap)) {
5822 bool niu;
5823 int idx;
5824 unsigned long l_idx;
5825 struct sdeb_store_info *sip;
5826
5827 seq_puts(m, "\nhost list:\n");
5828 j = 0;
5829 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
5830 idx = sdhp->si_idx;
5831 seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j,
5832 sdhp->shost->host_no, idx);
5833 ++j;
5834 }
5835 seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
5836 sdeb_most_recent_idx);
5837 j = 0;
5838 xa_for_each(per_store_ap, l_idx, sip) {
5839 niu = xa_get_mark(per_store_ap, l_idx,
5840 SDEB_XA_NOT_IN_USE);
5841 idx = (int)l_idx;
5842 seq_printf(m, " %d: idx=%d%s\n", j, idx,
5843 (niu ? " not_in_use" : ""));
5844 ++j;
5845 }
5846 }
Al Viroc8ed5552013-03-31 01:46:06 -04005847 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848}
5849
Akinobu Mita82069372013-10-14 22:48:04 +09005850static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851{
Douglas Gilbertc2206092016-04-25 12:16:31 -04005852 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853}
Douglas Gilbertc4837392016-05-06 00:40:26 -04005854/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5855 * of delay is jiffies.
5856 */
Akinobu Mita82069372013-10-14 22:48:04 +09005857static ssize_t delay_store(struct device_driver *ddp, const char *buf,
5858 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859{
Douglas Gilbertc2206092016-04-25 12:16:31 -04005860 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005862 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005863 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04005864 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005865 int j, k;
5866 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005867
Douglas Gilbertc4837392016-05-06 00:40:26 -04005868 block_unblock_all_queues(true);
5869 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5870 ++j, ++sqp) {
5871 k = find_first_bit(sqp->in_use_bm,
5872 sdebug_max_queue);
5873 if (k != sdebug_max_queue) {
5874 res = -EBUSY; /* queued commands */
5875 break;
5876 }
5877 }
5878 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04005879 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005880 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005881 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005882 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005884 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 }
5886 return -EINVAL;
5887}
Akinobu Mita82069372013-10-14 22:48:04 +09005888static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005890static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5891{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005892 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005893}
5894/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04005895/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005896static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04005897 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005898{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005899 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005900
5901 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04005902 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005903 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005904 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005905 int j, k;
5906 struct sdebug_queue *sqp;
5907
5908 block_unblock_all_queues(true);
5909 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5910 ++j, ++sqp) {
5911 k = find_first_bit(sqp->in_use_bm,
5912 sdebug_max_queue);
5913 if (k != sdebug_max_queue) {
5914 res = -EBUSY; /* queued commands */
5915 break;
5916 }
5917 }
5918 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005919 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04005920 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
5921 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005922 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005923 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005924 }
5925 return res;
5926 }
5927 return -EINVAL;
5928}
5929static DRIVER_ATTR_RW(ndelay);
5930
Akinobu Mita82069372013-10-14 22:48:04 +09005931static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005933 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934}
5935
Akinobu Mita82069372013-10-14 22:48:04 +09005936static ssize_t opts_store(struct device_driver *ddp, const char *buf,
5937 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005939 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940 char work[20];
5941
Douglas Gilbert9a051012017-12-23 12:48:10 -05005942 if (sscanf(buf, "%10s", work) == 1) {
5943 if (strncasecmp(work, "0x", 2) == 0) {
5944 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945 goto opts_done;
5946 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005947 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948 goto opts_done;
5949 }
5950 }
5951 return -EINVAL;
5952opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005953 sdebug_opts = opts;
5954 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5955 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005956 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 return count;
5958}
Akinobu Mita82069372013-10-14 22:48:04 +09005959static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960
Akinobu Mita82069372013-10-14 22:48:04 +09005961static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005963 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964}
Akinobu Mita82069372013-10-14 22:48:04 +09005965static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
5966 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005968 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09005970 /* Cannot change from or to TYPE_ZBC with sysfs */
5971 if (sdebug_ptype == TYPE_ZBC)
5972 return -EINVAL;
5973
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09005975 if (n == TYPE_ZBC)
5976 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005977 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978 return count;
5979 }
5980 return -EINVAL;
5981}
Akinobu Mita82069372013-10-14 22:48:04 +09005982static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983
Akinobu Mita82069372013-10-14 22:48:04 +09005984static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005986 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987}
Akinobu Mita82069372013-10-14 22:48:04 +09005988static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
5989 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005991 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992
5993 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005994 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 return count;
5996 }
5997 return -EINVAL;
5998}
Akinobu Mita82069372013-10-14 22:48:04 +09005999static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000
Akinobu Mita82069372013-10-14 22:48:04 +09006001static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04006002{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006003 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04006004}
Akinobu Mita82069372013-10-14 22:48:04 +09006005static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
6006 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04006007{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006008 int n, idx;
Douglas Gilbert23183912006-09-16 20:30:47 -04006009
6010 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006011 bool want_store = (n == 0);
6012 struct sdebug_host_info *sdhp;
6013
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006014 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04006015 sdebug_fake_rw = (sdebug_fake_rw > 0);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006016 if (sdebug_fake_rw == n)
6017 return count; /* not transitioning so do nothing */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006018
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006019 if (want_store) { /* 1 --> 0 transition, set up store */
6020 if (sdeb_first_idx < 0) {
6021 idx = sdebug_add_store();
6022 if (idx < 0)
6023 return idx;
6024 } else {
6025 idx = sdeb_first_idx;
6026 xa_clear_mark(per_store_ap, idx,
6027 SDEB_XA_NOT_IN_USE);
6028 }
6029 /* make all hosts use same store */
6030 list_for_each_entry(sdhp, &sdebug_host_list,
6031 host_list) {
6032 if (sdhp->si_idx != idx) {
6033 xa_set_mark(per_store_ap, sdhp->si_idx,
6034 SDEB_XA_NOT_IN_USE);
6035 sdhp->si_idx = idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006036 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006037 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006038 sdeb_most_recent_idx = idx;
6039 } else { /* 0 --> 1 transition is trigger for shrink */
6040 sdebug_erase_all_stores(true /* apart from first */);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006041 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006042 sdebug_fake_rw = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04006043 return count;
6044 }
6045 return -EINVAL;
6046}
Akinobu Mita82069372013-10-14 22:48:04 +09006047static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04006048
Akinobu Mita82069372013-10-14 22:48:04 +09006049static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006050{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006051 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006052}
Akinobu Mita82069372013-10-14 22:48:04 +09006053static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
6054 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006055{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006056 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006057
6058 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006059 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006060 return count;
6061 }
6062 return -EINVAL;
6063}
Akinobu Mita82069372013-10-14 22:48:04 +09006064static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006065
Akinobu Mita82069372013-10-14 22:48:04 +09006066static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006068 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069}
Akinobu Mita82069372013-10-14 22:48:04 +09006070static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
6071 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006073 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074
6075 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006076 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 sdebug_max_tgts_luns();
6078 return count;
6079 }
6080 return -EINVAL;
6081}
Akinobu Mita82069372013-10-14 22:48:04 +09006082static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083
Akinobu Mita82069372013-10-14 22:48:04 +09006084static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006086 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087}
Akinobu Mita82069372013-10-14 22:48:04 +09006088static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006090static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
6091{
6092 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
6093}
6094
6095static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
6096 size_t count)
6097{
6098 bool v;
6099
6100 if (kstrtobool(buf, &v))
6101 return -EINVAL;
6102
6103 sdebug_per_host_store = v;
6104 return count;
6105}
6106static DRIVER_ATTR_RW(per_host_store);
6107
Akinobu Mita82069372013-10-14 22:48:04 +09006108static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006110 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111}
Akinobu Mita82069372013-10-14 22:48:04 +09006112static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113
Akinobu Mita82069372013-10-14 22:48:04 +09006114static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006116 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006117}
Akinobu Mita82069372013-10-14 22:48:04 +09006118static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
6119 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006121 int nth;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006122 char work[20];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006124 if (sscanf(buf, "%10s", work) == 1) {
6125 if (strncasecmp(work, "0x", 2) == 0) {
6126 if (kstrtoint(work + 2, 16, &nth) == 0)
6127 goto every_nth_done;
6128 } else {
6129 if (kstrtoint(work, 10, &nth) == 0)
6130 goto every_nth_done;
Douglas Gilbertc4837392016-05-06 00:40:26 -04006131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 }
6133 return -EINVAL;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006134
6135every_nth_done:
6136 sdebug_every_nth = nth;
6137 if (nth && !sdebug_statistics) {
6138 pr_info("every_nth needs statistics=1, set it\n");
6139 sdebug_statistics = true;
6140 }
6141 tweak_cmnd_count();
6142 return count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143}
Akinobu Mita82069372013-10-14 22:48:04 +09006144static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006145
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006146static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6147{
6148 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6149}
6150static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6151 size_t count)
6152{
6153 int n;
6154 bool changed;
6155
6156 if (kstrtoint(buf, 0, &n))
6157 return -EINVAL;
6158 if (n >= 0) {
6159 if (n > (int)SAM_LUN_AM_FLAT) {
6160 pr_warn("only LUN address methods 0 and 1 are supported\n");
6161 return -EINVAL;
6162 }
6163 changed = ((int)sdebug_lun_am != n);
6164 sdebug_lun_am = n;
6165 if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */
6166 struct sdebug_host_info *sdhp;
6167 struct sdebug_dev_info *dp;
6168
6169 spin_lock(&sdebug_host_list_lock);
6170 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6171 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6172 set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6173 }
6174 }
6175 spin_unlock(&sdebug_host_list_lock);
6176 }
6177 return count;
6178 }
6179 return -EINVAL;
6180}
6181static DRIVER_ATTR_RW(lun_format);
6182
Akinobu Mita82069372013-10-14 22:48:04 +09006183static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006185 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186}
Akinobu Mita82069372013-10-14 22:48:04 +09006187static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
6188 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006190 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05006191 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192
6193 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006194 if (n > 256) {
6195 pr_warn("max_luns can be no more than 256\n");
6196 return -EINVAL;
6197 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006198 changed = (sdebug_max_luns != n);
6199 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04006201 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05006202 struct sdebug_host_info *sdhp;
6203 struct sdebug_dev_info *dp;
6204
6205 spin_lock(&sdebug_host_list_lock);
6206 list_for_each_entry(sdhp, &sdebug_host_list,
6207 host_list) {
6208 list_for_each_entry(dp, &sdhp->dev_info_list,
6209 dev_list) {
6210 set_bit(SDEBUG_UA_LUNS_CHANGED,
6211 dp->uas_bm);
6212 }
6213 }
6214 spin_unlock(&sdebug_host_list_lock);
6215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216 return count;
6217 }
6218 return -EINVAL;
6219}
Akinobu Mita82069372013-10-14 22:48:04 +09006220static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221
Akinobu Mita82069372013-10-14 22:48:04 +09006222static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006223{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006224 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006225}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006226/* N.B. max_queue can be changed while there are queued commands. In flight
6227 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09006228static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
6229 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006230{
Douglas Gilbertc4837392016-05-06 00:40:26 -04006231 int j, n, k, a;
6232 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006233
6234 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
John Garryc10fa552020-07-09 20:23:20 +08006235 (n <= SDEBUG_CANQUEUE) &&
6236 (sdebug_host_max_queue == 0)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04006237 block_unblock_all_queues(true);
6238 k = 0;
6239 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6240 ++j, ++sqp) {
6241 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6242 if (a > k)
6243 k = a;
6244 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006245 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04006246 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006247 atomic_set(&retired_max_queue, 0);
6248 else if (k >= n)
6249 atomic_set(&retired_max_queue, k + 1);
6250 else
6251 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04006252 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006253 return count;
6254 }
6255 return -EINVAL;
6256}
Akinobu Mita82069372013-10-14 22:48:04 +09006257static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006258
John Garryc10fa552020-07-09 20:23:20 +08006259static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6260{
6261 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6262}
6263
6264/*
6265 * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6266 * in range [0, sdebug_host_max_queue), we can't change it.
6267 */
6268static DRIVER_ATTR_RO(host_max_queue);
6269
Akinobu Mita82069372013-10-14 22:48:04 +09006270static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006271{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006272 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006273}
Akinobu Mita82069372013-10-14 22:48:04 +09006274static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006275
Akinobu Mita82069372013-10-14 22:48:04 +09006276static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006278 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279}
Akinobu Mita82069372013-10-14 22:48:04 +09006280static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281
Akinobu Mita82069372013-10-14 22:48:04 +09006282static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006283{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006284 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006285}
Akinobu Mita82069372013-10-14 22:48:04 +09006286static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
6287 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006288{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006289 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006290 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006291
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006292 /* Ignore capacity change for ZBC drives for now */
6293 if (sdeb_zbc_in_use)
6294 return -ENOTSUPP;
6295
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006296 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006297 changed = (sdebug_virtual_gb != n);
6298 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006299 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006300 if (changed) {
6301 struct sdebug_host_info *sdhp;
6302 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006303
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05006304 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006305 list_for_each_entry(sdhp, &sdebug_host_list,
6306 host_list) {
6307 list_for_each_entry(dp, &sdhp->dev_info_list,
6308 dev_list) {
6309 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
6310 dp->uas_bm);
6311 }
6312 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05006313 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006314 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006315 return count;
6316 }
6317 return -EINVAL;
6318}
Akinobu Mita82069372013-10-14 22:48:04 +09006319static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006320
Akinobu Mita82069372013-10-14 22:48:04 +09006321static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006322{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006323 /* absolute number of hosts currently active is what is shown */
6324 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325}
6326
Akinobu Mita82069372013-10-14 22:48:04 +09006327static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
6328 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006329{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006330 bool found;
6331 unsigned long idx;
6332 struct sdeb_store_info *sip;
6333 bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09006334 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09006336 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 if (delta_hosts > 0) {
6339 do {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006340 found = false;
6341 if (want_phs) {
6342 xa_for_each_marked(per_store_ap, idx, sip,
6343 SDEB_XA_NOT_IN_USE) {
6344 sdeb_most_recent_idx = (int)idx;
6345 found = true;
6346 break;
6347 }
6348 if (found) /* re-use case */
6349 sdebug_add_host_helper((int)idx);
6350 else
6351 sdebug_do_add_host(true);
6352 } else {
6353 sdebug_do_add_host(false);
6354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355 } while (--delta_hosts);
6356 } else if (delta_hosts < 0) {
6357 do {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006358 sdebug_do_remove_host(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 } while (++delta_hosts);
6360 }
6361 return count;
6362}
Akinobu Mita82069372013-10-14 22:48:04 +09006363static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364
Akinobu Mita82069372013-10-14 22:48:04 +09006365static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04006366{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006367 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04006368}
Akinobu Mita82069372013-10-14 22:48:04 +09006369static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
6370 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04006371{
6372 int n;
6373
6374 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006375 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04006376 return count;
6377 }
6378 return -EINVAL;
6379}
Akinobu Mita82069372013-10-14 22:48:04 +09006380static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04006381
Douglas Gilbertc4837392016-05-06 00:40:26 -04006382static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6383{
6384 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6385}
6386static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6387 size_t count)
6388{
6389 int n;
6390
6391 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6392 if (n > 0)
6393 sdebug_statistics = true;
6394 else {
6395 clear_queue_stats();
6396 sdebug_statistics = false;
6397 }
6398 return count;
6399 }
6400 return -EINVAL;
6401}
6402static DRIVER_ATTR_RW(statistics);
6403
Akinobu Mita82069372013-10-14 22:48:04 +09006404static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006405{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006406 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006407}
Akinobu Mita82069372013-10-14 22:48:04 +09006408static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006409
Douglas Gilbertc4837392016-05-06 00:40:26 -04006410static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6411{
6412 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6413}
6414static DRIVER_ATTR_RO(submit_queues);
6415
Akinobu Mita82069372013-10-14 22:48:04 +09006416static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006417{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006418 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006419}
Akinobu Mita82069372013-10-14 22:48:04 +09006420static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006421
Akinobu Mita82069372013-10-14 22:48:04 +09006422static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006423{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006424 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006425}
Akinobu Mita82069372013-10-14 22:48:04 +09006426static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006427
Akinobu Mita82069372013-10-14 22:48:04 +09006428static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006429{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006430 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006431}
Akinobu Mita82069372013-10-14 22:48:04 +09006432static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006433
Akinobu Mita82069372013-10-14 22:48:04 +09006434static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006435{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006436 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006437}
Akinobu Mita82069372013-10-14 22:48:04 +09006438static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006439
Akinobu Mita82069372013-10-14 22:48:04 +09006440static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04006441{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006442 ssize_t count = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006443
Martin K. Petersen5b94e232011-03-08 02:08:11 -05006444 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04006445 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
6446 sdebug_store_sectors);
6447
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006448 if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
6449 struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
6450
6451 if (sip)
6452 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
6453 (int)map_size, sip->map_storep);
6454 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04006455 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08006456 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04006457
6458 return count;
6459}
Akinobu Mita82069372013-10-14 22:48:04 +09006460static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04006461
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04006462static ssize_t random_show(struct device_driver *ddp, char *buf)
6463{
6464 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
6465}
6466
6467static ssize_t random_store(struct device_driver *ddp, const char *buf,
6468 size_t count)
6469{
6470 bool v;
6471
6472 if (kstrtobool(buf, &v))
6473 return -EINVAL;
6474
6475 sdebug_random = v;
6476 return count;
6477}
6478static DRIVER_ATTR_RW(random);
6479
Akinobu Mita82069372013-10-14 22:48:04 +09006480static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02006481{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006482 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02006483}
Akinobu Mita82069372013-10-14 22:48:04 +09006484static ssize_t removable_store(struct device_driver *ddp, const char *buf,
6485 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02006486{
6487 int n;
6488
6489 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006490 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02006491 return count;
6492 }
6493 return -EINVAL;
6494}
Akinobu Mita82069372013-10-14 22:48:04 +09006495static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02006496
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006497static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6498{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006499 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006500}
Douglas Gilbert185dd232016-04-25 12:16:29 -04006501/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006502static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6503 size_t count)
6504{
Douglas Gilbert185dd232016-04-25 12:16:29 -04006505 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006506
6507 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04006508 sdebug_host_lock = (n > 0);
6509 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006510 }
6511 return -EINVAL;
6512}
6513static DRIVER_ATTR_RW(host_lock);
6514
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006515static ssize_t strict_show(struct device_driver *ddp, char *buf)
6516{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006517 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006518}
6519static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6520 size_t count)
6521{
6522 int n;
6523
6524 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006525 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006526 return count;
6527 }
6528 return -EINVAL;
6529}
6530static DRIVER_ATTR_RW(strict);
6531
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04006532static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
6533{
6534 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
6535}
6536static DRIVER_ATTR_RO(uuid_ctl);
6537
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05006538static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
6539{
6540 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
6541}
6542static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
6543 size_t count)
6544{
6545 int ret, n;
6546
6547 ret = kstrtoint(buf, 0, &n);
6548 if (ret)
6549 return ret;
6550 sdebug_cdb_len = n;
6551 all_config_cdb_len();
6552 return count;
6553}
6554static DRIVER_ATTR_RW(cdb_len);
6555
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006556static const char * const zbc_model_strs_a[] = {
6557 [BLK_ZONED_NONE] = "none",
6558 [BLK_ZONED_HA] = "host-aware",
6559 [BLK_ZONED_HM] = "host-managed",
6560};
6561
6562static const char * const zbc_model_strs_b[] = {
6563 [BLK_ZONED_NONE] = "no",
6564 [BLK_ZONED_HA] = "aware",
6565 [BLK_ZONED_HM] = "managed",
6566};
6567
6568static const char * const zbc_model_strs_c[] = {
6569 [BLK_ZONED_NONE] = "0",
6570 [BLK_ZONED_HA] = "1",
6571 [BLK_ZONED_HM] = "2",
6572};
6573
6574static int sdeb_zbc_model_str(const char *cp)
6575{
6576 int res = sysfs_match_string(zbc_model_strs_a, cp);
6577
6578 if (res < 0) {
6579 res = sysfs_match_string(zbc_model_strs_b, cp);
6580 if (res < 0) {
6581 res = sysfs_match_string(zbc_model_strs_c, cp);
Dan Carpenter47742bd2020-05-09 13:04:08 +03006582 if (res < 0)
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006583 return -EINVAL;
6584 }
6585 }
6586 return res;
6587}
6588
6589static ssize_t zbc_show(struct device_driver *ddp, char *buf)
6590{
6591 return scnprintf(buf, PAGE_SIZE, "%s\n",
6592 zbc_model_strs_a[sdeb_zbc_model]);
6593}
6594static DRIVER_ATTR_RO(zbc);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006595
Douglas Gilbertfc136382020-07-24 11:55:31 -04006596static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6597{
6598 return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6599}
6600static DRIVER_ATTR_RO(tur_ms_to_ready);
6601
Akinobu Mita82069372013-10-14 22:48:04 +09006602/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04006603 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
6604 files (over those found in the /sys/module/scsi_debug/parameters
6605 directory) is that auxiliary actions can be triggered when an attribute
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006606 is changed. For example see: add_host_store() above.
Douglas Gilbert23183912006-09-16 20:30:47 -04006607 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006608
Akinobu Mita82069372013-10-14 22:48:04 +09006609static struct attribute *sdebug_drv_attrs[] = {
6610 &driver_attr_delay.attr,
6611 &driver_attr_opts.attr,
6612 &driver_attr_ptype.attr,
6613 &driver_attr_dsense.attr,
6614 &driver_attr_fake_rw.attr,
John Garryc10fa552020-07-09 20:23:20 +08006615 &driver_attr_host_max_queue.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006616 &driver_attr_no_lun_0.attr,
6617 &driver_attr_num_tgts.attr,
6618 &driver_attr_dev_size_mb.attr,
6619 &driver_attr_num_parts.attr,
6620 &driver_attr_every_nth.attr,
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006621 &driver_attr_lun_format.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006622 &driver_attr_max_luns.attr,
6623 &driver_attr_max_queue.attr,
6624 &driver_attr_no_uld.attr,
6625 &driver_attr_scsi_level.attr,
6626 &driver_attr_virtual_gb.attr,
6627 &driver_attr_add_host.attr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006628 &driver_attr_per_host_store.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006629 &driver_attr_vpd_use_hostno.attr,
6630 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04006631 &driver_attr_statistics.attr,
6632 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006633 &driver_attr_dix.attr,
6634 &driver_attr_dif.attr,
6635 &driver_attr_guard.attr,
6636 &driver_attr_ato.attr,
6637 &driver_attr_map.attr,
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04006638 &driver_attr_random.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006639 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006640 &driver_attr_host_lock.attr,
6641 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006642 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04006643 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05006644 &driver_attr_cdb_len.attr,
Douglas Gilbertfc136382020-07-24 11:55:31 -04006645 &driver_attr_tur_ms_to_ready.attr,
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006646 &driver_attr_zbc.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006647 NULL,
6648};
6649ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006650
Akinobu Mita11ddcec2014-02-26 22:56:59 +09006651static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09006652
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653static int __init scsi_debug_init(void)
6654{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006655 bool want_store = (sdebug_fake_rw == 0);
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09006656 unsigned long sz;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006657 int k, ret, hosts_to_add;
6658 int idx = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006660 ramdisk_lck_a[0] = &atomic_rw;
6661 ramdisk_lck_a[1] = &atomic_rw2;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006662 atomic_set(&retired_max_queue, 0);
6663
Douglas Gilbert773642d2016-04-25 12:16:28 -04006664 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006665 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04006666 sdebug_ndelay = 0;
6667 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04006668 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006669
Douglas Gilbert773642d2016-04-25 12:16:28 -04006670 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006671 case 512:
6672 case 1024:
6673 case 2048:
6674 case 4096:
6675 break;
6676 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04006677 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006678 return -EINVAL;
6679 }
6680
Douglas Gilbert773642d2016-04-25 12:16:28 -04006681 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02006682 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04006683 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02006684 case T10_PI_TYPE1_PROTECTION:
6685 case T10_PI_TYPE2_PROTECTION:
6686 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04006687 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006688 break;
6689
6690 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03006691 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006692 return -EINVAL;
6693 }
6694
Maurizio Lombardiaa5334c2019-11-15 17:37:27 +01006695 if (sdebug_num_tgts < 0) {
6696 pr_err("num_tgts must be >= 0\n");
6697 return -EINVAL;
6698 }
6699
Douglas Gilbert773642d2016-04-25 12:16:28 -04006700 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006701 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006702 return -EINVAL;
6703 }
6704
Douglas Gilbert773642d2016-04-25 12:16:28 -04006705 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006706 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006707 return -EINVAL;
6708 }
6709
Douglas Gilbert773642d2016-04-25 12:16:28 -04006710 if (sdebug_physblk_exp > 15) {
6711 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006712 return -EINVAL;
6713 }
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006714
6715 sdebug_lun_am = sdebug_lun_am_i;
6716 if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6717 pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6718 sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6719 }
6720
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006721 if (sdebug_max_luns > 256) {
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006722 if (sdebug_max_luns > 16384) {
6723 pr_warn("max_luns can be no more than 16384, use default\n");
6724 sdebug_max_luns = DEF_MAX_LUNS;
6725 }
6726 sdebug_lun_am = SAM_LUN_AM_FLAT;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006727 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006728
Douglas Gilbert773642d2016-04-25 12:16:28 -04006729 if (sdebug_lowest_aligned > 0x3fff) {
6730 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006731 return -EINVAL;
6732 }
6733
Douglas Gilbertc4837392016-05-06 00:40:26 -04006734 if (submit_queues < 1) {
6735 pr_err("submit_queues must be 1 or more\n");
6736 return -EINVAL;
6737 }
John Garryc87bf242020-07-09 20:23:19 +08006738
6739 if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6740 pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6741 return -EINVAL;
6742 }
6743
John Garryc10fa552020-07-09 20:23:20 +08006744 if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6745 (sdebug_host_max_queue < 0)) {
6746 pr_err("host_max_queue must be in range [0 %d]\n",
6747 SDEBUG_CANQUEUE);
6748 return -EINVAL;
6749 }
6750
6751 if (sdebug_host_max_queue &&
6752 (sdebug_max_queue != sdebug_host_max_queue)) {
6753 sdebug_max_queue = sdebug_host_max_queue;
6754 pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6755 sdebug_max_queue);
6756 }
6757
Douglas Gilbertc4837392016-05-06 00:40:26 -04006758 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6759 GFP_KERNEL);
6760 if (sdebug_q_arr == NULL)
6761 return -ENOMEM;
6762 for (k = 0; k < submit_queues; ++k)
6763 spin_lock_init(&sdebug_q_arr[k].qc_lock);
6764
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006765 /*
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006766 * check for host managed zoned block device specified with
6767 * ptype=0x14 or zbc=XXX.
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006768 */
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006769 if (sdebug_ptype == TYPE_ZBC) {
6770 sdeb_zbc_model = BLK_ZONED_HM;
6771 } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
6772 k = sdeb_zbc_model_str(sdeb_zbc_model_s);
6773 if (k < 0) {
6774 ret = k;
Dinghao Liu3b01d7e2020-12-26 14:15:03 +08006775 goto free_q_arr;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006776 }
6777 sdeb_zbc_model = k;
6778 switch (sdeb_zbc_model) {
6779 case BLK_ZONED_NONE:
Damien Le Moal64e14ec2020-04-22 19:42:21 +09006780 case BLK_ZONED_HA:
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006781 sdebug_ptype = TYPE_DISK;
6782 break;
6783 case BLK_ZONED_HM:
6784 sdebug_ptype = TYPE_ZBC;
6785 break;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006786 default:
6787 pr_err("Invalid ZBC model\n");
Dinghao Liu3b01d7e2020-12-26 14:15:03 +08006788 ret = -EINVAL;
6789 goto free_q_arr;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006790 }
6791 }
6792 if (sdeb_zbc_model != BLK_ZONED_NONE) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006793 sdeb_zbc_in_use = true;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006794 if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
6795 sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
6796 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006797
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006798 if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
6799 sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006800 if (sdebug_dev_size_mb < 1)
6801 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
6802 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6803 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006804 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006805
6806 /* play around with geometry, don't waste too much on track 0 */
6807 sdebug_heads = 8;
6808 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006809 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006811 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02006812 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
6814 (sdebug_sectors_per * sdebug_heads);
6815 if (sdebug_cylinders_per >= 1024) {
6816 /* other LLDs do this; implies >= 1GB ram disk ... */
6817 sdebug_heads = 255;
6818 sdebug_sectors_per = 63;
6819 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
6820 (sdebug_sectors_per * sdebug_heads);
6821 }
Martin K. Petersen5b94e232011-03-08 02:08:11 -05006822 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006823 sdebug_unmap_max_blocks =
6824 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04006825
Douglas Gilbert773642d2016-04-25 12:16:28 -04006826 sdebug_unmap_max_desc =
6827 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04006828
Douglas Gilbert773642d2016-04-25 12:16:28 -04006829 sdebug_unmap_granularity =
6830 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04006831
Douglas Gilbert773642d2016-04-25 12:16:28 -04006832 if (sdebug_unmap_alignment &&
6833 sdebug_unmap_granularity <=
6834 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006835 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04006836 ret = -EINVAL;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006837 goto free_q_arr;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006838 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006839 }
6840 xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
6841 if (want_store) {
6842 idx = sdebug_add_store();
6843 if (idx < 0) {
6844 ret = idx;
6845 goto free_q_arr;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006846 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04006847 }
6848
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006849 pseudo_primary = root_device_register("pseudo_0");
6850 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006851 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006852 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006853 goto free_vm;
6854 }
6855 ret = bus_register(&pseudo_lld_bus);
6856 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006857 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006858 goto dev_unreg;
6859 }
6860 ret = driver_register(&sdebug_driverfs_driver);
6861 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006862 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006863 goto bus_unreg;
6864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006865
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006866 hosts_to_add = sdebug_add_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006867 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006869 for (k = 0; k < hosts_to_add; k++) {
6870 if (want_store && k == 0) {
6871 ret = sdebug_add_host_helper(idx);
6872 if (ret < 0) {
6873 pr_err("add_host_helper k=%d, error=%d\n",
6874 k, -ret);
6875 break;
6876 }
6877 } else {
6878 ret = sdebug_do_add_host(want_store &&
6879 sdebug_per_host_store);
6880 if (ret < 0) {
6881 pr_err("add_host k=%d error=%d\n", k, -ret);
6882 break;
6883 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05006884 }
6885 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006886 if (sdebug_verbose)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006887 pr_info("built %d host(s)\n", sdebug_num_hosts);
Tomas Winklerc12879702015-07-28 16:54:20 +03006888
Linus Torvalds1da177e2005-04-16 15:20:36 -07006889 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006890
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006891bus_unreg:
6892 bus_unregister(&pseudo_lld_bus);
6893dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006894 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006895free_vm:
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006896 sdebug_erase_store(idx, NULL);
Douglas Gilbertc4837392016-05-06 00:40:26 -04006897free_q_arr:
6898 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006899 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006900}
6901
6902static void __exit scsi_debug_exit(void)
6903{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006904 int k = sdebug_num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006905
6906 stop_all_queued();
6907 for (; k; k--)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006908 sdebug_do_remove_host(true);
Luis Henriques52ab9762018-06-18 17:08:03 +01006909 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006910 driver_unregister(&sdebug_driverfs_driver);
6911 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006912 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006913
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006914 sdebug_erase_all_stores(false);
6915 xa_destroy(per_store_ap);
Maurizio Lombardif852c592021-02-08 12:17:34 +01006916 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006917}
6918
6919device_initcall(scsi_debug_init);
6920module_exit(scsi_debug_exit);
6921
John Pittman91d4c752018-02-09 21:12:43 -05006922static void sdebug_release_adapter(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006923{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006924 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006925
6926 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05006927 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006928}
6929
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006930/* idx must be valid, if sip is NULL then it will be obtained using idx */
6931static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006932{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006933 if (idx < 0)
6934 return;
6935 if (!sip) {
6936 if (xa_empty(per_store_ap))
6937 return;
6938 sip = xa_load(per_store_ap, idx);
6939 if (!sip)
6940 return;
6941 }
6942 vfree(sip->map_storep);
6943 vfree(sip->dif_storep);
6944 vfree(sip->storep);
6945 xa_erase(per_store_ap, idx);
6946 kfree(sip);
6947}
6948
6949/* Assume apart_from_first==false only in shutdown case. */
6950static void sdebug_erase_all_stores(bool apart_from_first)
6951{
6952 unsigned long idx;
6953 struct sdeb_store_info *sip = NULL;
6954
6955 xa_for_each(per_store_ap, idx, sip) {
6956 if (apart_from_first)
6957 apart_from_first = false;
6958 else
6959 sdebug_erase_store(idx, sip);
6960 }
6961 if (apart_from_first)
6962 sdeb_most_recent_idx = sdeb_first_idx;
6963}
6964
6965/*
6966 * Returns store xarray new element index (idx) if >=0 else negated errno.
6967 * Limit the number of stores to 65536.
6968 */
6969static int sdebug_add_store(void)
6970{
6971 int res;
6972 u32 n_idx;
6973 unsigned long iflags;
6974 unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6975 struct sdeb_store_info *sip = NULL;
6976 struct xa_limit xal = { .max = 1 << 16, .min = 0 };
6977
6978 sip = kzalloc(sizeof(*sip), GFP_KERNEL);
6979 if (!sip)
6980 return -ENOMEM;
6981
6982 xa_lock_irqsave(per_store_ap, iflags);
6983 res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
6984 if (unlikely(res < 0)) {
6985 xa_unlock_irqrestore(per_store_ap, iflags);
6986 kfree(sip);
6987 pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
6988 return res;
6989 }
6990 sdeb_most_recent_idx = n_idx;
6991 if (sdeb_first_idx < 0)
6992 sdeb_first_idx = n_idx;
6993 xa_unlock_irqrestore(per_store_ap, iflags);
6994
6995 res = -ENOMEM;
6996 sip->storep = vzalloc(sz);
6997 if (!sip->storep) {
6998 pr_err("user data oom\n");
6999 goto err;
7000 }
7001 if (sdebug_num_parts > 0)
7002 sdebug_build_parts(sip->storep, sz);
7003
7004 /* DIF/DIX: what T10 calls Protection Information (PI) */
7005 if (sdebug_dix) {
7006 int dif_size;
7007
7008 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
7009 sip->dif_storep = vmalloc(dif_size);
7010
7011 pr_info("dif_storep %u bytes @ %pK\n", dif_size,
7012 sip->dif_storep);
7013
7014 if (!sip->dif_storep) {
7015 pr_err("DIX oom\n");
7016 goto err;
7017 }
7018 memset(sip->dif_storep, 0xff, dif_size);
7019 }
7020 /* Logical Block Provisioning */
7021 if (scsi_debug_lbp()) {
7022 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
7023 sip->map_storep = vmalloc(array_size(sizeof(long),
7024 BITS_TO_LONGS(map_size)));
7025
7026 pr_info("%lu provisioning blocks\n", map_size);
7027
7028 if (!sip->map_storep) {
7029 pr_err("LBP map oom\n");
7030 goto err;
7031 }
7032
7033 bitmap_zero(sip->map_storep, map_size);
7034
7035 /* Map first 1KB for partition table */
7036 if (sdebug_num_parts)
7037 map_region(sip, 0, 2);
7038 }
7039
7040 rwlock_init(&sip->macc_lck);
7041 return (int)n_idx;
7042err:
7043 sdebug_erase_store((int)n_idx, sip);
7044 pr_warn("%s: failed, errno=%d\n", __func__, -res);
7045 return res;
7046}
7047
7048static int sdebug_add_host_helper(int per_host_idx)
7049{
7050 int k, devs_per_host, idx;
7051 int error = -ENOMEM;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007052 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007053 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007054
Douglas Gilbert9a051012017-12-23 12:48:10 -05007055 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007056 if (!sdbg_host)
Douglas Gilbert9a051012017-12-23 12:48:10 -05007057 return -ENOMEM;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007058 idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
7059 if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
7060 xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
7061 sdbg_host->si_idx = idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007062
Douglas Gilbert9a051012017-12-23 12:48:10 -05007063 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007064
Douglas Gilbert773642d2016-04-25 12:16:28 -04007065 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007066 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09007067 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007068 if (!sdbg_devinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007069 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007071
Douglas Gilbert9a051012017-12-23 12:48:10 -05007072 spin_lock(&sdebug_host_list_lock);
7073 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
7074 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007075
Douglas Gilbert9a051012017-12-23 12:48:10 -05007076 sdbg_host->dev.bus = &pseudo_lld_bus;
7077 sdbg_host->dev.parent = pseudo_primary;
7078 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007079 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007080
Douglas Gilbert9a051012017-12-23 12:48:10 -05007081 error = device_register(&sdbg_host->dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007082 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007083 goto clean;
7084
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007085 ++sdebug_num_hosts;
7086 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007087
7088clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007089 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
7090 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007091 list_del(&sdbg_devinfo->dev_list);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09007092 kfree(sdbg_devinfo->zstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007093 kfree(sdbg_devinfo);
7094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095 kfree(sdbg_host);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007096 pr_warn("%s: failed, errno=%d\n", __func__, -error);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007097 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098}
7099
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007100static int sdebug_do_add_host(bool mk_new_store)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007102 int ph_idx = sdeb_most_recent_idx;
7103
7104 if (mk_new_store) {
7105 ph_idx = sdebug_add_store();
7106 if (ph_idx < 0)
7107 return ph_idx;
7108 }
7109 return sdebug_add_host_helper(ph_idx);
7110}
7111
7112static void sdebug_do_remove_host(bool the_end)
7113{
7114 int idx = -1;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007115 struct sdebug_host_info *sdbg_host = NULL;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007116 struct sdebug_host_info *sdbg_host2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117
Douglas Gilbert9a051012017-12-23 12:48:10 -05007118 spin_lock(&sdebug_host_list_lock);
7119 if (!list_empty(&sdebug_host_list)) {
7120 sdbg_host = list_entry(sdebug_host_list.prev,
7121 struct sdebug_host_info, host_list);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007122 idx = sdbg_host->si_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007123 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007124 if (!the_end && idx >= 0) {
7125 bool unique = true;
7126
7127 list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
7128 if (sdbg_host2 == sdbg_host)
7129 continue;
7130 if (idx == sdbg_host2->si_idx) {
7131 unique = false;
7132 break;
7133 }
7134 }
7135 if (unique) {
7136 xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
7137 if (idx == sdeb_most_recent_idx)
7138 --sdeb_most_recent_idx;
7139 }
7140 }
7141 if (sdbg_host)
7142 list_del(&sdbg_host->host_list);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007143 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144
7145 if (!sdbg_host)
7146 return;
7147
Douglas Gilbert773642d2016-04-25 12:16:28 -04007148 device_unregister(&sdbg_host->dev);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007149 --sdebug_num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150}
7151
Douglas Gilbertfd321192016-04-25 12:16:33 -04007152static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007153{
7154 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007155 struct sdebug_dev_info *devip;
7156
Douglas Gilbertc4837392016-05-06 00:40:26 -04007157 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007158 devip = (struct sdebug_dev_info *)sdev->hostdata;
7159 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007160 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007161 return -ENODEV;
7162 }
7163 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007164
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007165 if (qdepth > SDEBUG_CANQUEUE) {
7166 qdepth = SDEBUG_CANQUEUE;
7167 pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7168 qdepth, SDEBUG_CANQUEUE);
7169 }
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007170 if (qdepth < 1)
7171 qdepth = 1;
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007172 if (qdepth != sdev->queue_depth)
7173 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007174
Douglas Gilbert773642d2016-04-25 12:16:28 -04007175 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007176 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007177 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007178 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007179 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007180 return sdev->queue_depth;
7181}
7182
Douglas Gilbertc4837392016-05-06 00:40:26 -04007183static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05007184{
Douglas Gilbertc4837392016-05-06 00:40:26 -04007185 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04007186 if (sdebug_every_nth < -1)
7187 sdebug_every_nth = -1;
7188 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04007189 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04007190 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05007191 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04007192 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05007193 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007194 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05007195}
7196
Douglas Gilbertfc136382020-07-24 11:55:31 -04007197/* Response to TUR or media access command when device stopped */
7198static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7199{
7200 int stopped_state;
7201 u64 diff_ns = 0;
7202 ktime_t now_ts = ktime_get_boottime();
7203 struct scsi_device *sdp = scp->device;
7204
7205 stopped_state = atomic_read(&devip->stopped);
7206 if (stopped_state == 2) {
7207 if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7208 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7209 if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7210 /* tur_ms_to_ready timer extinguished */
7211 atomic_set(&devip->stopped, 0);
7212 return 0;
7213 }
7214 }
7215 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7216 if (sdebug_verbose)
7217 sdev_printk(KERN_INFO, sdp,
7218 "%s: Not ready: in process of becoming ready\n", my_name);
7219 if (scp->cmnd[0] == TEST_UNIT_READY) {
7220 u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7221
7222 if (diff_ns <= tur_nanosecs_to_ready)
7223 diff_ns = tur_nanosecs_to_ready - diff_ns;
7224 else
7225 diff_ns = tur_nanosecs_to_ready;
7226 /* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7227 do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */
7228 scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7229 diff_ns);
7230 return check_condition_result;
7231 }
7232 }
7233 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7234 if (sdebug_verbose)
7235 sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7236 my_name);
7237 return check_condition_result;
7238}
7239
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307240static int sdebug_map_queues(struct Scsi_Host *shost)
7241{
7242 int i, qoff;
7243
7244 if (shost->nr_hw_queues == 1)
7245 return 0;
7246
7247 for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7248 struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7249
7250 map->nr_queues = 0;
7251
7252 if (i == HCTX_TYPE_DEFAULT)
7253 map->nr_queues = submit_queues - poll_queues;
7254 else if (i == HCTX_TYPE_POLL)
7255 map->nr_queues = poll_queues;
7256
7257 if (!map->nr_queues) {
7258 BUG_ON(i == HCTX_TYPE_DEFAULT);
7259 continue;
7260 }
7261
7262 map->queue_offset = qoff;
7263 blk_mq_map_queues(map);
7264
7265 qoff += map->nr_queues;
7266 }
7267
7268 return 0;
7269
7270}
7271
7272static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7273{
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307274 bool first;
7275 bool retiring = false;
7276 int num_entries = 0;
7277 unsigned int qc_idx = 0;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307278 unsigned long iflags;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307279 ktime_t kt_from_boot = ktime_get_boottime();
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307280 struct sdebug_queue *sqp;
7281 struct sdebug_queued_cmd *sqcp;
7282 struct scsi_cmnd *scp;
7283 struct sdebug_dev_info *devip;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307284 struct sdebug_defer *sd_dp;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307285
7286 sqp = sdebug_q_arr + queue_num;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307287 spin_lock_irqsave(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307288
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307289 for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) {
7290 if (first) {
7291 qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
7292 first = false;
7293 } else {
7294 qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
7295 }
7296 if (unlikely(qc_idx >= sdebug_max_queue))
7297 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307298
7299 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307300 sd_dp = sqcp->sd_dp;
7301 if (unlikely(!sd_dp))
7302 continue;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307303 scp = sqcp->a_cmnd;
7304 if (unlikely(scp == NULL)) {
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307305 pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307306 queue_num, qc_idx, __func__);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307307 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307308 }
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307309 if (sd_dp->defer_t == SDEB_DEFER_POLL) {
7310 if (kt_from_boot < sd_dp->cmpl_ts)
7311 continue;
7312
7313 } else /* ignoring non REQ_HIPRI requests */
7314 continue;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307315 devip = (struct sdebug_dev_info *)scp->device->hostdata;
7316 if (likely(devip))
7317 atomic_dec(&devip->num_in_q);
7318 else
7319 pr_err("devip=NULL from %s\n", __func__);
7320 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307321 retiring = true;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307322
7323 sqcp->a_cmnd = NULL;
7324 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307325 pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307326 sqp, queue_num, qc_idx, __func__);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307327 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307328 }
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307329 if (unlikely(retiring)) { /* user has reduced max_queue */
7330 int k, retval;
7331
7332 retval = atomic_read(&retired_max_queue);
7333 if (qc_idx >= retval) {
7334 pr_err("index %d too large\n", retval);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307335 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307336 }
7337 k = find_last_bit(sqp->in_use_bm, retval);
7338 if ((k < sdebug_max_queue) || (k == retval))
7339 atomic_set(&retired_max_queue, 0);
7340 else
7341 atomic_set(&retired_max_queue, k + 1);
7342 }
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307343 sd_dp->defer_t = SDEB_DEFER_NONE;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307344 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
7345 scp->scsi_done(scp); /* callback to mid level */
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307346 spin_lock_irqsave(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307347 num_entries++;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307348 }
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307349 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307350 if (num_entries > 0)
7351 atomic_add(num_entries, &sdeb_mq_poll_count);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307352 return num_entries;
7353}
7354
Douglas Gilbertfd321192016-04-25 12:16:33 -04007355static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7356 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007357{
7358 u8 sdeb_i;
7359 struct scsi_device *sdp = scp->device;
7360 const struct opcode_info_t *oip;
7361 const struct opcode_info_t *r_oip;
7362 struct sdebug_dev_info *devip;
7363 u8 *cmd = scp->cmnd;
7364 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
Martin Wilckf66b8512018-02-14 11:05:57 +01007365 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007366 int k, na;
7367 int errsts = 0;
Douglas Gilbertad0c7772020-08-21 00:22:49 -04007368 u64 lun_index = sdp->lun & 0x3FFF;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007369 u32 flags;
7370 u16 sa;
7371 u8 opcode = cmd[0];
7372 bool has_wlun_rl;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007373 bool inject_now;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007374
7375 scsi_set_resid(scp, 0);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007376 if (sdebug_statistics) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007377 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007378 inject_now = inject_on_this_cmd();
7379 } else {
7380 inject_now = false;
7381 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007382 if (unlikely(sdebug_verbose &&
7383 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007384 char b[120];
7385 int n, len, sb;
7386
7387 len = scp->cmd_len;
7388 sb = (int)sizeof(b);
7389 if (len > 32)
7390 strcpy(b, "too long, over 32 bytes");
7391 else {
7392 for (k = 0, n = 0; k < len && n < sb; ++k)
7393 n += scnprintf(b + n, sb - n, "%02x ",
7394 (u32)cmd[k]);
7395 }
Bart Van Assche458df782018-01-26 08:52:19 -08007396 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
7397 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007398 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007399 if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08007400 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03007401 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04007402 if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007403 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007404
7405 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
7406 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
7407 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007408 if (unlikely(!devip)) {
7409 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007410 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007411 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007412 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007413 if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
7414 atomic_set(&sdeb_inject_pending, 1);
7415
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007416 na = oip->num_attached;
7417 r_pfp = oip->pfp;
7418 if (na) { /* multiple commands with this opcode */
7419 r_oip = oip;
7420 if (FF_SA & r_oip->flags) {
7421 if (F_SA_LOW & oip->flags)
7422 sa = 0x1f & cmd[1];
7423 else
7424 sa = get_unaligned_be16(cmd + 8);
7425 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7426 if (opcode == oip->opcode && sa == oip->sa)
7427 break;
7428 }
7429 } else { /* since no service action only check opcode */
7430 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7431 if (opcode == oip->opcode)
7432 break;
7433 }
7434 }
7435 if (k > na) {
7436 if (F_SA_LOW & r_oip->flags)
7437 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7438 else if (F_SA_HIGH & r_oip->flags)
7439 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7440 else
7441 mk_sense_invalid_opcode(scp);
7442 goto check_cond;
7443 }
7444 } /* else (when na==0) we assume the oip is a match */
7445 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007446 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007447 mk_sense_invalid_opcode(scp);
7448 goto check_cond;
7449 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007450 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04007451 if (sdebug_verbose)
7452 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7453 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007454 mk_sense_invalid_opcode(scp);
7455 goto check_cond;
7456 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007457 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007458 u8 rem;
7459 int j;
7460
7461 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7462 rem = ~oip->len_mask[k] & cmd[k];
7463 if (rem) {
7464 for (j = 7; j >= 0; --j, rem <<= 1) {
7465 if (0x80 & rem)
7466 break;
7467 }
7468 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7469 goto check_cond;
7470 }
7471 }
7472 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007473 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04007474 find_first_bit(devip->uas_bm,
7475 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007476 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007477 if (errsts)
7478 goto check_cond;
7479 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04007480 if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7481 atomic_read(&devip->stopped))) {
7482 errsts = resp_not_ready(scp, devip);
7483 if (errsts)
7484 goto fini;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007485 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04007486 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007487 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007488 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007489 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007490 return 0; /* ignore command: make trouble */
7491 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007492 if (likely(oip->pfp))
Martin Wilckf66b8512018-02-14 11:05:57 +01007493 pfp = oip->pfp; /* calls a resp_* function */
7494 else
7495 pfp = r_pfp; /* if leaf function ptr NULL, try the root's */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007496
7497fini:
Douglas Gilbert67da4132020-04-21 11:14:20 -04007498 if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */
Martin Wilckf66b8512018-02-14 11:05:57 +01007499 return schedule_resp(scp, devip, errsts, pfp, 0, 0);
Douglas Gilbert75aa3202018-07-12 13:35:42 -04007500 else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
7501 sdebug_ndelay > 10000)) {
Douglas Gilbert80c49562018-02-09 21:36:39 -05007502 /*
Douglas Gilbert75aa3202018-07-12 13:35:42 -04007503 * Skip long delays if ndelay <= 10 microseconds. Otherwise
7504 * for Start Stop Unit (SSU) want at least 1 second delay and
7505 * if sdebug_jdelay>1 want a long delay of that many seconds.
7506 * For Synchronize Cache want 1/20 of SSU's delay.
Douglas Gilbert80c49562018-02-09 21:36:39 -05007507 */
7508 int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04007509 int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
Douglas Gilbert80c49562018-02-09 21:36:39 -05007510
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04007511 jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
Martin Wilckf66b8512018-02-14 11:05:57 +01007512 return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05007513 } else
Martin Wilckf66b8512018-02-14 11:05:57 +01007514 return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
Douglas Gilbert10bde982018-01-10 16:57:31 -05007515 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007516check_cond:
Martin Wilckf66b8512018-02-14 11:05:57 +01007517 return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007518err_out:
Martin Wilckf66b8512018-02-14 11:05:57 +01007519 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007520}
7521
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007522static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04007523 .show_info = scsi_debug_show_info,
7524 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007525 .proc_name = sdebug_proc_name,
7526 .name = "SCSI DEBUG",
7527 .info = scsi_debug_info,
7528 .slave_alloc = scsi_debug_slave_alloc,
7529 .slave_configure = scsi_debug_slave_configure,
7530 .slave_destroy = scsi_debug_slave_destroy,
7531 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04007532 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007533 .change_queue_depth = sdebug_change_qdepth,
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307534 .map_queues = sdebug_map_queues,
7535 .mq_poll = sdebug_blk_mq_poll,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007536 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007537 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007538 .eh_target_reset_handler = scsi_debug_target_reset,
7539 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007540 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04007541 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007542 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07007543 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007544 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09007545 .max_sectors = -1U,
Christoph Hellwig50c2e912018-12-13 16:17:03 +01007546 .max_segment_size = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007547 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007548 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007549};
7550
John Pittman91d4c752018-02-09 21:12:43 -05007551static int sdebug_driver_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007552{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05007553 int error = 0;
7554 struct sdebug_host_info *sdbg_host;
7555 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007556 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557
7558 sdbg_host = to_sdebug_host(dev);
7559
John Garryf7c4cdc2020-08-19 23:20:33 +08007560 sdebug_driver_template.can_queue = sdebug_max_queue;
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007561 sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
Christoph Hellwig2a3d4eb2018-12-13 16:17:02 +01007562 if (!sdebug_clustering)
Christoph Hellwig4af14d12018-12-13 16:17:09 +01007563 sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
7564
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007565 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
7566 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007567 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007568 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007569 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007570 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007571 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07007572 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04007573 my_name, submit_queues, nr_cpu_ids);
7574 submit_queues = nr_cpu_ids;
7575 }
John Garryc10fa552020-07-09 20:23:20 +08007576 /*
7577 * Decide whether to tell scsi subsystem that we want mq. The
John Garryf7c4cdc2020-08-19 23:20:33 +08007578 * following should give the same answer for each host.
John Garryc10fa552020-07-09 20:23:20 +08007579 */
John Garryf7c4cdc2020-08-19 23:20:33 +08007580 hpnt->nr_hw_queues = submit_queues;
7581 if (sdebug_host_max_queue)
7582 hpnt->host_tagset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007583
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307584 /* poll queues are possible for nr_hw_queues > 1 */
7585 if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7586 pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7587 my_name, poll_queues, hpnt->nr_hw_queues);
7588 poll_queues = 0;
7589 }
7590
7591 /*
7592 * Poll queues don't need interrupts, but we need at least one I/O queue
7593 * left over for non-polled I/O.
7594 * If condition not met, trim poll_queues to 1 (just for simplicity).
7595 */
7596 if (poll_queues >= submit_queues) {
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007597 if (submit_queues < 3)
7598 pr_warn("%s: trim poll_queues to 1\n", my_name);
7599 else
7600 pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7601 my_name, submit_queues - 1);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307602 poll_queues = 1;
7603 }
7604 if (poll_queues)
7605 hpnt->nr_maps = 3;
7606
Douglas Gilbert9a051012017-12-23 12:48:10 -05007607 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007609 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7610 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007611 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04007612 hpnt->max_id = sdebug_num_tgts;
7613 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03007614 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007615
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007616 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007617
Douglas Gilbert773642d2016-04-25 12:16:28 -04007618 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007619
Christoph Hellwig8475c812016-09-11 19:35:41 +02007620 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007621 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007622 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007623 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007624 break;
7625
Christoph Hellwig8475c812016-09-11 19:35:41 +02007626 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007627 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007628 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007629 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007630 break;
7631
Christoph Hellwig8475c812016-09-11 19:35:41 +02007632 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007633 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007634 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007635 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007636 break;
7637
7638 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04007639 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007640 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007641 break;
7642 }
7643
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007644 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007645
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007646 if (have_dif_prot || sdebug_dix)
7647 pr_info("host protection%s%s%s%s%s%s%s\n",
7648 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7649 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7650 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7651 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7652 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7653 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7654 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007655
Douglas Gilbert773642d2016-04-25 12:16:28 -04007656 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007657 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7658 else
7659 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7660
Douglas Gilbert773642d2016-04-25 12:16:28 -04007661 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7662 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04007663 if (sdebug_every_nth) /* need stats counters for every_nth */
7664 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007665 error = scsi_add_host(hpnt, &sdbg_host->dev);
7666 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007667 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05007668 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669 scsi_host_put(hpnt);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007670 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007671 scsi_scan_host(hpnt);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007672 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007674 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007675}
7676
Uwe Kleine-Königfc7a6202021-07-13 21:35:22 +02007677static void sdebug_driver_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678{
Douglas Gilbert9a051012017-12-23 12:48:10 -05007679 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007680 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007681
7682 sdbg_host = to_sdebug_host(dev);
7683
Douglas Gilbert9a051012017-12-23 12:48:10 -05007684 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007685
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007686 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
7687 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05007688 list_del(&sdbg_devinfo->dev_list);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09007689 kfree(sdbg_devinfo->zstate);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007690 kfree(sdbg_devinfo);
7691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692
Douglas Gilbert9a051012017-12-23 12:48:10 -05007693 scsi_host_put(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694}
7695
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007696static int pseudo_lld_bus_match(struct device *dev,
7697 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007698{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007699 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007700}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007701
7702static struct bus_type pseudo_lld_bus = {
7703 .name = "pseudo",
7704 .match = pseudo_lld_bus_match,
7705 .probe = sdebug_driver_probe,
7706 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09007707 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007708};