blob: 1d0278da9041394bd0ccc365e48f502436f3f6c9 [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];
Ye Bin4e3ace02021-10-13 11:39:12 +08001859 u32 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,
Ye Bin4e3ace02021-10-13 11:39:12 +08001888 min_t(u32, 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;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001899 int port_group_a, port_group_b, port_a, port_b;
Ye Binf347c262021-10-13 11:39:13 +08001900 u32 alen, n, rlen;
1901 int ret;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001902
Douglas Gilbert773642d2016-04-25 12:16:28 -04001903 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001904 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1905 if (! arr)
1906 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001907 /*
1908 * EVPD page 0x88 states we have two ports, one
1909 * real and a fake port with no device connected.
1910 * So we create two port groups with one port each
1911 * and set the group with port B to unavailable.
1912 */
1913 port_a = 0x1; /* relative port A */
1914 port_b = 0x2; /* relative port B */
1915 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001916 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001917 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001918 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001919
1920 /*
1921 * The asymmetric access state is cycled according to the host_id.
1922 */
1923 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001924 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001925 arr[n++] = host_no % 3; /* Asymm access state */
1926 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001927 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001928 arr[n++] = 0x0; /* Active/Optimized path */
1929 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001930 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001931 put_unaligned_be16(port_group_a, arr + n);
1932 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001933 arr[n++] = 0; /* Reserved */
1934 arr[n++] = 0; /* Status code */
1935 arr[n++] = 0; /* Vendor unique */
1936 arr[n++] = 0x1; /* One port per group */
1937 arr[n++] = 0; /* Reserved */
1938 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001939 put_unaligned_be16(port_a, arr + n);
1940 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001941 arr[n++] = 3; /* Port unavailable */
1942 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001943 put_unaligned_be16(port_group_b, arr + n);
1944 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001945 arr[n++] = 0; /* Reserved */
1946 arr[n++] = 0; /* Status code */
1947 arr[n++] = 0; /* Vendor unique */
1948 arr[n++] = 0x1; /* One port per group */
1949 arr[n++] = 0; /* Reserved */
1950 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001951 put_unaligned_be16(port_b, arr + n);
1952 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001953
1954 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001955 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001956
1957 /*
1958 * Return the smallest value of either
1959 * - The allocated length
1960 * - The constructed command length
1961 * - The maximum array size
1962 */
Ye Binf347c262021-10-13 11:39:13 +08001963 rlen = min(alen, n);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001964 ret = fill_from_dev_buffer(scp, arr,
Ye Binf347c262021-10-13 11:39:13 +08001965 min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001966 kfree(arr);
1967 return ret;
1968}
1969
Douglas Gilbertfd321192016-04-25 12:16:33 -04001970static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1971 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001972{
1973 bool rctd;
1974 u8 reporting_opts, req_opcode, sdeb_i, supp;
1975 u16 req_sa, u;
1976 u32 alloc_len, a_len;
1977 int k, offset, len, errsts, count, bump, na;
1978 const struct opcode_info_t *oip;
1979 const struct opcode_info_t *r_oip;
1980 u8 *arr;
1981 u8 *cmd = scp->cmnd;
1982
1983 rctd = !!(cmd[2] & 0x80);
1984 reporting_opts = cmd[2] & 0x7;
1985 req_opcode = cmd[3];
1986 req_sa = get_unaligned_be16(cmd + 4);
1987 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001988 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001989 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1990 return check_condition_result;
1991 }
1992 if (alloc_len > 8192)
1993 a_len = 8192;
1994 else
1995 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001996 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001997 if (NULL == arr) {
1998 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1999 INSUFF_RES_ASCQ);
2000 return check_condition_result;
2001 }
2002 switch (reporting_opts) {
2003 case 0: /* all commands */
2004 /* count number of commands */
2005 for (count = 0, oip = opcode_info_arr;
2006 oip->num_attached != 0xff; ++oip) {
2007 if (F_INV_OP & oip->flags)
2008 continue;
2009 count += (oip->num_attached + 1);
2010 }
2011 bump = rctd ? 20 : 8;
2012 put_unaligned_be32(count * bump, arr);
2013 for (offset = 4, oip = opcode_info_arr;
2014 oip->num_attached != 0xff && offset < a_len; ++oip) {
2015 if (F_INV_OP & oip->flags)
2016 continue;
2017 na = oip->num_attached;
2018 arr[offset] = oip->opcode;
2019 put_unaligned_be16(oip->sa, arr + offset + 2);
2020 if (rctd)
2021 arr[offset + 5] |= 0x2;
2022 if (FF_SA & oip->flags)
2023 arr[offset + 5] |= 0x1;
2024 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
2025 if (rctd)
2026 put_unaligned_be16(0xa, arr + offset + 8);
2027 r_oip = oip;
2028 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
2029 if (F_INV_OP & oip->flags)
2030 continue;
2031 offset += bump;
2032 arr[offset] = oip->opcode;
2033 put_unaligned_be16(oip->sa, arr + offset + 2);
2034 if (rctd)
2035 arr[offset + 5] |= 0x2;
2036 if (FF_SA & oip->flags)
2037 arr[offset + 5] |= 0x1;
2038 put_unaligned_be16(oip->len_mask[0],
2039 arr + offset + 6);
2040 if (rctd)
2041 put_unaligned_be16(0xa,
2042 arr + offset + 8);
2043 }
2044 oip = r_oip;
2045 offset += bump;
2046 }
2047 break;
2048 case 1: /* one command: opcode only */
2049 case 2: /* one command: opcode plus service action */
2050 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
2051 sdeb_i = opcode_ind_arr[req_opcode];
2052 oip = &opcode_info_arr[sdeb_i];
2053 if (F_INV_OP & oip->flags) {
2054 supp = 1;
2055 offset = 4;
2056 } else {
2057 if (1 == reporting_opts) {
2058 if (FF_SA & oip->flags) {
2059 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
2060 2, 2);
2061 kfree(arr);
2062 return check_condition_result;
2063 }
2064 req_sa = 0;
2065 } else if (2 == reporting_opts &&
2066 0 == (FF_SA & oip->flags)) {
2067 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
2068 kfree(arr); /* point at requested sa */
2069 return check_condition_result;
2070 }
2071 if (0 == (FF_SA & oip->flags) &&
2072 req_opcode == oip->opcode)
2073 supp = 3;
2074 else if (0 == (FF_SA & oip->flags)) {
2075 na = oip->num_attached;
2076 for (k = 0, oip = oip->arrp; k < na;
2077 ++k, ++oip) {
2078 if (req_opcode == oip->opcode)
2079 break;
2080 }
2081 supp = (k >= na) ? 1 : 3;
2082 } else if (req_sa != oip->sa) {
2083 na = oip->num_attached;
2084 for (k = 0, oip = oip->arrp; k < na;
2085 ++k, ++oip) {
2086 if (req_sa == oip->sa)
2087 break;
2088 }
2089 supp = (k >= na) ? 1 : 3;
2090 } else
2091 supp = 3;
2092 if (3 == supp) {
2093 u = oip->len_mask[0];
2094 put_unaligned_be16(u, arr + 2);
2095 arr[4] = oip->opcode;
2096 for (k = 1; k < u; ++k)
2097 arr[4 + k] = (k < 16) ?
2098 oip->len_mask[k] : 0xff;
2099 offset = 4 + u;
2100 } else
2101 offset = 4;
2102 }
2103 arr[1] = (rctd ? 0x80 : 0) | supp;
2104 if (rctd) {
2105 put_unaligned_be16(0xa, arr + offset);
2106 offset += 12;
2107 }
2108 break;
2109 default:
2110 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
2111 kfree(arr);
2112 return check_condition_result;
2113 }
2114 offset = (offset < a_len) ? offset : a_len;
2115 len = (offset < alloc_len) ? offset : alloc_len;
2116 errsts = fill_from_dev_buffer(scp, arr, len);
2117 kfree(arr);
2118 return errsts;
2119}
2120
Douglas Gilbertfd321192016-04-25 12:16:33 -04002121static int resp_rsup_tmfs(struct scsi_cmnd *scp,
2122 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002123{
2124 bool repd;
2125 u32 alloc_len, len;
2126 u8 arr[16];
2127 u8 *cmd = scp->cmnd;
2128
2129 memset(arr, 0, sizeof(arr));
2130 repd = !!(cmd[2] & 0x80);
2131 alloc_len = get_unaligned_be32(cmd + 6);
2132 if (alloc_len < 4) {
2133 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
2134 return check_condition_result;
2135 }
2136 arr[0] = 0xc8; /* ATS | ATSS | LURS */
2137 arr[1] = 0x1; /* ITNRS */
2138 if (repd) {
2139 arr[3] = 0xc;
2140 len = 16;
2141 } else
2142 len = 4;
2143
2144 len = (len < alloc_len) ? len : alloc_len;
2145 return fill_from_dev_buffer(scp, arr, len);
2146}
2147
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148/* <<Following mode page info copied from ST318451LW>> */
2149
John Pittman91d4c752018-02-09 21:12:43 -05002150static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151{ /* Read-Write Error Recovery page for mode_sense */
2152 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
2153 5, 0, 0xff, 0xff};
2154
2155 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
2156 if (1 == pcontrol)
2157 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
2158 return sizeof(err_recov_pg);
2159}
2160
John Pittman91d4c752018-02-09 21:12:43 -05002161static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162{ /* Disconnect-Reconnect page for mode_sense */
2163 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
2164 0, 0, 0, 0, 0, 0, 0, 0};
2165
2166 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
2167 if (1 == pcontrol)
2168 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
2169 return sizeof(disconnect_pg);
2170}
2171
John Pittman91d4c752018-02-09 21:12:43 -05002172static int resp_format_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173{ /* Format device page for mode_sense */
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002174 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
2175 0, 0, 0, 0, 0, 0, 0, 0,
2176 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002178 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002179 put_unaligned_be16(sdebug_sectors_per, p + 10);
2180 put_unaligned_be16(sdebug_sector_size, p + 12);
2181 if (sdebug_removable)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04002182 p[20] |= 0x20; /* should agree with INQUIRY */
2183 if (1 == pcontrol)
2184 memset(p + 2, 0, sizeof(format_pg) - 2);
2185 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186}
2187
Douglas Gilbertfd321192016-04-25 12:16:33 -04002188static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
2189 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
2190 0, 0, 0, 0};
2191
John Pittman91d4c752018-02-09 21:12:43 -05002192static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002194 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2196 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
2198
Douglas Gilbert773642d2016-04-25 12:16:28 -04002199 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002200 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 memcpy(p, caching_pg, sizeof(caching_pg));
2202 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002203 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2204 else if (2 == pcontrol)
2205 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 return sizeof(caching_pg);
2207}
2208
Douglas Gilbertfd321192016-04-25 12:16:33 -04002209static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2210 0, 0, 0x2, 0x4b};
2211
John Pittman91d4c752018-02-09 21:12:43 -05002212static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002214 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05002215 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002216 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 0, 0, 0x2, 0x4b};
2218
Douglas Gilbert773642d2016-04-25 12:16:28 -04002219 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002221 else
2222 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002223
Douglas Gilbert773642d2016-04-25 12:16:28 -04002224 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002225 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2226
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2228 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002229 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2230 else if (2 == pcontrol)
2231 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 return sizeof(ctrl_m_pg);
2233}
2234
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002235
John Pittman91d4c752018-02-09 21:12:43 -05002236static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002238 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2239 0, 0, 0x0, 0x0};
2240 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2241 0, 0, 0x0, 0x0};
2242
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2244 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002245 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2246 else if (2 == pcontrol)
2247 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 return sizeof(iec_m_pg);
2249}
2250
John Pittman91d4c752018-02-09 21:12:43 -05002251static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002252{ /* SAS SSP mode page - short format for mode_sense */
2253 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2254 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2255
2256 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2257 if (1 == pcontrol)
2258 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2259 return sizeof(sas_sf_m_pg);
2260}
2261
2262
John Pittman91d4c752018-02-09 21:12:43 -05002263static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002264 int target_dev_id)
2265{ /* SAS phy control and discover mode page for mode_sense */
2266 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2267 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002268 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2269 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002270 0x2, 0, 0, 0, 0, 0, 0, 0,
2271 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2272 0, 0, 0, 0, 0, 0, 0, 0,
2273 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002274 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2275 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002276 0x3, 0, 0, 0, 0, 0, 0, 0,
2277 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2278 0, 0, 0, 0, 0, 0, 0, 0,
2279 };
2280 int port_a, port_b;
2281
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002282 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2283 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2284 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2285 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002286 port_a = target_dev_id + 1;
2287 port_b = port_a + 1;
2288 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002289 put_unaligned_be32(port_a, p + 20);
2290 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002291 if (1 == pcontrol)
2292 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2293 return sizeof(sas_pcd_m_pg);
2294}
2295
John Pittman91d4c752018-02-09 21:12:43 -05002296static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002297{ /* SAS SSP shared protocol specific port mode subpage */
2298 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2299 0, 0, 0, 0, 0, 0, 0, 0,
2300 };
2301
2302 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2303 if (1 == pcontrol)
2304 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2305 return sizeof(sas_sha_m_pg);
2306}
2307
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308#define SDEBUG_MAX_MSENSE_SZ 256
2309
Douglas Gilbertfd321192016-04-25 12:16:33 -04002310static int resp_mode_sense(struct scsi_cmnd *scp,
2311 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312{
Douglas Gilbert23183912006-09-16 20:30:47 -04002313 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002315 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002316 int target = scp->device->id;
John Pittman91d4c752018-02-09 21:12:43 -05002317 unsigned char *ap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002319 unsigned char *cmd = scp->cmnd;
Douglas Gilbertd36da302020-04-22 19:42:15 +09002320 bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002322 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 pcontrol = (cmd[2] & 0xc0) >> 6;
2324 pcode = cmd[2] & 0x3f;
2325 subpcode = cmd[3];
2326 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002327 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2328 is_disk = (sdebug_ptype == TYPE_DISK);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002329 is_zbc = (devip->zmodel != BLK_ZONED_NONE);
Douglas Gilbertd36da302020-04-22 19:42:15 +09002330 if ((is_disk || is_zbc) && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002331 bd_len = llbaa ? 16 : 8;
2332 else
2333 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002334 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2336 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002337 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 return check_condition_result;
2339 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002340 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2341 (devip->target * 1000) - 3;
Douglas Gilbertd36da302020-04-22 19:42:15 +09002342 /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
2343 if (is_disk || is_zbc) {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002344 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002345 if (sdebug_wp)
2346 dev_spec |= 0x80;
2347 } else
Douglas Gilbert23183912006-09-16 20:30:47 -04002348 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 if (msense_6) {
2350 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002351 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 offset = 4;
2353 } else {
2354 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002355 if (16 == bd_len)
2356 arr[4] = 0x1; /* set LONGLBA bit */
2357 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 offset = 8;
2359 }
2360 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002361 if ((bd_len > 0) && (!sdebug_capacity))
2362 sdebug_capacity = get_sdebug_capacity();
2363
Douglas Gilbert23183912006-09-16 20:30:47 -04002364 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002365 if (sdebug_capacity > 0xfffffffe)
2366 put_unaligned_be32(0xffffffff, ap + 0);
2367 else
2368 put_unaligned_be32(sdebug_capacity, ap + 0);
2369 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002370 offset += bd_len;
2371 ap = arr + offset;
2372 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002373 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2374 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002375 offset += bd_len;
2376 ap = arr + offset;
2377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002379 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2380 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002381 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 return check_condition_result;
2383 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002384 bad_pcode = false;
2385
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 switch (pcode) {
2387 case 0x1: /* Read-Write error recovery page, direct access */
2388 len = resp_err_recov_pg(ap, pcontrol, target);
2389 offset += len;
2390 break;
2391 case 0x2: /* Disconnect-Reconnect page, all devices */
2392 len = resp_disconnect_pg(ap, pcontrol, target);
2393 offset += len;
2394 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002395 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002396 if (is_disk) {
2397 len = resp_format_pg(ap, pcontrol, target);
2398 offset += len;
2399 } else
2400 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002401 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 case 0x8: /* Caching page, direct access */
Douglas Gilbertd36da302020-04-22 19:42:15 +09002403 if (is_disk || is_zbc) {
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002404 len = resp_caching_pg(ap, pcontrol, target);
2405 offset += len;
2406 } else
2407 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 break;
2409 case 0xa: /* Control Mode page, all devices */
2410 len = resp_ctrl_m_pg(ap, pcontrol, target);
2411 offset += len;
2412 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002413 case 0x19: /* if spc==1 then sas phy, control+discover */
2414 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002415 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002416 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002417 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002418 len = 0;
2419 if ((0x0 == subpcode) || (0xff == subpcode))
2420 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2421 if ((0x1 == subpcode) || (0xff == subpcode))
2422 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2423 target_dev_id);
2424 if ((0x2 == subpcode) || (0xff == subpcode))
2425 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2426 offset += len;
2427 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 case 0x1c: /* Informational Exceptions Mode page, all devices */
2429 len = resp_iec_m_pg(ap, pcontrol, target);
2430 offset += len;
2431 break;
2432 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002433 if ((0 == subpcode) || (0xff == subpcode)) {
2434 len = resp_err_recov_pg(ap, pcontrol, target);
2435 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002436 if (is_disk) {
2437 len += resp_format_pg(ap + len, pcontrol,
2438 target);
2439 len += resp_caching_pg(ap + len, pcontrol,
2440 target);
Douglas Gilbertd36da302020-04-22 19:42:15 +09002441 } else if (is_zbc) {
2442 len += resp_caching_pg(ap + len, pcontrol,
2443 target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002444 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002445 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2446 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2447 if (0xff == subpcode) {
2448 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2449 target, target_dev_id);
2450 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2451 }
2452 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002453 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002454 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002455 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002456 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 break;
2459 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002460 bad_pcode = true;
2461 break;
2462 }
2463 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002464 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 return check_condition_result;
2466 }
2467 if (msense_6)
2468 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002469 else
2470 put_unaligned_be16((offset - 2), arr + 0);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002471 return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472}
2473
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002474#define SDEBUG_MAX_MSELECT_SZ 512
2475
Douglas Gilbertfd321192016-04-25 12:16:33 -04002476static int resp_mode_select(struct scsi_cmnd *scp,
2477 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002478{
2479 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002480 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002481 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002482 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002483 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002484
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002485 memset(arr, 0, sizeof(arr));
2486 pf = cmd[1] & 0x10;
2487 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002488 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002489 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002490 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002491 return check_condition_result;
2492 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002493 res = fetch_to_dev_buffer(scp, arr, param_len);
2494 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002495 return DID_ERROR << 16;
2496 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002497 sdev_printk(KERN_INFO, scp->device,
2498 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2499 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002500 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2501 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002502 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002503 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002504 return check_condition_result;
2505 }
2506 off = bd_len + (mselect6 ? 4 : 8);
2507 mpage = arr[off] & 0x3f;
2508 ps = !!(arr[off] & 0x80);
2509 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002510 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002511 return check_condition_result;
2512 }
2513 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002514 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002515 (arr[off + 1] + 2);
2516 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002517 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002518 PARAMETER_LIST_LENGTH_ERR, 0);
2519 return check_condition_result;
2520 }
2521 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002522 case 0x8: /* Caching Mode page */
2523 if (caching_pg[1] == arr[off + 1]) {
2524 memcpy(caching_pg + 2, arr + off + 2,
2525 sizeof(caching_pg) - 2);
2526 goto set_mode_changed_ua;
2527 }
2528 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002529 case 0xa: /* Control Mode page */
2530 if (ctrl_m_pg[1] == arr[off + 1]) {
2531 memcpy(ctrl_m_pg + 2, arr + off + 2,
2532 sizeof(ctrl_m_pg) - 2);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002533 if (ctrl_m_pg[4] & 0x8)
2534 sdebug_wp = true;
2535 else
2536 sdebug_wp = false;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002537 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002538 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002539 }
2540 break;
2541 case 0x1c: /* Informational Exceptions Mode page */
2542 if (iec_m_pg[1] == arr[off + 1]) {
2543 memcpy(iec_m_pg + 2, arr + off + 2,
2544 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002545 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002546 }
2547 break;
2548 default:
2549 break;
2550 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002551 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002552 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002553set_mode_changed_ua:
2554 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2555 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002556}
2557
John Pittman91d4c752018-02-09 21:12:43 -05002558static int resp_temp_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002559{
2560 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2561 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2562 };
2563
Douglas Gilbert9a051012017-12-23 12:48:10 -05002564 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2565 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002566}
2567
John Pittman91d4c752018-02-09 21:12:43 -05002568static int resp_ie_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002569{
2570 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2571 };
2572
Douglas Gilbert9a051012017-12-23 12:48:10 -05002573 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002574 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2575 arr[4] = THRESHOLD_EXCEEDED;
2576 arr[5] = 0xff;
2577 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002578 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002579}
2580
2581#define SDEBUG_MAX_LSENSE_SZ 512
2582
Douglas Gilbert9a051012017-12-23 12:48:10 -05002583static int resp_log_sense(struct scsi_cmnd *scp,
2584 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002585{
Bart Van Asscheab172412017-08-25 13:46:42 -07002586 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002587 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002588 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002589
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002590 memset(arr, 0, sizeof(arr));
2591 ppc = cmd[1] & 0x2;
2592 sp = cmd[1] & 0x1;
2593 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002594 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002595 return check_condition_result;
2596 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002597 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002598 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002599 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002600 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002601 if (0 == subpcode) {
2602 switch (pcode) {
2603 case 0x0: /* Supported log pages log page */
2604 n = 4;
2605 arr[n++] = 0x0; /* this page */
2606 arr[n++] = 0xd; /* Temperature */
2607 arr[n++] = 0x2f; /* Informational exceptions */
2608 arr[3] = n - 4;
2609 break;
2610 case 0xd: /* Temperature log page */
2611 arr[3] = resp_temp_l_pg(arr + 4);
2612 break;
2613 case 0x2f: /* Informational exceptions log page */
2614 arr[3] = resp_ie_l_pg(arr + 4);
2615 break;
2616 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002617 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002618 return check_condition_result;
2619 }
2620 } else if (0xff == subpcode) {
2621 arr[0] |= 0x40;
2622 arr[1] = subpcode;
2623 switch (pcode) {
2624 case 0x0: /* Supported log pages and subpages log page */
2625 n = 4;
2626 arr[n++] = 0x0;
2627 arr[n++] = 0x0; /* 0,0 page */
2628 arr[n++] = 0x0;
2629 arr[n++] = 0xff; /* this page */
2630 arr[n++] = 0xd;
2631 arr[n++] = 0x0; /* Temperature */
2632 arr[n++] = 0x2f;
2633 arr[n++] = 0x0; /* Informational exceptions */
2634 arr[3] = n - 4;
2635 break;
2636 case 0xd: /* Temperature subpages */
2637 n = 4;
2638 arr[n++] = 0xd;
2639 arr[n++] = 0x0; /* Temperature */
2640 arr[3] = n - 4;
2641 break;
2642 case 0x2f: /* Informational exceptions subpages */
2643 n = 4;
2644 arr[n++] = 0x2f;
2645 arr[n++] = 0x0; /* Informational exceptions */
2646 arr[3] = n - 4;
2647 break;
2648 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002649 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002650 return check_condition_result;
2651 }
2652 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002653 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002654 return check_condition_result;
2655 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002656 len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002657 return fill_from_dev_buffer(scp, arr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002658 min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002659}
2660
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002661static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662{
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002663 return devip->nr_zones != 0;
2664}
2665
2666static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
2667 unsigned long long lba)
2668{
Damien Le Moal108e36f2020-05-07 11:35:26 +09002669 return &devip->zstate[lba >> devip->zsize_shift];
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002670}
2671
2672static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
2673{
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002674 return zsp->z_type == ZBC_ZONE_TYPE_CNV;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002675}
2676
2677static void zbc_close_zone(struct sdebug_dev_info *devip,
2678 struct sdeb_zone_state *zsp)
2679{
2680 enum sdebug_z_cond zc;
2681
2682 if (zbc_zone_is_conv(zsp))
2683 return;
2684
2685 zc = zsp->z_cond;
2686 if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
2687 return;
2688
2689 if (zc == ZC2_IMPLICIT_OPEN)
2690 devip->nr_imp_open--;
2691 else
2692 devip->nr_exp_open--;
2693
2694 if (zsp->z_wp == zsp->z_start) {
2695 zsp->z_cond = ZC1_EMPTY;
2696 } else {
2697 zsp->z_cond = ZC4_CLOSED;
2698 devip->nr_closed++;
2699 }
2700}
2701
2702static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
2703{
2704 struct sdeb_zone_state *zsp = &devip->zstate[0];
2705 unsigned int i;
2706
2707 for (i = 0; i < devip->nr_zones; i++, zsp++) {
2708 if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
2709 zbc_close_zone(devip, zsp);
2710 return;
2711 }
2712 }
2713}
2714
2715static void zbc_open_zone(struct sdebug_dev_info *devip,
2716 struct sdeb_zone_state *zsp, bool explicit)
2717{
2718 enum sdebug_z_cond zc;
2719
2720 if (zbc_zone_is_conv(zsp))
2721 return;
2722
2723 zc = zsp->z_cond;
2724 if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
2725 (!explicit && zc == ZC2_IMPLICIT_OPEN))
2726 return;
2727
2728 /* Close an implicit open zone if necessary */
2729 if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
2730 zbc_close_zone(devip, zsp);
2731 else if (devip->max_open &&
2732 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
2733 zbc_close_imp_open_zone(devip);
2734
2735 if (zsp->z_cond == ZC4_CLOSED)
2736 devip->nr_closed--;
2737 if (explicit) {
2738 zsp->z_cond = ZC3_EXPLICIT_OPEN;
2739 devip->nr_exp_open++;
2740 } else {
2741 zsp->z_cond = ZC2_IMPLICIT_OPEN;
2742 devip->nr_imp_open++;
2743 }
2744}
2745
2746static void zbc_inc_wp(struct sdebug_dev_info *devip,
2747 unsigned long long lba, unsigned int num)
2748{
2749 struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002750 unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002751
2752 if (zbc_zone_is_conv(zsp))
2753 return;
2754
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002755 if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2756 zsp->z_wp += num;
2757 if (zsp->z_wp >= zend)
2758 zsp->z_cond = ZC5_FULL;
2759 return;
2760 }
2761
2762 while (num) {
2763 if (lba != zsp->z_wp)
2764 zsp->z_non_seq_resource = true;
2765
2766 end = lba + num;
2767 if (end >= zend) {
2768 n = zend - lba;
2769 zsp->z_wp = zend;
2770 } else if (end > zsp->z_wp) {
2771 n = num;
2772 zsp->z_wp = end;
2773 } else {
2774 n = num;
2775 }
2776 if (zsp->z_wp >= zend)
2777 zsp->z_cond = ZC5_FULL;
2778
2779 num -= n;
2780 lba += n;
2781 if (num) {
2782 zsp++;
2783 zend = zsp->z_start + zsp->z_size;
2784 }
2785 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002786}
2787
2788static int check_zbc_access_params(struct scsi_cmnd *scp,
2789 unsigned long long lba, unsigned int num, bool write)
2790{
2791 struct scsi_device *sdp = scp->device;
2792 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2793 struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
2794 struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
2795
2796 if (!write) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002797 if (devip->zmodel == BLK_ZONED_HA)
2798 return 0;
2799 /* For host-managed, reads cannot cross zone types boundaries */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002800 if (zsp_end != zsp &&
2801 zbc_zone_is_conv(zsp) &&
2802 !zbc_zone_is_conv(zsp_end)) {
2803 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2804 LBA_OUT_OF_RANGE,
2805 READ_INVDATA_ASCQ);
2806 return check_condition_result;
2807 }
2808 return 0;
2809 }
2810
2811 /* No restrictions for writes within conventional zones */
2812 if (zbc_zone_is_conv(zsp)) {
2813 if (!zbc_zone_is_conv(zsp_end)) {
2814 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2815 LBA_OUT_OF_RANGE,
2816 WRITE_BOUNDARY_ASCQ);
2817 return check_condition_result;
2818 }
2819 return 0;
2820 }
2821
Damien Le Moal64e14ec2020-04-22 19:42:21 +09002822 if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
2823 /* Writes cannot cross sequential zone boundaries */
2824 if (zsp_end != zsp) {
2825 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2826 LBA_OUT_OF_RANGE,
2827 WRITE_BOUNDARY_ASCQ);
2828 return check_condition_result;
2829 }
2830 /* Cannot write full zones */
2831 if (zsp->z_cond == ZC5_FULL) {
2832 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2833 INVALID_FIELD_IN_CDB, 0);
2834 return check_condition_result;
2835 }
2836 /* Writes must be aligned to the zone WP */
2837 if (lba != zsp->z_wp) {
2838 mk_sense_buffer(scp, ILLEGAL_REQUEST,
2839 LBA_OUT_OF_RANGE,
2840 UNALIGNED_WRITE_ASCQ);
2841 return check_condition_result;
2842 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002843 }
2844
2845 /* Handle implicit open of closed and empty zones */
2846 if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
2847 if (devip->max_open &&
2848 devip->nr_exp_open >= devip->max_open) {
2849 mk_sense_buffer(scp, DATA_PROTECT,
2850 INSUFF_RES_ASC,
2851 INSUFF_ZONE_ASCQ);
2852 return check_condition_result;
2853 }
2854 zbc_open_zone(devip, zsp, false);
2855 }
2856
2857 return 0;
2858}
2859
2860static inline int check_device_access_params
2861 (struct scsi_cmnd *scp, unsigned long long lba,
2862 unsigned int num, bool write)
2863{
2864 struct scsi_device *sdp = scp->device;
2865 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
2866
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002867 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002868 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 return check_condition_result;
2870 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002871 /* transfer length excessive (tie in to block limits VPD page) */
2872 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002873 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002874 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002875 return check_condition_result;
2876 }
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002877 if (write && unlikely(sdebug_wp)) {
2878 mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
2879 return check_condition_result;
2880 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09002881 if (sdebug_dev_is_zoned(devip))
2882 return check_zbc_access_params(scp, lba, num, write);
2883
FUJITA Tomonori19789102008-03-30 00:59:56 +09002884 return 0;
2885}
2886
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04002887/*
2888 * Note: if BUG_ON() fires it usually indicates a problem with the parser
2889 * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
2890 * that access any of the "stores" in struct sdeb_store_info should call this
2891 * function with bug_if_fake_rw set to true.
2892 */
2893static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
2894 bool bug_if_fake_rw)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002895{
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04002896 if (sdebug_fake_rw) {
2897 BUG_ON(bug_if_fake_rw); /* See note above */
2898 return NULL;
2899 }
2900 return xa_load(per_store_ap, devip->sdbg_host->si_idx);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002901}
2902
Akinobu Mitaa4517512013-07-08 16:01:57 -07002903/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002904static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
2905 u32 sg_skip, u64 lba, u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002906{
2907 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002908 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002909 enum dma_data_direction dir;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002910 struct scsi_data_buffer *sdb = &scp->sdb;
2911 u8 *fsp;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002912
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002913 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002914 dir = DMA_TO_DEVICE;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04002915 write_since_sync = true;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002916 } else {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002917 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002918 }
2919
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002920 if (!sdb->length || !sip)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002921 return 0;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002922 if (scp->sc_data_direction != dir)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002923 return -1;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002924 fsp = sip->storep;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002925
2926 block = do_div(lba, sdebug_store_sectors);
2927 if (block + num > sdebug_store_sectors)
2928 rest = block + num - sdebug_store_sectors;
2929
Dave Gordon386ecb12015-06-30 14:58:57 -07002930 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002931 fsp + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002932 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002933 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002934 return ret;
2935
2936 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002937 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002938 fsp, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002939 sg_skip + ((num - rest) * sdebug_sector_size),
2940 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002941 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002942
2943 return ret;
2944}
2945
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002946/* Returns number of bytes copied or -1 if error. */
2947static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
2948{
2949 struct scsi_data_buffer *sdb = &scp->sdb;
2950
2951 if (!sdb->length)
2952 return 0;
2953 if (scp->sc_data_direction != DMA_TO_DEVICE)
2954 return -1;
2955 return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
2956 num * sdebug_sector_size, 0, true);
2957}
2958
2959/* If sip->storep+lba compares equal to arr(num), then copy top half of
2960 * arr into sip->storep+lba and return true. If comparison fails then
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002961 * return false. */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002962static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04002963 const u8 *arr, bool compare_only)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002964{
2965 bool res;
2966 u64 block, rest = 0;
2967 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002968 u32 lb_size = sdebug_sector_size;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002969 u8 *fsp = sip->storep;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002970
2971 block = do_div(lba, store_blks);
2972 if (block + num > store_blks)
2973 rest = block + num - store_blks;
2974
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002975 res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002976 if (!res)
2977 return res;
2978 if (rest)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002979 res = memcmp(fsp, arr + ((num - rest) * lb_size),
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002980 rest * lb_size);
2981 if (!res)
2982 return res;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04002983 if (compare_only)
2984 return true;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002985 arr += num * lb_size;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002986 memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002987 if (rest)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04002988 memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002989 return res;
2990}
2991
Akinobu Mita51d648a2013-09-18 21:27:28 +09002992static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002993{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002994 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002995
Douglas Gilbert773642d2016-04-25 12:16:28 -04002996 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002997 csum = (__force __be16)ip_compute_csum(buf, len);
2998 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002999 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09003000
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003001 return csum;
3002}
3003
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003004static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003005 sector_t sector, u32 ei_lba)
3006{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003007 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003008
3009 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003010 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003011 (unsigned long)sector,
3012 be16_to_cpu(sdt->guard_tag),
3013 be16_to_cpu(csum));
3014 return 0x01;
3015 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003016 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003017 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003018 pr_err("REF check failed on sector %lu\n",
3019 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003020 return 0x03;
3021 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003022 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003023 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003024 pr_err("REF check failed on sector %lu\n",
3025 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09003026 return 0x03;
3027 }
3028 return 0;
3029}
3030
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003031static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003032 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003033{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003034 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003035 void *paddr;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003036 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003037 scp->device->hostdata, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003038 struct t10_pi_tuple *dif_storep = sip->dif_storep;
Akinobu Mita14faa942013-09-18 21:27:24 +09003039 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003040 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003041
Akinobu Mitae18d8be2013-06-29 17:59:18 +09003042 /* Bytes of protection data to copy into sgl */
3043 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003044
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003045 sg_miter_start(&miter, scsi_prot_sglist(scp),
3046 scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
3047 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003048
3049 while (sg_miter_next(&miter) && resid > 0) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003050 size_t len = min_t(size_t, miter.length, resid);
3051 void *start = dif_store(sip, sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003052 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09003053
3054 if (dif_store_end < start + len)
3055 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003056
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003057 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09003058
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003059 if (read)
3060 memcpy(paddr, start, len - rest);
3061 else
3062 memcpy(start, paddr, len - rest);
3063
3064 if (rest) {
3065 if (read)
3066 memcpy(paddr + len - rest, dif_storep, rest);
3067 else
3068 memcpy(dif_storep, paddr + len - rest, rest);
3069 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003070
Akinobu Mitae18d8be2013-06-29 17:59:18 +09003071 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003072 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003073 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003074 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003075}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003076
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003077static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003078 unsigned int sectors, u32 ei_lba)
3079{
Martin K. Petersenf7be6772021-06-08 23:39:23 -04003080 int ret = 0;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003081 unsigned int i;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003082 sector_t sector;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003083 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003084 scp->device->hostdata, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003085 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003086
Akinobu Mitac45eabec2014-02-26 22:56:58 +09003087 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003088 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
Martin K. Petersenf7be6772021-06-08 23:39:23 -04003094 /*
3095 * Because scsi_debug acts as both initiator and
3096 * target we proceed to verify the PI even if
3097 * RDPROTECT=3. This is done so the "initiator" knows
3098 * which type of error to return. Otherwise we would
3099 * have to iterate over the PI twice.
3100 */
3101 if (scp->cmnd[1] >> 5) { /* RDPROTECT */
3102 ret = dif_verify(sdt, lba2fake_store(sip, sector),
3103 sector, ei_lba);
3104 if (ret) {
3105 dif_errors++;
3106 break;
3107 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003108 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09003109 }
3110
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003111 dif_copy_prot(scp, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003112 dix_reads++;
3113
Martin K. Petersenf7be6772021-06-08 23:39:23 -04003114 return ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003115}
3116
Douglas Gilbertfd321192016-04-25 12:16:33 -04003117static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09003118{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003119 bool check_prot;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003120 u32 num;
3121 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003122 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003123 u64 lba;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003124 struct sdeb_store_info *sip = devip2sip(devip, true);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003125 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
3126 u8 *cmd = scp->cmnd;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003127
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003128 switch (cmd[0]) {
3129 case READ_16:
3130 ei_lba = 0;
3131 lba = get_unaligned_be64(cmd + 2);
3132 num = get_unaligned_be32(cmd + 10);
3133 check_prot = true;
3134 break;
3135 case READ_10:
3136 ei_lba = 0;
3137 lba = get_unaligned_be32(cmd + 2);
3138 num = get_unaligned_be16(cmd + 7);
3139 check_prot = true;
3140 break;
3141 case READ_6:
3142 ei_lba = 0;
3143 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3144 (u32)(cmd[1] & 0x1f) << 16;
3145 num = (0 == cmd[4]) ? 256 : cmd[4];
3146 check_prot = true;
3147 break;
3148 case READ_12:
3149 ei_lba = 0;
3150 lba = get_unaligned_be32(cmd + 2);
3151 num = get_unaligned_be32(cmd + 6);
3152 check_prot = true;
3153 break;
3154 case XDWRITEREAD_10:
3155 ei_lba = 0;
3156 lba = get_unaligned_be32(cmd + 2);
3157 num = get_unaligned_be16(cmd + 7);
3158 check_prot = false;
3159 break;
3160 default: /* assume READ(32) */
3161 lba = get_unaligned_be64(cmd + 12);
3162 ei_lba = get_unaligned_be32(cmd + 20);
3163 num = get_unaligned_be32(cmd + 28);
3164 check_prot = false;
3165 break;
3166 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003167 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003168 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003169 (cmd[1] & 0xe0)) {
3170 mk_sense_invalid_opcode(scp);
3171 return check_condition_result;
3172 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003173 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3174 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003175 (cmd[1] & 0xe0) == 0)
3176 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
3177 "to DIF device\n");
3178 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003179 if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
3180 atomic_read(&sdeb_inject_pending))) {
3181 num /= 2;
3182 atomic_set(&sdeb_inject_pending, 0);
3183 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003184
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003185 ret = check_device_access_params(scp, lba, num, false);
3186 if (ret)
3187 return ret;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003188 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05003189 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
3190 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003191 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003192 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003193 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003194 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
3195 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05003196 ret = (lba < OPT_MEDIUM_ERR_ADDR)
3197 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003198 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003199 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003200 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 return check_condition_result;
3202 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003203
Douglas Gilbert67da4132020-04-21 11:14:20 -04003204 read_lock(macc_lckp);
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003205
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003206 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003207 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Martin K. Petersenf7be6772021-06-08 23:39:23 -04003208 switch (prot_verify_read(scp, lba, num, ei_lba)) {
3209 case 1: /* Guard tag error */
3210 if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
3211 read_unlock(macc_lckp);
3212 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3213 return check_condition_result;
3214 } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
3215 read_unlock(macc_lckp);
3216 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3217 return illegal_condition_result;
3218 }
3219 break;
3220 case 3: /* Reference tag error */
3221 if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
3222 read_unlock(macc_lckp);
3223 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3224 return check_condition_result;
3225 } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
3226 read_unlock(macc_lckp);
3227 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3228 return illegal_condition_result;
3229 }
3230 break;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003231 }
3232 }
3233
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003234 ret = do_device_access(sip, scp, 0, lba, num, false);
Douglas Gilbert67da4132020-04-21 11:14:20 -04003235 read_unlock(macc_lckp);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003236 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07003237 return DID_ERROR << 16;
3238
Bart Van Assche42d387b2019-02-08 13:25:00 -08003239 scsi_set_resid(scp, scsi_bufflen(scp) - ret);
Akinobu Mitaa4517512013-07-08 16:01:57 -07003240
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003241 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3242 atomic_read(&sdeb_inject_pending))) {
3243 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3244 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3245 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003246 return check_condition_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003247 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003248 /* Logical block guard check failed */
3249 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003250 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003251 return illegal_condition_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003252 } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003253 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003254 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003255 return illegal_condition_result;
3256 }
3257 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07003258 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259}
3260
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003261static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04003262 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003263{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003264 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003265 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003266 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003267 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003268 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003269 int dpage_offset;
3270 struct sg_mapping_iter diter;
3271 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003272
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003273 BUG_ON(scsi_sg_count(SCpnt) == 0);
3274 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
3275
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003276 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
3277 scsi_prot_sg_count(SCpnt),
3278 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
3279 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
3280 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003281
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003282 /* For each protection page */
3283 while (sg_miter_next(&piter)) {
3284 dpage_offset = 0;
3285 if (WARN_ON(!sg_miter_next(&diter))) {
3286 ret = 0x01;
3287 goto out;
3288 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003289
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003290 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02003291 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003292 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003293 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003294 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003295 if (dpage_offset >= diter.length) {
3296 if (WARN_ON(!sg_miter_next(&diter))) {
3297 ret = 0x01;
3298 goto out;
3299 }
3300 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003301 }
3302
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003303 sdt = piter.addr + ppage_offset;
3304 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003305
Martin K. Petersenf7be6772021-06-08 23:39:23 -04003306 if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */
3307 ret = dif_verify(sdt, daddr, sector, ei_lba);
3308 if (ret)
3309 goto out;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003310 }
3311
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003312 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003313 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003314 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003315 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003316 diter.consumed = dpage_offset;
3317 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003318 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003319 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003320
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09003321 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003322 dix_writes++;
3323
3324 return 0;
3325
3326out:
3327 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003328 sg_miter_stop(&diter);
3329 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003330 return ret;
3331}
3332
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003333static unsigned long lba_to_map_index(sector_t lba)
3334{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003335 if (sdebug_unmap_alignment)
3336 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
3337 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003338 return lba;
3339}
3340
3341static sector_t map_index_to_lba(unsigned long index)
3342{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003343 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09003344
Douglas Gilbert773642d2016-04-25 12:16:28 -04003345 if (sdebug_unmap_alignment)
3346 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09003347 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003348}
3349
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003350static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
3351 unsigned int *num)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003352{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003353 sector_t end;
3354 unsigned int mapped;
3355 unsigned long index;
3356 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003357
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003358 index = lba_to_map_index(lba);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003359 mapped = test_bit(index, sip->map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003360
3361 if (mapped)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003362 next = find_next_zero_bit(sip->map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003363 else
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003364 next = find_next_bit(sip->map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003365
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003366 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003367 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003368 return mapped;
3369}
3370
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003371static void map_region(struct sdeb_store_info *sip, sector_t lba,
3372 unsigned int len)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003373{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003374 sector_t end = lba + len;
3375
Martin K. Petersen44d92692009-10-15 14:45:27 -04003376 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003377 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003378
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003379 if (index < map_size)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003380 set_bit(index, sip->map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003381
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003382 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003383 }
3384}
3385
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003386static void unmap_region(struct sdeb_store_info *sip, sector_t lba,
3387 unsigned int len)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003388{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003389 sector_t end = lba + len;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003390 u8 *fsp = sip->storep;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003391
Martin K. Petersen44d92692009-10-15 14:45:27 -04003392 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003393 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003394
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003395 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04003396 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003397 index < map_size) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003398 clear_bit(index, sip->map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04003399 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003400 memset(fsp + lba * sdebug_sector_size,
Douglas Gilbert760f3b02016-05-06 00:40:27 -04003401 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04003402 sdebug_sector_size *
3403 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003404 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003405 if (sip->dif_storep) {
3406 memset(sip->dif_storep + lba, 0xff,
3407 sizeof(*sip->dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04003408 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09003409 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003410 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003411 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003412 }
3413}
3414
Douglas Gilbertfd321192016-04-25 12:16:33 -04003415static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003417 bool check_prot;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003418 u32 num;
3419 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09003420 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003421 u64 lba;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003422 struct sdeb_store_info *sip = devip2sip(devip, true);
3423 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003424 u8 *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003426 switch (cmd[0]) {
3427 case WRITE_16:
3428 ei_lba = 0;
3429 lba = get_unaligned_be64(cmd + 2);
3430 num = get_unaligned_be32(cmd + 10);
3431 check_prot = true;
3432 break;
3433 case WRITE_10:
3434 ei_lba = 0;
3435 lba = get_unaligned_be32(cmd + 2);
3436 num = get_unaligned_be16(cmd + 7);
3437 check_prot = true;
3438 break;
3439 case WRITE_6:
3440 ei_lba = 0;
3441 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
3442 (u32)(cmd[1] & 0x1f) << 16;
3443 num = (0 == cmd[4]) ? 256 : cmd[4];
3444 check_prot = true;
3445 break;
3446 case WRITE_12:
3447 ei_lba = 0;
3448 lba = get_unaligned_be32(cmd + 2);
3449 num = get_unaligned_be32(cmd + 6);
3450 check_prot = true;
3451 break;
3452 case 0x53: /* XDWRITEREAD(10) */
3453 ei_lba = 0;
3454 lba = get_unaligned_be32(cmd + 2);
3455 num = get_unaligned_be16(cmd + 7);
3456 check_prot = false;
3457 break;
3458 default: /* assume WRITE(32) */
3459 lba = get_unaligned_be64(cmd + 12);
3460 ei_lba = get_unaligned_be32(cmd + 20);
3461 num = get_unaligned_be32(cmd + 28);
3462 check_prot = false;
3463 break;
3464 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003465 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003466 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003467 (cmd[1] & 0xe0)) {
3468 mk_sense_invalid_opcode(scp);
3469 return check_condition_result;
3470 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003471 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3472 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003473 (cmd[1] & 0xe0) == 0)
3474 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3475 "to DIF device\n");
3476 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003477
Douglas Gilbert67da4132020-04-21 11:14:20 -04003478 write_lock(macc_lckp);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003479 ret = check_device_access_params(scp, lba, num, true);
3480 if (ret) {
3481 write_unlock(macc_lckp);
3482 return ret;
3483 }
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003484
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003485 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003486 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Martin K. Petersenf7be6772021-06-08 23:39:23 -04003487 switch (prot_verify_write(scp, lba, num, ei_lba)) {
3488 case 1: /* Guard tag error */
3489 if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
3490 write_unlock(macc_lckp);
3491 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3492 return illegal_condition_result;
3493 } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
3494 write_unlock(macc_lckp);
3495 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3496 return check_condition_result;
3497 }
3498 break;
3499 case 3: /* Reference tag error */
3500 if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
3501 write_unlock(macc_lckp);
3502 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
3503 return illegal_condition_result;
3504 } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
3505 write_unlock(macc_lckp);
3506 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
3507 return check_condition_result;
3508 }
3509 break;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003510 }
3511 }
3512
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003513 ret = do_device_access(sip, scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003514 if (unlikely(scsi_debug_lbp()))
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003515 map_region(sip, lba, num);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003516 /* If ZBC zone then bump its write pointer */
3517 if (sdebug_dev_is_zoned(devip))
3518 zbc_inc_wp(devip, lba, num);
Douglas Gilbert67da4132020-04-21 11:14:20 -04003519 write_unlock(macc_lckp);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003520 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003521 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003522 else if (unlikely(sdebug_verbose &&
3523 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003524 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003525 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003526 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003527
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003528 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3529 atomic_read(&sdeb_inject_pending))) {
3530 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3531 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3532 atomic_set(&sdeb_inject_pending, 0);
3533 return check_condition_result;
3534 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3535 /* Logical block guard check failed */
3536 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3537 atomic_set(&sdeb_inject_pending, 0);
3538 return illegal_condition_result;
3539 } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3540 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3541 atomic_set(&sdeb_inject_pending, 0);
3542 return illegal_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003543 }
3544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 return 0;
3546}
3547
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003548/*
3549 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3550 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3551 */
3552static int resp_write_scat(struct scsi_cmnd *scp,
3553 struct sdebug_dev_info *devip)
3554{
3555 u8 *cmd = scp->cmnd;
3556 u8 *lrdp = NULL;
3557 u8 *up;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003558 struct sdeb_store_info *sip = devip2sip(devip, true);
3559 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003560 u8 wrprotect;
3561 u16 lbdof, num_lrd, k;
3562 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3563 u32 lb_size = sdebug_sector_size;
3564 u32 ei_lba;
3565 u64 lba;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003566 int ret, res;
3567 bool is_16;
3568 static const u32 lrd_size = 32; /* + parameter list header size */
3569
3570 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3571 is_16 = false;
3572 wrprotect = (cmd[10] >> 5) & 0x7;
3573 lbdof = get_unaligned_be16(cmd + 12);
3574 num_lrd = get_unaligned_be16(cmd + 16);
3575 bt_len = get_unaligned_be32(cmd + 28);
3576 } else { /* that leaves WRITE SCATTERED(16) */
3577 is_16 = true;
3578 wrprotect = (cmd[2] >> 5) & 0x7;
3579 lbdof = get_unaligned_be16(cmd + 4);
3580 num_lrd = get_unaligned_be16(cmd + 8);
3581 bt_len = get_unaligned_be32(cmd + 10);
3582 if (unlikely(have_dif_prot)) {
3583 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3584 wrprotect) {
3585 mk_sense_invalid_opcode(scp);
3586 return illegal_condition_result;
3587 }
3588 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3589 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3590 wrprotect == 0)
3591 sdev_printk(KERN_ERR, scp->device,
3592 "Unprotected WR to DIF device\n");
3593 }
3594 }
3595 if ((num_lrd == 0) || (bt_len == 0))
3596 return 0; /* T10 says these do-nothings are not errors */
3597 if (lbdof == 0) {
3598 if (sdebug_verbose)
3599 sdev_printk(KERN_INFO, scp->device,
3600 "%s: %s: LB Data Offset field bad\n",
3601 my_name, __func__);
3602 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3603 return illegal_condition_result;
3604 }
3605 lbdof_blen = lbdof * lb_size;
3606 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3607 if (sdebug_verbose)
3608 sdev_printk(KERN_INFO, scp->device,
3609 "%s: %s: LBA range descriptors don't fit\n",
3610 my_name, __func__);
3611 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3612 return illegal_condition_result;
3613 }
3614 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3615 if (lrdp == NULL)
3616 return SCSI_MLQUEUE_HOST_BUSY;
3617 if (sdebug_verbose)
3618 sdev_printk(KERN_INFO, scp->device,
3619 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3620 my_name, __func__, lbdof_blen);
3621 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3622 if (res == -1) {
3623 ret = DID_ERROR << 16;
3624 goto err_out;
3625 }
3626
Douglas Gilbert67da4132020-04-21 11:14:20 -04003627 write_lock(macc_lckp);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003628 sg_off = lbdof_blen;
3629 /* Spec says Buffer xfer Length field in number of LBs in dout */
3630 cum_lb = 0;
3631 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3632 lba = get_unaligned_be64(up + 0);
3633 num = get_unaligned_be32(up + 8);
3634 if (sdebug_verbose)
3635 sdev_printk(KERN_INFO, scp->device,
3636 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3637 my_name, __func__, k, lba, num, sg_off);
3638 if (num == 0)
3639 continue;
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003640 ret = check_device_access_params(scp, lba, num, true);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003641 if (ret)
3642 goto err_out_unlock;
3643 num_by = num * lb_size;
3644 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3645
3646 if ((cum_lb + num) > bt_len) {
3647 if (sdebug_verbose)
3648 sdev_printk(KERN_INFO, scp->device,
3649 "%s: %s: sum of blocks > data provided\n",
3650 my_name, __func__);
3651 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3652 0);
3653 ret = illegal_condition_result;
3654 goto err_out_unlock;
3655 }
3656
3657 /* DIX + T10 DIF */
3658 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3659 int prot_ret = prot_verify_write(scp, lba, num,
3660 ei_lba);
3661
3662 if (prot_ret) {
3663 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3664 prot_ret);
3665 ret = illegal_condition_result;
3666 goto err_out_unlock;
3667 }
3668 }
3669
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003670 ret = do_device_access(sip, scp, sg_off, lba, num, true);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003671 /* If ZBC zone then bump its write pointer */
3672 if (sdebug_dev_is_zoned(devip))
3673 zbc_inc_wp(devip, lba, num);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003674 if (unlikely(scsi_debug_lbp()))
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003675 map_region(sip, lba, num);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003676 if (unlikely(-1 == ret)) {
3677 ret = DID_ERROR << 16;
3678 goto err_out_unlock;
3679 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3680 sdev_printk(KERN_INFO, scp->device,
3681 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3682 my_name, num_by, ret);
3683
Douglas Gilbert3a90a632020-07-12 14:29:26 -04003684 if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
3685 atomic_read(&sdeb_inject_pending))) {
3686 if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
3687 mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
3688 atomic_set(&sdeb_inject_pending, 0);
3689 ret = check_condition_result;
3690 goto err_out_unlock;
3691 } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
3692 /* Logical block guard check failed */
3693 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3694 atomic_set(&sdeb_inject_pending, 0);
3695 ret = illegal_condition_result;
3696 goto err_out_unlock;
3697 } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
3698 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3699 atomic_set(&sdeb_inject_pending, 0);
3700 ret = illegal_condition_result;
3701 goto err_out_unlock;
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003702 }
3703 }
3704 sg_off += num_by;
3705 cum_lb += num;
3706 }
3707 ret = 0;
3708err_out_unlock:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003709 write_unlock(macc_lckp);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003710err_out:
3711 kfree(lrdp);
3712 return ret;
3713}
3714
Douglas Gilbertfd321192016-04-25 12:16:33 -04003715static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3716 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003717{
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003718 struct scsi_device *sdp = scp->device;
3719 struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003720 unsigned long long i;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003721 u64 block, lbaa;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003722 u32 lb_size = sdebug_sector_size;
3723 int ret;
3724 struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003725 scp->device->hostdata, true);
3726 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003727 u8 *fs1p;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003728 u8 *fsp;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003729
Douglas Gilbert67da4132020-04-21 11:14:20 -04003730 write_lock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003731
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003732 ret = check_device_access_params(scp, lba, num, true);
3733 if (ret) {
3734 write_unlock(macc_lckp);
3735 return ret;
3736 }
3737
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003738 if (unmap && scsi_debug_lbp()) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003739 unmap_region(sip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003740 goto out;
3741 }
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003742 lbaa = lba;
3743 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003744 /* if ndob then zero 1 logical block, else fetch 1 logical block */
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003745 fsp = sip->storep;
3746 fs1p = fsp + (block * lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003747 if (ndob) {
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003748 memset(fs1p, 0, lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003749 ret = 0;
3750 } else
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003751 ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003752
3753 if (-1 == ret) {
Douglas Gilbert67da4132020-04-21 11:14:20 -04003754 write_unlock(&sip->macc_lck);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003755 return DID_ERROR << 16;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003756 } else if (sdebug_verbose && !ndob && (ret < lb_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003757 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003758 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003759 my_name, "write same", lb_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003760
3761 /* Copy first sector to remaining blocks */
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003762 for (i = 1 ; i < num ; i++) {
3763 lbaa = lba + i;
3764 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003765 memmove(fsp + (block * lb_size), fs1p, lb_size);
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003766 }
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003767 if (scsi_debug_lbp())
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003768 map_region(sip, lba, num);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09003769 /* If ZBC zone then bump its write pointer */
3770 if (sdebug_dev_is_zoned(devip))
3771 zbc_inc_wp(devip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003772out:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003773 write_unlock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003774
3775 return 0;
3776}
3777
Douglas Gilbertfd321192016-04-25 12:16:33 -04003778static int resp_write_same_10(struct scsi_cmnd *scp,
3779 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003780{
3781 u8 *cmd = scp->cmnd;
3782 u32 lba;
3783 u16 num;
3784 u32 ei_lba = 0;
3785 bool unmap = false;
3786
3787 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003788 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003789 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3790 return check_condition_result;
3791 } else
3792 unmap = true;
3793 }
3794 lba = get_unaligned_be32(cmd + 2);
3795 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003796 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003797 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3798 return check_condition_result;
3799 }
3800 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3801}
3802
Douglas Gilbertfd321192016-04-25 12:16:33 -04003803static int resp_write_same_16(struct scsi_cmnd *scp,
3804 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003805{
3806 u8 *cmd = scp->cmnd;
3807 u64 lba;
3808 u32 num;
3809 u32 ei_lba = 0;
3810 bool unmap = false;
3811 bool ndob = false;
3812
3813 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003814 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003815 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3816 return check_condition_result;
3817 } else
3818 unmap = true;
3819 }
3820 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3821 ndob = true;
3822 lba = get_unaligned_be64(cmd + 2);
3823 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003824 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003825 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3826 return check_condition_result;
3827 }
3828 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3829}
3830
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003831/* Note the mode field is in the same position as the (lower) service action
3832 * field. For the Report supported operation codes command, SPC-4 suggests
3833 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003834static int resp_write_buffer(struct scsi_cmnd *scp,
3835 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003836{
3837 u8 *cmd = scp->cmnd;
3838 struct scsi_device *sdp = scp->device;
3839 struct sdebug_dev_info *dp;
3840 u8 mode;
3841
3842 mode = cmd[1] & 0x1f;
3843 switch (mode) {
3844 case 0x4: /* download microcode (MC) and activate (ACT) */
3845 /* set UAs on this device only */
3846 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3847 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3848 break;
3849 case 0x5: /* download MC, save and ACT */
3850 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3851 break;
3852 case 0x6: /* download MC with offsets and ACT */
3853 /* set UAs on most devices (LUs) in this target */
3854 list_for_each_entry(dp,
3855 &devip->sdbg_host->dev_info_list,
3856 dev_list)
3857 if (dp->target == sdp->id) {
3858 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3859 if (devip != dp)
3860 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3861 dp->uas_bm);
3862 }
3863 break;
3864 case 0x7: /* download MC with offsets, save, and ACT */
3865 /* set UA on all devices (LUs) in this target */
3866 list_for_each_entry(dp,
3867 &devip->sdbg_host->dev_info_list,
3868 dev_list)
3869 if (dp->target == sdp->id)
3870 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3871 dp->uas_bm);
3872 break;
3873 default:
3874 /* do nothing for this command for other mode values */
3875 break;
3876 }
3877 return 0;
3878}
3879
Douglas Gilbertfd321192016-04-25 12:16:33 -04003880static int resp_comp_write(struct scsi_cmnd *scp,
3881 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003882{
3883 u8 *cmd = scp->cmnd;
3884 u8 *arr;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003885 struct sdeb_store_info *sip = devip2sip(devip, true);
3886 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003887 u64 lba;
3888 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003889 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003890 u8 num;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003891 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003892 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003893
Douglas Gilbertd467d312014-11-26 12:33:48 -05003894 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003895 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3896 if (0 == num)
3897 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003898 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003899 (cmd[1] & 0xe0)) {
3900 mk_sense_invalid_opcode(scp);
3901 return check_condition_result;
3902 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003903 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3904 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003905 (cmd[1] & 0xe0) == 0)
3906 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3907 "to DIF device\n");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003908 ret = check_device_access_params(scp, lba, num, false);
3909 if (ret)
3910 return ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003911 dnum = 2 * num;
Kees Cook6396bb22018-06-12 14:03:40 -07003912 arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003913 if (NULL == arr) {
3914 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3915 INSUFF_RES_ASCQ);
3916 return check_condition_result;
3917 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003918
Douglas Gilbert67da4132020-04-21 11:14:20 -04003919 write_lock(macc_lckp);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003920
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003921 ret = do_dout_fetch(scp, dnum, arr);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003922 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003923 retval = DID_ERROR << 16;
3924 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003925 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003926 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3927 "indicated=%u, IO sent=%d bytes\n", my_name,
3928 dnum * lb_size, ret);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04003929 if (!comp_write_worker(sip, lba, num, arr, false)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003930 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003931 retval = check_condition_result;
3932 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003933 }
3934 if (scsi_debug_lbp())
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003935 map_region(sip, lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003936cleanup:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003937 write_unlock(macc_lckp);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003938 kfree(arr);
3939 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003940}
3941
Martin K. Petersen44d92692009-10-15 14:45:27 -04003942struct unmap_block_desc {
3943 __be64 lba;
3944 __be32 blocks;
3945 __be32 __reserved;
3946};
3947
Douglas Gilbertfd321192016-04-25 12:16:33 -04003948static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003949{
3950 unsigned char *buf;
3951 struct unmap_block_desc *desc;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04003952 struct sdeb_store_info *sip = devip2sip(devip, true);
3953 rwlock_t *macc_lckp = &sip->macc_lck;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003954 unsigned int i, payload_len, descriptors;
3955 int ret;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003956
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003957 if (!scsi_debug_lbp())
3958 return 0; /* fib and say its done */
3959 payload_len = get_unaligned_be16(scp->cmnd + 7);
3960 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003961
3962 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003963 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003964 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003965 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003966 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003967
Douglas Gilbertb333a812016-04-25 12:16:30 -04003968 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003969 if (!buf) {
3970 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3971 INSUFF_RES_ASCQ);
3972 return check_condition_result;
3973 }
3974
3975 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003976
3977 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3978 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3979
3980 desc = (void *)&buf[8];
3981
Douglas Gilbert67da4132020-04-21 11:14:20 -04003982 write_lock(macc_lckp);
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003983
Martin K. Petersen44d92692009-10-15 14:45:27 -04003984 for (i = 0 ; i < descriptors ; i++) {
3985 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3986 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3987
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003988 ret = check_device_access_params(scp, lba, num, true);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003989 if (ret)
3990 goto out;
3991
Douglas Gilbert87c715d2020-04-21 11:14:18 -04003992 unmap_region(sip, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003993 }
3994
3995 ret = 0;
3996
3997out:
Douglas Gilbert67da4132020-04-21 11:14:20 -04003998 write_unlock(macc_lckp);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003999 kfree(buf);
4000
4001 return ret;
4002}
4003
4004#define SDEBUG_GET_LBA_STATUS_LEN 32
4005
Douglas Gilbertfd321192016-04-25 12:16:33 -04004006static int resp_get_lba_status(struct scsi_cmnd *scp,
4007 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004008{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004009 u8 *cmd = scp->cmnd;
4010 u64 lba;
4011 u32 alloc_len, mapped, num;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004012 int ret;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04004013 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04004014
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004015 lba = get_unaligned_be64(cmd + 2);
4016 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004017
4018 if (alloc_len < 24)
4019 return 0;
4020
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05004021 ret = check_device_access_params(scp, lba, 1, false);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004022 if (ret)
4023 return ret;
4024
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004025 if (scsi_debug_lbp()) {
4026 struct sdeb_store_info *sip = devip2sip(devip, true);
4027
Douglas Gilbert87c715d2020-04-21 11:14:18 -04004028 mapped = map_state(sip, lba, &num);
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004029 } else {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004030 mapped = 1;
4031 /* following just in case virtual_gb changed */
4032 sdebug_capacity = get_sdebug_capacity();
4033 if (sdebug_capacity - lba <= 0xffffffff)
4034 num = sdebug_capacity - lba;
4035 else
4036 num = 0xffffffff;
4037 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04004038
4039 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004040 put_unaligned_be32(20, arr); /* Parameter Data Length */
4041 put_unaligned_be64(lba, arr + 8); /* LBA */
4042 put_unaligned_be32(num, arr + 16); /* Number of blocks */
4043 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04004044
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004045 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004046}
4047
Douglas Gilbert80c49562018-02-09 21:36:39 -05004048static int resp_sync_cache(struct scsi_cmnd *scp,
4049 struct sdebug_dev_info *devip)
4050{
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04004051 int res = 0;
Douglas Gilbert80c49562018-02-09 21:36:39 -05004052 u64 lba;
4053 u32 num_blocks;
4054 u8 *cmd = scp->cmnd;
4055
4056 if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
4057 lba = get_unaligned_be32(cmd + 2);
4058 num_blocks = get_unaligned_be16(cmd + 7);
4059 } else { /* SYNCHRONIZE_CACHE(16) */
4060 lba = get_unaligned_be64(cmd + 2);
4061 num_blocks = get_unaligned_be32(cmd + 10);
4062 }
4063 if (lba + num_blocks > sdebug_capacity) {
4064 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4065 return check_condition_result;
4066 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04004067 if (!write_since_sync || (cmd[1] & 0x2))
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04004068 res = SDEG_RES_IMMED_MASK;
4069 else /* delay if write_since_sync and IMMED clear */
4070 write_since_sync = false;
4071 return res;
Douglas Gilbert80c49562018-02-09 21:36:39 -05004072}
4073
Douglas Gilberted9f3e22020-04-21 11:14:22 -04004074/*
4075 * Assuming the LBA+num_blocks is not out-of-range, this function will return
4076 * CONDITION MET if the specified blocks will/have fitted in the cache, and
4077 * a GOOD status otherwise. Model a disk with a big cache and yield
4078 * CONDITION MET. Actually tries to bring range in main memory into the
4079 * cache associated with the CPU(s).
4080 */
4081static int resp_pre_fetch(struct scsi_cmnd *scp,
4082 struct sdebug_dev_info *devip)
4083{
4084 int res = 0;
4085 u64 lba;
4086 u64 block, rest = 0;
4087 u32 nblks;
4088 u8 *cmd = scp->cmnd;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004089 struct sdeb_store_info *sip = devip2sip(devip, true);
4090 rwlock_t *macc_lckp = &sip->macc_lck;
4091 u8 *fsp = sip->storep;
Douglas Gilberted9f3e22020-04-21 11:14:22 -04004092
4093 if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */
4094 lba = get_unaligned_be32(cmd + 2);
4095 nblks = get_unaligned_be16(cmd + 7);
4096 } else { /* PRE-FETCH(16) */
4097 lba = get_unaligned_be64(cmd + 2);
4098 nblks = get_unaligned_be32(cmd + 10);
4099 }
4100 if (lba + nblks > sdebug_capacity) {
4101 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4102 return check_condition_result;
4103 }
4104 if (!fsp)
4105 goto fini;
4106 /* PRE-FETCH spec says nothing about LBP or PI so skip them */
4107 block = do_div(lba, sdebug_store_sectors);
4108 if (block + nblks > sdebug_store_sectors)
4109 rest = block + nblks - sdebug_store_sectors;
4110
4111 /* Try to bring the PRE-FETCH range into CPU's cache */
4112 read_lock(macc_lckp);
4113 prefetch_range(fsp + (sdebug_sector_size * block),
4114 (nblks - rest) * sdebug_sector_size);
4115 if (rest)
4116 prefetch_range(fsp, rest * sdebug_sector_size);
4117 read_unlock(macc_lckp);
4118fini:
4119 if (cmd[1] & 0x2)
4120 res = SDEG_RES_IMMED_MASK;
4121 return res | condition_met_result;
4122}
4123
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004124#define RL_BUCKET_ELEMS 8
4125
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004126/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
4127 * (W-LUN), the normal Linux scanning logic does not associate it with a
4128 * device (e.g. /dev/sg7). The following magic will make that association:
4129 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
4130 * where <n> is a host number. If there are multiple targets in a host then
4131 * the above will associate a W-LUN to each target. To only get a W-LUN
4132 * for target 2, then use "echo '- 2 49409' > scan" .
4133 */
4134static int resp_report_luns(struct scsi_cmnd *scp,
4135 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02004137 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004138 unsigned int alloc_len;
4139 unsigned char select_report;
4140 u64 lun;
4141 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004142 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004143 unsigned int lun_cnt; /* normal LUN count (max: 256) */
4144 unsigned int wlun_cnt; /* report luns W-LUN count */
4145 unsigned int tlun_cnt; /* total LUN count */
4146 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004147 int k, j, n, res;
4148 unsigned int off_rsp = 0;
4149 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004151 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004152
4153 select_report = cmd[2];
4154 alloc_len = get_unaligned_be32(cmd + 6);
4155
4156 if (alloc_len < 4) {
4157 pr_err("alloc len too small %d\n", alloc_len);
4158 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 return check_condition_result;
4160 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004161
4162 switch (select_report) {
4163 case 0: /* all LUNs apart from W-LUNs */
4164 lun_cnt = sdebug_max_luns;
4165 wlun_cnt = 0;
4166 break;
4167 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004168 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004169 wlun_cnt = 1;
4170 break;
4171 case 2: /* all LUNs */
4172 lun_cnt = sdebug_max_luns;
4173 wlun_cnt = 1;
4174 break;
4175 case 0x10: /* only administrative LUs */
4176 case 0x11: /* see SPC-5 */
4177 case 0x12: /* only subsiduary LUs owned by referenced LU */
4178 default:
4179 pr_debug("select report invalid %d\n", select_report);
4180 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
4181 return check_condition_result;
4182 }
4183
4184 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004185 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004186
4187 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004188 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
4189 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004190 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
4191 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
4192
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004193 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004194 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004195 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
4196 memset(arr, 0, sizeof(arr));
4197 lun_p = (struct scsi_lun *)&arr[0];
4198 if (k == 0) {
4199 put_unaligned_be32(rlen, &arr[0]);
4200 ++lun_p;
4201 j = 1;
4202 }
4203 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
4204 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
4205 break;
4206 int_to_scsilun(lun++, lun_p);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04004207 if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
4208 lun_p->scsi_lun[0] |= 0x40;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04004209 }
4210 if (j < RL_BUCKET_ELEMS)
4211 break;
4212 n = j * sz_lun;
4213 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
4214 if (res)
4215 return res;
4216 off_rsp += n;
4217 }
4218 if (wlun_cnt) {
4219 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
4220 ++j;
4221 }
4222 if (j > 0)
4223 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004224 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225}
4226
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004227static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4228{
4229 bool is_bytchk3 = false;
4230 u8 bytchk;
4231 int ret, j;
4232 u32 vnum, a_num, off;
4233 const u32 lb_size = sdebug_sector_size;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004234 u64 lba;
4235 u8 *arr;
4236 u8 *cmd = scp->cmnd;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004237 struct sdeb_store_info *sip = devip2sip(devip, true);
4238 rwlock_t *macc_lckp = &sip->macc_lck;
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004239
4240 bytchk = (cmd[1] >> 1) & 0x3;
4241 if (bytchk == 0) {
4242 return 0; /* always claim internal verify okay */
4243 } else if (bytchk == 2) {
4244 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
4245 return check_condition_result;
4246 } else if (bytchk == 3) {
4247 is_bytchk3 = true; /* 1 block sent, compared repeatedly */
4248 }
4249 switch (cmd[0]) {
4250 case VERIFY_16:
4251 lba = get_unaligned_be64(cmd + 2);
4252 vnum = get_unaligned_be32(cmd + 10);
4253 break;
4254 case VERIFY: /* is VERIFY(10) */
4255 lba = get_unaligned_be32(cmd + 2);
4256 vnum = get_unaligned_be16(cmd + 7);
4257 break;
4258 default:
4259 mk_sense_invalid_opcode(scp);
4260 return check_condition_result;
4261 }
George Kennedy3344b582021-11-04 15:06:37 -05004262 if (vnum == 0)
4263 return 0; /* not an error */
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004264 a_num = is_bytchk3 ? 1 : vnum;
4265 /* Treat following check like one for read (i.e. no write) access */
4266 ret = check_device_access_params(scp, lba, a_num, false);
4267 if (ret)
4268 return ret;
4269
4270 arr = kcalloc(lb_size, vnum, GFP_ATOMIC);
4271 if (!arr) {
4272 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4273 INSUFF_RES_ASCQ);
4274 return check_condition_result;
4275 }
4276 /* Not changing store, so only need read access */
Douglas Gilbert67da4132020-04-21 11:14:20 -04004277 read_lock(macc_lckp);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004278
4279 ret = do_dout_fetch(scp, a_num, arr);
4280 if (ret == -1) {
4281 ret = DID_ERROR << 16;
4282 goto cleanup;
4283 } else if (sdebug_verbose && (ret < (a_num * lb_size))) {
4284 sdev_printk(KERN_INFO, scp->device,
4285 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
4286 my_name, __func__, a_num * lb_size, ret);
4287 }
4288 if (is_bytchk3) {
4289 for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
4290 memcpy(arr + off, arr, lb_size);
4291 }
4292 ret = 0;
4293 if (!comp_write_worker(sip, lba, vnum, arr, true)) {
4294 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
4295 ret = check_condition_result;
4296 goto cleanup;
4297 }
4298cleanup:
Douglas Gilbert67da4132020-04-21 11:14:20 -04004299 read_unlock(macc_lckp);
Douglas Gilbertc3e2fe92020-04-21 11:14:19 -04004300 kfree(arr);
4301 return ret;
4302}
4303
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004304#define RZONES_DESC_HD 64
4305
4306/* Report zones depending on start LBA nad reporting options */
4307static int resp_report_zones(struct scsi_cmnd *scp,
4308 struct sdebug_dev_info *devip)
4309{
4310 unsigned int i, max_zones, rep_max_zones, nrz = 0;
4311 int ret = 0;
4312 u32 alloc_len, rep_opts, rep_len;
4313 bool partial;
4314 u64 lba, zs_lba;
4315 u8 *arr = NULL, *desc;
4316 u8 *cmd = scp->cmnd;
4317 struct sdeb_zone_state *zsp;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004318 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004319 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4320
4321 if (!sdebug_dev_is_zoned(devip)) {
4322 mk_sense_invalid_opcode(scp);
4323 return check_condition_result;
4324 }
4325 zs_lba = get_unaligned_be64(cmd + 2);
4326 alloc_len = get_unaligned_be32(cmd + 10);
George Kennedy3344b582021-11-04 15:06:37 -05004327 if (alloc_len == 0)
4328 return 0; /* not an error */
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004329 rep_opts = cmd[14] & 0x3f;
4330 partial = cmd[14] & 0x80;
4331
4332 if (zs_lba >= sdebug_capacity) {
4333 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4334 return check_condition_result;
4335 }
4336
Damien Le Moal108e36f2020-05-07 11:35:26 +09004337 max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004338 rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
4339 max_zones);
4340
4341 arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC);
4342 if (!arr) {
4343 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
4344 INSUFF_RES_ASCQ);
4345 return check_condition_result;
4346 }
4347
4348 read_lock(macc_lckp);
4349
4350 desc = arr + 64;
4351 for (i = 0; i < max_zones; i++) {
4352 lba = zs_lba + devip->zsize * i;
4353 if (lba > sdebug_capacity)
4354 break;
4355 zsp = zbc_zone(devip, lba);
4356 switch (rep_opts) {
4357 case 0x00:
4358 /* All zones */
4359 break;
4360 case 0x01:
4361 /* Empty zones */
4362 if (zsp->z_cond != ZC1_EMPTY)
4363 continue;
4364 break;
4365 case 0x02:
4366 /* Implicit open zones */
4367 if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
4368 continue;
4369 break;
4370 case 0x03:
4371 /* Explicit open zones */
4372 if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
4373 continue;
4374 break;
4375 case 0x04:
4376 /* Closed zones */
4377 if (zsp->z_cond != ZC4_CLOSED)
4378 continue;
4379 break;
4380 case 0x05:
4381 /* Full zones */
4382 if (zsp->z_cond != ZC5_FULL)
4383 continue;
4384 break;
4385 case 0x06:
4386 case 0x07:
4387 case 0x10:
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004388 /*
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004389 * Read-only, offline, reset WP recommended are
4390 * not emulated: no zones to report;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004391 */
4392 continue;
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004393 case 0x11:
4394 /* non-seq-resource set */
4395 if (!zsp->z_non_seq_resource)
4396 continue;
4397 break;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004398 case 0x3f:
4399 /* Not write pointer (conventional) zones */
4400 if (!zbc_zone_is_conv(zsp))
4401 continue;
4402 break;
4403 default:
4404 mk_sense_buffer(scp, ILLEGAL_REQUEST,
4405 INVALID_FIELD_IN_CDB, 0);
4406 ret = check_condition_result;
4407 goto fini;
4408 }
4409
4410 if (nrz < rep_max_zones) {
4411 /* Fill zone descriptor */
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004412 desc[0] = zsp->z_type;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004413 desc[1] = zsp->z_cond << 4;
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004414 if (zsp->z_non_seq_resource)
4415 desc[1] |= 1 << 1;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004416 put_unaligned_be64((u64)zsp->z_size, desc + 8);
4417 put_unaligned_be64((u64)zsp->z_start, desc + 16);
4418 put_unaligned_be64((u64)zsp->z_wp, desc + 24);
4419 desc += 64;
4420 }
4421
4422 if (partial && nrz >= rep_max_zones)
4423 break;
4424
4425 nrz++;
4426 }
4427
4428 /* Report header */
4429 put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
4430 put_unaligned_be64(sdebug_capacity - 1, arr + 8);
4431
4432 rep_len = (unsigned long)desc - (unsigned long)arr;
4433 ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len));
4434
4435fini:
4436 read_unlock(macc_lckp);
4437 kfree(arr);
4438 return ret;
4439}
4440
4441/* Logic transplanted from tcmu-runner, file_zbc.c */
4442static void zbc_open_all(struct sdebug_dev_info *devip)
4443{
4444 struct sdeb_zone_state *zsp = &devip->zstate[0];
4445 unsigned int i;
4446
4447 for (i = 0; i < devip->nr_zones; i++, zsp++) {
4448 if (zsp->z_cond == ZC4_CLOSED)
4449 zbc_open_zone(devip, &devip->zstate[i], true);
4450 }
4451}
4452
4453static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4454{
4455 int res = 0;
4456 u64 z_id;
4457 enum sdebug_z_cond zc;
4458 u8 *cmd = scp->cmnd;
4459 struct sdeb_zone_state *zsp;
4460 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004461 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004462 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4463
4464 if (!sdebug_dev_is_zoned(devip)) {
4465 mk_sense_invalid_opcode(scp);
4466 return check_condition_result;
4467 }
4468
4469 write_lock(macc_lckp);
4470
4471 if (all) {
4472 /* Check if all closed zones can be open */
4473 if (devip->max_open &&
4474 devip->nr_exp_open + devip->nr_closed > devip->max_open) {
4475 mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4476 INSUFF_ZONE_ASCQ);
4477 res = check_condition_result;
4478 goto fini;
4479 }
4480 /* Open all closed zones */
4481 zbc_open_all(devip);
4482 goto fini;
4483 }
4484
4485 /* Open the specified zone */
4486 z_id = get_unaligned_be64(cmd + 2);
4487 if (z_id >= sdebug_capacity) {
4488 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4489 res = check_condition_result;
4490 goto fini;
4491 }
4492
4493 zsp = zbc_zone(devip, z_id);
4494 if (z_id != zsp->z_start) {
4495 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4496 res = check_condition_result;
4497 goto fini;
4498 }
4499 if (zbc_zone_is_conv(zsp)) {
4500 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4501 res = check_condition_result;
4502 goto fini;
4503 }
4504
4505 zc = zsp->z_cond;
4506 if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
4507 goto fini;
4508
4509 if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
4510 mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
4511 INSUFF_ZONE_ASCQ);
4512 res = check_condition_result;
4513 goto fini;
4514 }
4515
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004516 zbc_open_zone(devip, zsp, true);
4517fini:
4518 write_unlock(macc_lckp);
4519 return res;
4520}
4521
4522static void zbc_close_all(struct sdebug_dev_info *devip)
4523{
4524 unsigned int i;
4525
4526 for (i = 0; i < devip->nr_zones; i++)
4527 zbc_close_zone(devip, &devip->zstate[i]);
4528}
4529
4530static int resp_close_zone(struct scsi_cmnd *scp,
4531 struct sdebug_dev_info *devip)
4532{
4533 int res = 0;
4534 u64 z_id;
4535 u8 *cmd = scp->cmnd;
4536 struct sdeb_zone_state *zsp;
4537 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004538 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004539 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4540
4541 if (!sdebug_dev_is_zoned(devip)) {
4542 mk_sense_invalid_opcode(scp);
4543 return check_condition_result;
4544 }
4545
4546 write_lock(macc_lckp);
4547
4548 if (all) {
4549 zbc_close_all(devip);
4550 goto fini;
4551 }
4552
4553 /* Close specified zone */
4554 z_id = get_unaligned_be64(cmd + 2);
4555 if (z_id >= sdebug_capacity) {
4556 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4557 res = check_condition_result;
4558 goto fini;
4559 }
4560
4561 zsp = zbc_zone(devip, z_id);
4562 if (z_id != zsp->z_start) {
4563 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4564 res = check_condition_result;
4565 goto fini;
4566 }
4567 if (zbc_zone_is_conv(zsp)) {
4568 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4569 res = check_condition_result;
4570 goto fini;
4571 }
4572
4573 zbc_close_zone(devip, zsp);
4574fini:
4575 write_unlock(macc_lckp);
4576 return res;
4577}
4578
4579static void zbc_finish_zone(struct sdebug_dev_info *devip,
4580 struct sdeb_zone_state *zsp, bool empty)
4581{
4582 enum sdebug_z_cond zc = zsp->z_cond;
4583
4584 if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
4585 zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
4586 if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4587 zbc_close_zone(devip, zsp);
4588 if (zsp->z_cond == ZC4_CLOSED)
4589 devip->nr_closed--;
4590 zsp->z_wp = zsp->z_start + zsp->z_size;
4591 zsp->z_cond = ZC5_FULL;
4592 }
4593}
4594
4595static void zbc_finish_all(struct sdebug_dev_info *devip)
4596{
4597 unsigned int i;
4598
4599 for (i = 0; i < devip->nr_zones; i++)
4600 zbc_finish_zone(devip, &devip->zstate[i], false);
4601}
4602
4603static int resp_finish_zone(struct scsi_cmnd *scp,
4604 struct sdebug_dev_info *devip)
4605{
4606 struct sdeb_zone_state *zsp;
4607 int res = 0;
4608 u64 z_id;
4609 u8 *cmd = scp->cmnd;
4610 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004611 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004612 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4613
4614 if (!sdebug_dev_is_zoned(devip)) {
4615 mk_sense_invalid_opcode(scp);
4616 return check_condition_result;
4617 }
4618
4619 write_lock(macc_lckp);
4620
4621 if (all) {
4622 zbc_finish_all(devip);
4623 goto fini;
4624 }
4625
4626 /* Finish the specified zone */
4627 z_id = get_unaligned_be64(cmd + 2);
4628 if (z_id >= sdebug_capacity) {
4629 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4630 res = check_condition_result;
4631 goto fini;
4632 }
4633
4634 zsp = zbc_zone(devip, z_id);
4635 if (z_id != zsp->z_start) {
4636 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4637 res = check_condition_result;
4638 goto fini;
4639 }
4640 if (zbc_zone_is_conv(zsp)) {
4641 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4642 res = check_condition_result;
4643 goto fini;
4644 }
4645
4646 zbc_finish_zone(devip, zsp, true);
4647fini:
4648 write_unlock(macc_lckp);
4649 return res;
4650}
4651
4652static void zbc_rwp_zone(struct sdebug_dev_info *devip,
4653 struct sdeb_zone_state *zsp)
4654{
4655 enum sdebug_z_cond zc;
4656
4657 if (zbc_zone_is_conv(zsp))
4658 return;
4659
4660 zc = zsp->z_cond;
4661 if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
4662 zbc_close_zone(devip, zsp);
4663
4664 if (zsp->z_cond == ZC4_CLOSED)
4665 devip->nr_closed--;
4666
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004667 zsp->z_non_seq_resource = false;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004668 zsp->z_wp = zsp->z_start;
4669 zsp->z_cond = ZC1_EMPTY;
4670}
4671
4672static void zbc_rwp_all(struct sdebug_dev_info *devip)
4673{
4674 unsigned int i;
4675
4676 for (i = 0; i < devip->nr_zones; i++)
4677 zbc_rwp_zone(devip, &devip->zstate[i]);
4678}
4679
4680static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
4681{
4682 struct sdeb_zone_state *zsp;
4683 int res = 0;
4684 u64 z_id;
4685 u8 *cmd = scp->cmnd;
4686 bool all = cmd[14] & 0x01;
Douglas Gilbertb6ff8ca2020-05-12 21:39:43 -04004687 struct sdeb_store_info *sip = devip2sip(devip, false);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004688 rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
4689
4690 if (!sdebug_dev_is_zoned(devip)) {
4691 mk_sense_invalid_opcode(scp);
4692 return check_condition_result;
4693 }
4694
4695 write_lock(macc_lckp);
4696
4697 if (all) {
4698 zbc_rwp_all(devip);
4699 goto fini;
4700 }
4701
4702 z_id = get_unaligned_be64(cmd + 2);
4703 if (z_id >= sdebug_capacity) {
4704 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
4705 res = check_condition_result;
4706 goto fini;
4707 }
4708
4709 zsp = zbc_zone(devip, z_id);
4710 if (z_id != zsp->z_start) {
4711 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4712 res = check_condition_result;
4713 goto fini;
4714 }
4715 if (zbc_zone_is_conv(zsp)) {
4716 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
4717 res = check_condition_result;
4718 goto fini;
4719 }
4720
4721 zbc_rwp_zone(devip, zsp);
4722fini:
4723 write_unlock(macc_lckp);
4724 return res;
4725}
4726
Douglas Gilbertc4837392016-05-06 00:40:26 -04004727static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
4728{
John Garryc10fa552020-07-09 20:23:20 +08004729 u16 hwq;
Bart Van Asschea6e76e62021-08-09 16:03:44 -07004730 u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
Douglas Gilbertc4837392016-05-06 00:40:26 -04004731
John Garryf7c4cdc2020-08-19 23:20:33 +08004732 hwq = blk_mq_unique_tag_to_hwq(tag);
John Garryc10fa552020-07-09 20:23:20 +08004733
John Garryf7c4cdc2020-08-19 23:20:33 +08004734 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
4735 if (WARN_ON_ONCE(hwq >= submit_queues))
4736 hwq = 0;
John Garryc10fa552020-07-09 20:23:20 +08004737
Bart Van Assche458df782018-01-26 08:52:19 -08004738 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004739}
4740
John Garryc10fa552020-07-09 20:23:20 +08004741static u32 get_tag(struct scsi_cmnd *cmnd)
4742{
Bart Van Asschea6e76e62021-08-09 16:03:44 -07004743 return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd));
John Garryc10fa552020-07-09 20:23:20 +08004744}
4745
Douglas Gilbertc4837392016-05-06 00:40:26 -04004746/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004747static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748{
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004749 bool aborted = sd_dp->aborted;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004750 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004751 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004753 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004754 struct sdebug_queued_cmd *sqcp;
4755 struct scsi_cmnd *scp;
4756 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004758 if (unlikely(aborted))
4759 sd_dp->aborted = false;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004760 qc_idx = sd_dp->qc_idx;
4761 sqp = sdebug_q_arr + sd_dp->sqa_idx;
4762 if (sdebug_statistics) {
4763 atomic_inc(&sdebug_completions);
4764 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
4765 atomic_inc(&sdebug_miss_cpus);
4766 }
4767 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
4768 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 return;
4770 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004771 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05304772 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004773 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004774 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004775 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004776 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
John Garryc10fa552020-07-09 20:23:20 +08004777 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
4778 sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 return;
4780 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004781 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004782 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004783 atomic_dec(&devip->num_in_q);
4784 else
Tomas Winklerc12879702015-07-28 16:54:20 +03004785 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004786 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004787 retiring = 1;
4788
4789 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004790 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
4791 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03004792 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004793 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004795
4796 if (unlikely(retiring)) { /* user has reduced max_queue */
4797 int k, retval;
4798
4799 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004800 if (qc_idx >= retval) {
4801 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03004802 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004803 return;
4804 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004805 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004806 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004807 atomic_set(&retired_max_queue, 0);
4808 else
4809 atomic_set(&retired_max_queue, k + 1);
4810 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004811 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004812 if (unlikely(aborted)) {
4813 if (sdebug_verbose)
4814 pr_info("bypassing scsi_done() due to aborted cmd\n");
4815 return;
4816 }
Bart Van Assche6c2c7d62021-10-07 13:29:04 -07004817 scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818}
4819
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004820/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004821static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004822{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004823 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
4824 hrt);
4825 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004826 return HRTIMER_NORESTART;
4827}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828
Douglas Gilberta10bc122016-04-25 12:16:32 -04004829/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004830static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04004831{
4832 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
4833 ew.work);
4834 sdebug_q_cmd_complete(sd_dp);
4835}
4836
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004837static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02004838static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004839
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004840static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
4841{
4842 struct sdeb_zone_state *zsp;
4843 sector_t capacity = get_sdebug_capacity();
4844 sector_t zstart = 0;
4845 unsigned int i;
4846
4847 /*
Damien Le Moal98e0a682020-04-22 19:42:20 +09004848 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
4849 * a zone size allowing for at least 4 zones on the device. Otherwise,
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004850 * use the specified zone size checking that at least 2 zones can be
4851 * created for the device.
4852 */
Damien Le Moal98e0a682020-04-22 19:42:20 +09004853 if (!sdeb_zbc_zone_size_mb) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004854 devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
4855 >> ilog2(sdebug_sector_size);
4856 while (capacity < devip->zsize << 2 && devip->zsize >= 2)
4857 devip->zsize >>= 1;
4858 if (devip->zsize < 2) {
4859 pr_err("Device capacity too small\n");
4860 return -EINVAL;
4861 }
4862 } else {
Damien Le Moal108e36f2020-05-07 11:35:26 +09004863 if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
4864 pr_err("Zone size is not a power of 2\n");
4865 return -EINVAL;
4866 }
Damien Le Moal98e0a682020-04-22 19:42:20 +09004867 devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004868 >> ilog2(sdebug_sector_size);
4869 if (devip->zsize >= capacity) {
4870 pr_err("Zone size too large for device capacity\n");
4871 return -EINVAL;
4872 }
4873 }
4874
Damien Le Moal108e36f2020-05-07 11:35:26 +09004875 devip->zsize_shift = ilog2(devip->zsize);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004876 devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
4877
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09004878 if (sdeb_zbc_nr_conv >= devip->nr_zones) {
4879 pr_err("Number of conventional zones too large\n");
4880 return -EINVAL;
4881 }
4882 devip->nr_conv_zones = sdeb_zbc_nr_conv;
4883
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004884 if (devip->zmodel == BLK_ZONED_HM) {
4885 /* zbc_max_open_zones can be 0, meaning "not reported" */
4886 if (sdeb_zbc_max_open >= devip->nr_zones - 1)
4887 devip->max_open = (devip->nr_zones - 1) / 2;
4888 else
4889 devip->max_open = sdeb_zbc_max_open;
4890 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004891
4892 devip->zstate = kcalloc(devip->nr_zones,
4893 sizeof(struct sdeb_zone_state), GFP_KERNEL);
4894 if (!devip->zstate)
4895 return -ENOMEM;
4896
4897 for (i = 0; i < devip->nr_zones; i++) {
4898 zsp = &devip->zstate[i];
4899
4900 zsp->z_start = zstart;
4901
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09004902 if (i < devip->nr_conv_zones) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004903 zsp->z_type = ZBC_ZONE_TYPE_CNV;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004904 zsp->z_cond = ZBC_NOT_WRITE_POINTER;
4905 zsp->z_wp = (sector_t)-1;
4906 } else {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004907 if (devip->zmodel == BLK_ZONED_HM)
4908 zsp->z_type = ZBC_ZONE_TYPE_SWR;
4909 else
4910 zsp->z_type = ZBC_ZONE_TYPE_SWP;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004911 zsp->z_cond = ZC1_EMPTY;
4912 zsp->z_wp = zsp->z_start;
4913 }
4914
4915 if (zsp->z_start + devip->zsize < capacity)
4916 zsp->z_size = devip->zsize;
4917 else
4918 zsp->z_size = capacity - zsp->z_start;
4919
4920 zstart += zsp->z_size;
4921 }
4922
4923 return 0;
4924}
4925
Douglas Gilbertfd321192016-04-25 12:16:33 -04004926static struct sdebug_dev_info *sdebug_device_create(
4927 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004928{
4929 struct sdebug_dev_info *devip;
4930
4931 devip = kzalloc(sizeof(*devip), flags);
4932 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004933 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02004934 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004935 else if (sdebug_uuid_ctl == 2) {
4936 if (got_shared_uuid)
4937 devip->lu_name = shared_uuid;
4938 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02004939 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004940 got_shared_uuid = true;
4941 devip->lu_name = shared_uuid;
4942 }
4943 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004944 devip->sdbg_host = sdbg_host;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004945 if (sdeb_zbc_in_use) {
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004946 devip->zmodel = sdeb_zbc_model;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004947 if (sdebug_device_create_zones(devip)) {
4948 kfree(devip);
4949 return NULL;
4950 }
Damien Le Moal64e14ec2020-04-22 19:42:21 +09004951 } else {
4952 devip->zmodel = BLK_ZONED_NONE;
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09004953 }
4954 devip->sdbg_host = sdbg_host;
Douglas Gilbertfc136382020-07-24 11:55:31 -04004955 devip->create_ts = ktime_get_boottime();
4956 atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004957 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
4958 }
4959 return devip;
4960}
4961
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004962static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004964 struct sdebug_host_info *sdbg_host;
4965 struct sdebug_dev_info *open_devip = NULL;
4966 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004968 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
4969 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004970 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004972 }
Douglas Gilbertad0c7772020-08-21 00:22:49 -04004973
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
4975 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05004976 (devip->target == sdev->id) &&
4977 (devip->lun == sdev->lun))
4978 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 else {
4980 if ((!devip->used) && (!open_devip))
4981 open_devip = devip;
4982 }
4983 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004984 if (!open_devip) { /* try and make a new one */
4985 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
4986 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004987 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 return NULL;
4989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09004991
4992 open_devip->channel = sdev->channel;
4993 open_devip->target = sdev->id;
4994 open_devip->lun = sdev->lun;
4995 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004996 atomic_set(&open_devip->num_in_q, 0);
4997 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004998 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09004999 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000}
5001
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005002static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005004 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03005005 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005006 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005007 return 0;
5008}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005010static int scsi_debug_slave_configure(struct scsi_device *sdp)
5011{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005012 struct sdebug_dev_info *devip =
5013 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09005014
Douglas Gilbert773642d2016-04-25 12:16:28 -04005015 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03005016 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005017 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005018 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
5019 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
5020 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005021 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005022 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005023 return 1; /* no resources, will be marked offline */
5024 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01005025 sdp->hostdata = devip;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005026 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005027 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005028 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005029 return 0;
5030}
5031
5032static void scsi_debug_slave_destroy(struct scsi_device *sdp)
5033{
5034 struct sdebug_dev_info *devip =
5035 (struct sdebug_dev_info *)sdp->hostdata;
5036
Douglas Gilbert773642d2016-04-25 12:16:28 -04005037 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03005038 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005039 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
5040 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005041 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005042 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005043 sdp->hostdata = NULL;
5044 }
5045}
5046
Douglas Gilbert10bde982018-01-10 16:57:31 -05005047static void stop_qc_helper(struct sdebug_defer *sd_dp,
5048 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005049{
5050 if (!sd_dp)
5051 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005052 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005053 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005054 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005055 cancel_work_sync(&sd_dp->ew.work);
5056}
5057
Douglas Gilberta10bc122016-04-25 12:16:32 -04005058/* If @cmnd found deletes its timer or work queue and returns true; else
5059 returns false */
5060static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005061{
5062 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005063 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005064 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005065 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005066 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005067 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005068 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005069
Douglas Gilbertc4837392016-05-06 00:40:26 -04005070 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5071 spin_lock_irqsave(&sqp->qc_lock, iflags);
5072 qmax = sdebug_max_queue;
5073 r_qmax = atomic_read(&retired_max_queue);
5074 if (r_qmax > qmax)
5075 qmax = r_qmax;
5076 for (k = 0; k < qmax; ++k) {
5077 if (test_bit(k, sqp->in_use_bm)) {
5078 sqcp = &sqp->qc_arr[k];
5079 if (cmnd != sqcp->a_cmnd)
5080 continue;
5081 /* found */
5082 devip = (struct sdebug_dev_info *)
5083 cmnd->device->hostdata;
5084 if (devip)
5085 atomic_dec(&devip->num_in_q);
5086 sqcp->a_cmnd = NULL;
5087 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005088 if (sd_dp) {
5089 l_defer_t = sd_dp->defer_t;
5090 sd_dp->defer_t = SDEB_DEFER_NONE;
5091 } else
5092 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005093 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005094 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005095 clear_bit(k, sqp->in_use_bm);
5096 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005097 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005098 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005099 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005100 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04005101 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005102}
5103
Douglas Gilberta10bc122016-04-25 12:16:32 -04005104/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005105static void stop_all_queued(void)
5106{
5107 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005108 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005109 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005110 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005111 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005112 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005113 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005114
Douglas Gilbertc4837392016-05-06 00:40:26 -04005115 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5116 spin_lock_irqsave(&sqp->qc_lock, iflags);
5117 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5118 if (test_bit(k, sqp->in_use_bm)) {
5119 sqcp = &sqp->qc_arr[k];
5120 if (sqcp->a_cmnd == NULL)
5121 continue;
5122 devip = (struct sdebug_dev_info *)
5123 sqcp->a_cmnd->device->hostdata;
5124 if (devip)
5125 atomic_dec(&devip->num_in_q);
5126 sqcp->a_cmnd = NULL;
5127 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005128 if (sd_dp) {
5129 l_defer_t = sd_dp->defer_t;
5130 sd_dp->defer_t = SDEB_DEFER_NONE;
5131 } else
5132 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005133 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005134 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005135 clear_bit(k, sqp->in_use_bm);
5136 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005137 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005138 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005139 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141}
5142
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005143/* Free queued command memory on heap */
5144static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005146 int j, k;
5147 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005148 struct sdebug_queued_cmd *sqcp;
5149
Douglas Gilbertc4837392016-05-06 00:40:26 -04005150 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5151 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
5152 sqcp = &sqp->qc_arr[k];
5153 kfree(sqcp->sd_dp);
5154 sqcp->sd_dp = NULL;
5155 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157}
5158
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005159static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160{
Douglas Gilberta10bc122016-04-25 12:16:32 -04005161 bool ok;
5162
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005163 ++num_aborts;
5164 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04005165 ok = stop_queued_cmnd(SCpnt);
5166 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
5167 sdev_printk(KERN_INFO, SCpnt->device,
5168 "%s: command%s found\n", __func__,
5169 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005171 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172}
5173
John Pittman91d4c752018-02-09 21:12:43 -05005174static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005177 if (SCpnt && SCpnt->device) {
5178 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005179 struct sdebug_dev_info *devip =
5180 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005181
Douglas Gilbert773642d2016-04-25 12:16:28 -04005182 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005183 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005185 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 }
5187 return SUCCESS;
5188}
5189
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005190static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
5191{
5192 struct sdebug_host_info *sdbg_host;
5193 struct sdebug_dev_info *devip;
5194 struct scsi_device *sdp;
5195 struct Scsi_Host *hp;
5196 int k = 0;
5197
5198 ++num_target_resets;
5199 if (!SCpnt)
5200 goto lie;
5201 sdp = SCpnt->device;
5202 if (!sdp)
5203 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005204 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005205 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5206 hp = sdp->host;
5207 if (!hp)
5208 goto lie;
5209 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
5210 if (sdbg_host) {
5211 list_for_each_entry(devip,
5212 &sdbg_host->dev_info_list,
5213 dev_list)
5214 if (devip->target == sdp->id) {
5215 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5216 ++k;
5217 }
5218 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005219 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005220 sdev_printk(KERN_INFO, sdp,
5221 "%s: %d device(s) found in target\n", __func__, k);
5222lie:
5223 return SUCCESS;
5224}
5225
John Pittman91d4c752018-02-09 21:12:43 -05005226static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227{
5228 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005229 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005230 struct scsi_device *sdp;
5231 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005232 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005235 if (!(SCpnt && SCpnt->device))
5236 goto lie;
5237 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005238 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005239 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
5240 hp = sdp->host;
5241 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09005242 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005244 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05005245 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005246 dev_list) {
5247 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5248 ++k;
5249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 }
5251 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005252 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005253 sdev_printk(KERN_INFO, sdp,
5254 "%s: %d device(s) found in host\n", __func__, k);
5255lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 return SUCCESS;
5257}
5258
John Pittman91d4c752018-02-09 21:12:43 -05005259static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260{
John Pittman91d4c752018-02-09 21:12:43 -05005261 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005262 struct sdebug_dev_info *devip;
5263 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005266 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005267 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005268 spin_lock(&sdebug_host_list_lock);
5269 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005270 list_for_each_entry(devip, &sdbg_host->dev_info_list,
5271 dev_list) {
5272 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
5273 ++k;
5274 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005275 }
5276 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04005278 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005279 sdev_printk(KERN_INFO, SCpnt->device,
5280 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 return SUCCESS;
5282}
5283
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005284static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285{
Christoph Hellwig1442f762020-03-24 08:25:26 +01005286 struct msdos_partition *pp;
John Pittman979e0dc2020-09-02 17:14:33 -04005287 int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 int sectors_per_part, num_sectors, k;
5289 int heads_by_sects, start_sec, end_sec;
5290
5291 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005292 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005294 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
5295 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03005296 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 }
John Pittman8c657232020-09-02 17:14:34 -04005298 num_sectors = (int)get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04005300 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005302 starts[0] = sdebug_sectors_per;
John Pittman979e0dc2020-09-02 17:14:33 -04005303 max_part_secs = sectors_per_part;
5304 for (k = 1; k < sdebug_num_parts; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 starts[k] = ((k * sectors_per_part) / heads_by_sects)
5306 * heads_by_sects;
John Pittman979e0dc2020-09-02 17:14:33 -04005307 if (starts[k] - starts[k - 1] < max_part_secs)
5308 max_part_secs = starts[k] - starts[k - 1];
5309 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005310 starts[sdebug_num_parts] = num_sectors;
5311 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312
5313 ramp[510] = 0x55; /* magic partition markings */
5314 ramp[511] = 0xAA;
Christoph Hellwig1442f762020-03-24 08:25:26 +01005315 pp = (struct msdos_partition *)(ramp + 0x1be);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 for (k = 0; starts[k + 1]; ++k, ++pp) {
5317 start_sec = starts[k];
John Pittman979e0dc2020-09-02 17:14:33 -04005318 end_sec = starts[k] + max_part_secs - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 pp->boot_ind = 0;
5320
5321 pp->cyl = start_sec / heads_by_sects;
5322 pp->head = (start_sec - (pp->cyl * heads_by_sects))
5323 / sdebug_sectors_per;
5324 pp->sector = (start_sec % sdebug_sectors_per) + 1;
5325
5326 pp->end_cyl = end_sec / heads_by_sects;
5327 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
5328 / sdebug_sectors_per;
5329 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
5330
Akinobu Mita150c3542013-08-26 22:08:40 +09005331 pp->start_sect = cpu_to_le32(start_sec);
5332 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 pp->sys_ind = 0x83; /* plain Linux partition */
5334 }
5335}
5336
Douglas Gilbertc4837392016-05-06 00:40:26 -04005337static void block_unblock_all_queues(bool block)
5338{
5339 int j;
5340 struct sdebug_queue *sqp;
5341
5342 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
5343 atomic_set(&sqp->blocked, (int)block);
5344}
5345
5346/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
5347 * commands will be processed normally before triggers occur.
5348 */
5349static void tweak_cmnd_count(void)
5350{
5351 int count, modulo;
5352
5353 modulo = abs(sdebug_every_nth);
5354 if (modulo < 2)
5355 return;
5356 block_unblock_all_queues(true);
5357 count = atomic_read(&sdebug_cmnd_count);
5358 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
5359 block_unblock_all_queues(false);
5360}
5361
5362static void clear_queue_stats(void)
5363{
5364 atomic_set(&sdebug_cmnd_count, 0);
5365 atomic_set(&sdebug_completions, 0);
5366 atomic_set(&sdebug_miss_cpus, 0);
5367 atomic_set(&sdebug_a_tsf, 0);
5368}
5369
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005370static bool inject_on_this_cmd(void)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005371{
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005372 if (sdebug_every_nth == 0)
5373 return false;
5374 return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005375}
5376
Douglas Gilberta2aede92020-04-21 11:14:21 -04005377#define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */
5378
Douglas Gilbertc4837392016-05-06 00:40:26 -04005379/* Complete the processing of the thread that queued a SCSI command to this
5380 * driver. It either completes the command by calling cmnd_done() or
5381 * schedules a hr timer or work queue then returns 0. Returns
5382 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
5383 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04005384static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Martin Wilckf66b8512018-02-14 11:05:57 +01005385 int scsi_result,
5386 int (*pfp)(struct scsi_cmnd *,
5387 struct sdebug_dev_info *),
5388 int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389{
Douglas Gilberta2aede92020-04-21 11:14:21 -04005390 bool new_sd_dp;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005391 bool inject = false;
Christoph Hellwig6ce913f2021-10-12 13:12:21 +02005392 bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005393 int k, num_in_q, qdepth;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005394 unsigned long iflags;
5395 u64 ns_from_boot = 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005396 struct sdebug_queue *sqp;
5397 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03005398 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005399 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005401 if (unlikely(devip == NULL)) {
5402 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005403 scsi_result = DID_NO_CONNECT << 16;
5404 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03005406 sdp = cmnd->device;
5407
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005408 if (delta_jiff == 0)
5409 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410
Douglas Gilbertc4837392016-05-06 00:40:26 -04005411 sqp = get_queue(cmnd);
5412 spin_lock_irqsave(&sqp->qc_lock, iflags);
5413 if (unlikely(atomic_read(&sqp->blocked))) {
5414 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5415 return SCSI_MLQUEUE_HOST_BUSY;
5416 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005417 num_in_q = atomic_read(&devip->num_in_q);
5418 qdepth = cmnd->device->queue_depth;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005419 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005420 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005421 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005422 goto respond_in_thread;
5423 } else
5424 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005425 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005426 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
5427 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005428 if ((num_in_q == (qdepth - 1)) &&
5429 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04005430 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005431 atomic_set(&sdebug_a_tsf, 0);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005432 inject = true;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005433 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005435 }
5436
Douglas Gilbertc4837392016-05-06 00:40:26 -04005437 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005438 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005439 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005440 if (scsi_result)
5441 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005442 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005443 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005444 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005445 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005446 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04005447 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005448 (scsi_result ? "status: TASK SET FULL" :
5449 "report: host busy"));
5450 if (scsi_result)
5451 goto respond_in_thread;
5452 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005453 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 }
Douglas Gilbert74595c02020-07-02 10:53:55 -04005455 set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005456 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005457 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005458 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005459 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04005460 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005461 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05305462
Douglas Gilbert74595c02020-07-02 10:53:55 -04005463 if (!sd_dp) {
Douglas Gilbert10bde982018-01-10 16:57:31 -05005464 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
Douglas Gilbert74595c02020-07-02 10:53:55 -04005465 if (!sd_dp) {
5466 atomic_dec(&devip->num_in_q);
5467 clear_bit(k, sqp->in_use_bm);
Douglas Gilbert10bde982018-01-10 16:57:31 -05005468 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilbert74595c02020-07-02 10:53:55 -04005469 }
Douglas Gilberta2aede92020-04-21 11:14:21 -04005470 new_sd_dp = true;
5471 } else {
5472 new_sd_dp = false;
Douglas Gilbert10bde982018-01-10 16:57:31 -05005473 }
Martin Wilckf66b8512018-02-14 11:05:57 +01005474
John Garryc10fa552020-07-09 20:23:20 +08005475 /* Set the hostwide tag */
5476 if (sdebug_host_max_queue)
5477 sd_dp->hc_idx = get_tag(cmnd);
5478
Christoph Hellwig6ce913f2021-10-12 13:12:21 +02005479 if (polled)
Douglas Gilberta2aede92020-04-21 11:14:21 -04005480 ns_from_boot = ktime_get_boottime_ns();
5481
5482 /* one of the resp_*() response functions is called here */
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005483 cmnd->result = pfp ? pfp(cmnd, devip) : 0;
Martin Wilckf66b8512018-02-14 11:05:57 +01005484 if (cmnd->result & SDEG_RES_IMMED_MASK) {
Martin Wilckf66b8512018-02-14 11:05:57 +01005485 cmnd->result &= ~SDEG_RES_IMMED_MASK;
5486 delta_jiff = ndelay = 0;
5487 }
5488 if (cmnd->result == 0 && scsi_result != 0)
5489 cmnd->result = scsi_result;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005490 if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
5491 if (atomic_read(&sdeb_inject_pending)) {
5492 mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
5493 atomic_set(&sdeb_inject_pending, 0);
5494 cmnd->result = check_condition_result;
5495 }
5496 }
Martin Wilckf66b8512018-02-14 11:05:57 +01005497
5498 if (unlikely(sdebug_verbose && cmnd->result))
5499 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
5500 __func__, cmnd->result);
5501
Douglas Gilbert10bde982018-01-10 16:57:31 -05005502 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04005503 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005504
Douglas Gilbertb333a812016-04-25 12:16:30 -04005505 if (delta_jiff > 0) {
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005506 u64 ns = jiffies_to_nsecs(delta_jiff);
5507
5508 if (sdebug_random && ns < U32_MAX) {
5509 ns = prandom_u32_max((u32)ns);
5510 } else if (sdebug_random) {
5511 ns >>= 12; /* scale to 4 usec precision */
5512 if (ns < U32_MAX) /* over 4 hours max */
5513 ns = prandom_u32_max((u32)ns);
5514 ns <<= 12;
5515 }
5516 kt = ns_to_ktime(ns);
5517 } else { /* ndelay has a 4.2 second max */
5518 kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
5519 (u32)ndelay;
Douglas Gilberta2aede92020-04-21 11:14:21 -04005520 if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
5521 u64 d = ktime_get_boottime_ns() - ns_from_boot;
5522
5523 if (kt <= d) { /* elapsed duration >= kt */
Douglas Gilbert223f91b2020-08-13 11:57:38 -04005524 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005525 sqcp->a_cmnd = NULL;
5526 atomic_dec(&devip->num_in_q);
5527 clear_bit(k, sqp->in_use_bm);
Douglas Gilbert223f91b2020-08-13 11:57:38 -04005528 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005529 if (new_sd_dp)
5530 kfree(sd_dp);
5531 /* call scsi_done() from this thread */
Bart Van Assche6c2c7d62021-10-07 13:29:04 -07005532 scsi_done(cmnd);
Douglas Gilberta2aede92020-04-21 11:14:21 -04005533 return 0;
5534 }
5535 /* otherwise reduce kt by elapsed time */
5536 kt -= d;
5537 }
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005538 }
Christoph Hellwig6ce913f2021-10-12 13:12:21 +02005539 if (polled) {
Douglas Gilbert771f7122021-03-03 20:41:07 -05005540 sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305541 spin_lock_irqsave(&sqp->qc_lock, iflags);
5542 if (!sd_dp->init_poll) {
5543 sd_dp->init_poll = true;
5544 sqcp->sd_dp = sd_dp;
5545 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5546 sd_dp->qc_idx = k;
5547 }
5548 sd_dp->defer_t = SDEB_DEFER_POLL;
5549 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5550 } else {
5551 if (!sd_dp->init_hrt) {
5552 sd_dp->init_hrt = true;
5553 sqcp->sd_dp = sd_dp;
5554 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
5555 HRTIMER_MODE_REL_PINNED);
5556 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
5557 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5558 sd_dp->qc_idx = k;
5559 }
5560 sd_dp->defer_t = SDEB_DEFER_HRT;
5561 /* schedule the invocation of scsi_done() for a later time */
5562 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005563 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005564 if (sdebug_statistics)
5565 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbertc4837392016-05-06 00:40:26 -04005566 } else { /* jdelay < 0, use work queue */
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005567 if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
5568 atomic_read(&sdeb_inject_pending)))
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005569 sd_dp->aborted = true;
Christoph Hellwig6ce913f2021-10-12 13:12:21 +02005570 if (polled) {
Douglas Gilbert771f7122021-03-03 20:41:07 -05005571 sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305572 spin_lock_irqsave(&sqp->qc_lock, iflags);
5573 if (!sd_dp->init_poll) {
5574 sd_dp->init_poll = true;
5575 sqcp->sd_dp = sd_dp;
5576 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5577 sd_dp->qc_idx = k;
5578 }
5579 sd_dp->defer_t = SDEB_DEFER_POLL;
5580 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
5581 } else {
5582 if (!sd_dp->init_wq) {
5583 sd_dp->init_wq = true;
5584 sqcp->sd_dp = sd_dp;
5585 sd_dp->sqa_idx = sqp - sdebug_q_arr;
5586 sd_dp->qc_idx = k;
5587 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
5588 }
5589 sd_dp->defer_t = SDEB_DEFER_WQ;
5590 schedule_work(&sd_dp->ew.work);
5591 }
5592 if (sdebug_statistics)
5593 sd_dp->issuing_cpu = raw_smp_processor_id();
5594 if (unlikely(sd_dp->aborted)) {
Bart Van Asschea6e76e62021-08-09 16:03:44 -07005595 sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
5596 scsi_cmd_to_rq(cmnd)->tag);
5597 blk_abort_request(scsi_cmd_to_rq(cmnd));
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005598 atomic_set(&sdeb_inject_pending, 0);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305599 sd_dp->aborted = false;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005600 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005601 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04005602 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
5603 sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
5604 num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005605 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005606
5607respond_in_thread: /* call back to mid-layer using invocation thread */
Martin Wilckf66b8512018-02-14 11:05:57 +01005608 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
5609 cmnd->result &= ~SDEG_RES_IMMED_MASK;
5610 if (cmnd->result == 0 && scsi_result != 0)
5611 cmnd->result = scsi_result;
Bart Van Assche6c2c7d62021-10-07 13:29:04 -07005612 scsi_done(cmnd);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02005613 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005615
Douglas Gilbert23183912006-09-16 20:30:47 -04005616/* Note: The following macros create attribute files in the
5617 /sys/module/scsi_debug/parameters directory. Unfortunately this
5618 driver is unaware of a change and cannot trigger auxiliary actions
5619 as it can when the corresponding attribute in the
5620 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
5621 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005622module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
5623module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005624module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005625module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04005626module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005627module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
5628module_param_named(dif, sdebug_dif, int, S_IRUGO);
5629module_param_named(dix, sdebug_dix, int, S_IRUGO);
5630module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
5631module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
5632module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
5633module_param_named(guard, sdebug_guard, uint, S_IRUGO);
5634module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
John Garryc10fa552020-07-09 20:23:20 +08005635module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005636module_param_string(inq_product, sdebug_inq_product_id,
Douglas Gilbert5d807072020-04-21 11:14:23 -04005637 sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005638module_param_string(inq_rev, sdebug_inq_product_rev,
Douglas Gilbert5d807072020-04-21 11:14:23 -04005639 sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
5640module_param_string(inq_vendor, sdebug_inq_vendor_id,
5641 sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
5642module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005643module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
5644module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
5645module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005646module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04005647module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005648module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
5649module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005650module_param_named(medium_error_count, sdebug_medium_error_count, int,
5651 S_IRUGO | S_IWUSR);
5652module_param_named(medium_error_start, sdebug_medium_error_start, int,
5653 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005654module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
5655module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
5656module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
5657module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
5658module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
5659module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005660module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005661module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005662module_param_named(per_host_store, sdebug_per_host_store, bool,
5663 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005664module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
5665module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005666module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005667module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
5668module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
5669module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005670module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005671module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005672module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05305673module_param_named(poll_queues, poll_queues, int, S_IRUGO);
Douglas Gilbertfc136382020-07-24 11:55:31 -04005674module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005675module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
5676module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
5677module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
5678module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005679module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert5d807072020-04-21 11:14:23 -04005680module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005681module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04005682 S_IRUGO | S_IWUSR);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05005683module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005684module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005685 S_IRUGO | S_IWUSR);
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09005686module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
Damien Le Moal380603a2020-04-22 19:42:18 +09005687module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09005688module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
Damien Le Moal98e0a682020-04-22 19:42:20 +09005689module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690
5691MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
5692MODULE_DESCRIPTION("SCSI debug adapter driver");
5693MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005694MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695
Douglas Gilbert5d807072020-04-21 11:14:23 -04005696MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005697MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005698MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09005699MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005700MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005701MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005702MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
5703MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005704MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07005705MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04005706MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005707MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04005708MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
John Garryc10fa552020-07-09 20:23:20 +08005709MODULE_PARM_DESC(host_max_queue,
5710 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02005711MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005712MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
5713 SDEBUG_VERSION "\")");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005714MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
5715MODULE_PARM_DESC(lbprz,
5716 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005717MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
5718MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
5719MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
5720MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertad0c7772020-08-21 00:22:49 -04005721MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04005722MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005723MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05005724MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005725MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005726MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005727MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005728MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005730MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05005731MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01005732MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Douglas Gilbert5d807072020-04-21 11:14:23 -04005733MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
5734MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
5735MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04005736MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04005738MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
Martin Pittd9867882012-09-06 12:04:33 +02005739MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005740MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005741MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005742MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005743MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005744MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Douglas Gilbertfc136382020-07-24 11:55:31 -04005745MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005746MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
5747MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04005748MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
5749MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005750MODULE_PARM_DESC(uuid_ctl,
5751 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005752MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005753MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05005754MODULE_PARM_DESC(wp, "Write Protect (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005755MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09005756MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
Damien Le Moal380603a2020-04-22 19:42:18 +09005757MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
Damien Le Moalaa8fecf2020-04-22 19:42:19 +09005758MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
Damien Le Moal98e0a682020-04-22 19:42:20 +09005759MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005761#define SDEBUG_INFO_LEN 256
5762static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763
John Pittman91d4c752018-02-09 21:12:43 -05005764static const char *scsi_debug_info(struct Scsi_Host *shp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005766 int k;
5767
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005768 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
5769 my_name, SDEBUG_VERSION, sdebug_version_date);
5770 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005771 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04005772 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
5773 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
5774 sdebug_dev_size_mb, sdebug_opts, submit_queues,
5775 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 return sdebug_info;
5777}
5778
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005779/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04005780static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
5781 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782{
Al Viroc8ed5552013-03-31 01:46:06 -04005783 char arr[16];
5784 int opts;
5785 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786
Al Viroc8ed5552013-03-31 01:46:06 -04005787 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
5788 return -EACCES;
5789 memcpy(arr, buffer, minLen);
5790 arr[minLen] = '\0';
5791 if (1 != sscanf(arr, "%d", &opts))
5792 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005793 sdebug_opts = opts;
5794 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5795 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
5796 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005797 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04005798 return length;
5799}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005801/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
5802 * same for each scsi_debug host (if more than one). Some of the counters
5803 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04005804static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
5805{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005806 int f, j, l;
5807 struct sdebug_queue *sqp;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005808 struct sdebug_host_info *sdhp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005809
Douglas Gilbertc4837392016-05-06 00:40:26 -04005810 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
5811 SDEBUG_VERSION, sdebug_version_date);
5812 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
5813 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
5814 sdebug_opts, sdebug_every_nth);
5815 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
5816 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
5817 sdebug_sector_size, "bytes");
5818 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
5819 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
5820 num_aborts);
5821 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
5822 num_dev_resets, num_target_resets, num_bus_resets,
5823 num_host_resets);
5824 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
5825 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08005826 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
5827 sdebug_statistics);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305828 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005829 atomic_read(&sdebug_cmnd_count),
5830 atomic_read(&sdebug_completions),
5831 "miss_cpus", atomic_read(&sdebug_miss_cpus),
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05305832 atomic_read(&sdebug_a_tsf),
5833 atomic_read(&sdeb_mq_poll_count));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005834
Douglas Gilbertc4837392016-05-06 00:40:26 -04005835 seq_printf(m, "submit_queues=%d\n", submit_queues);
5836 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
5837 seq_printf(m, " queue %d:\n", j);
5838 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
5839 if (f != sdebug_max_queue) {
5840 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
5841 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
5842 "first,last bits", f, l);
5843 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005844 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04005845
5846 seq_printf(m, "this host_no=%d\n", host->host_no);
5847 if (!xa_empty(per_store_ap)) {
5848 bool niu;
5849 int idx;
5850 unsigned long l_idx;
5851 struct sdeb_store_info *sip;
5852
5853 seq_puts(m, "\nhost list:\n");
5854 j = 0;
5855 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
5856 idx = sdhp->si_idx;
5857 seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j,
5858 sdhp->shost->host_no, idx);
5859 ++j;
5860 }
5861 seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
5862 sdeb_most_recent_idx);
5863 j = 0;
5864 xa_for_each(per_store_ap, l_idx, sip) {
5865 niu = xa_get_mark(per_store_ap, l_idx,
5866 SDEB_XA_NOT_IN_USE);
5867 idx = (int)l_idx;
5868 seq_printf(m, " %d: idx=%d%s\n", j, idx,
5869 (niu ? " not_in_use" : ""));
5870 ++j;
5871 }
5872 }
Al Viroc8ed5552013-03-31 01:46:06 -04005873 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874}
5875
Akinobu Mita82069372013-10-14 22:48:04 +09005876static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877{
Douglas Gilbertc2206092016-04-25 12:16:31 -04005878 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879}
Douglas Gilbertc4837392016-05-06 00:40:26 -04005880/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
5881 * of delay is jiffies.
5882 */
Akinobu Mita82069372013-10-14 22:48:04 +09005883static ssize_t delay_store(struct device_driver *ddp, const char *buf,
5884 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885{
Douglas Gilbertc2206092016-04-25 12:16:31 -04005886 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005888 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005889 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04005890 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005891 int j, k;
5892 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005893
Douglas Gilbertc4837392016-05-06 00:40:26 -04005894 block_unblock_all_queues(true);
5895 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5896 ++j, ++sqp) {
5897 k = find_first_bit(sqp->in_use_bm,
5898 sdebug_max_queue);
5899 if (k != sdebug_max_queue) {
5900 res = -EBUSY; /* queued commands */
5901 break;
5902 }
5903 }
5904 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04005905 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005906 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005907 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005908 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005910 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 }
5912 return -EINVAL;
5913}
Akinobu Mita82069372013-10-14 22:48:04 +09005914static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005916static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
5917{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005918 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005919}
5920/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04005921/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005922static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04005923 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005924{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005925 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005926
5927 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04005928 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005929 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005930 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005931 int j, k;
5932 struct sdebug_queue *sqp;
5933
5934 block_unblock_all_queues(true);
5935 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
5936 ++j, ++sqp) {
5937 k = find_first_bit(sqp->in_use_bm,
5938 sdebug_max_queue);
5939 if (k != sdebug_max_queue) {
5940 res = -EBUSY; /* queued commands */
5941 break;
5942 }
5943 }
5944 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005945 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04005946 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
5947 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005948 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005949 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005950 }
5951 return res;
5952 }
5953 return -EINVAL;
5954}
5955static DRIVER_ATTR_RW(ndelay);
5956
Akinobu Mita82069372013-10-14 22:48:04 +09005957static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005959 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960}
5961
Akinobu Mita82069372013-10-14 22:48:04 +09005962static ssize_t opts_store(struct device_driver *ddp, const char *buf,
5963 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005965 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966 char work[20];
5967
Douglas Gilbert9a051012017-12-23 12:48:10 -05005968 if (sscanf(buf, "%10s", work) == 1) {
5969 if (strncasecmp(work, "0x", 2) == 0) {
5970 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 goto opts_done;
5972 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005973 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974 goto opts_done;
5975 }
5976 }
5977 return -EINVAL;
5978opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005979 sdebug_opts = opts;
5980 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
5981 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005982 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983 return count;
5984}
Akinobu Mita82069372013-10-14 22:48:04 +09005985static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
Akinobu Mita82069372013-10-14 22:48:04 +09005987static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005989 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990}
Akinobu Mita82069372013-10-14 22:48:04 +09005991static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
5992 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005994 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09005996 /* Cannot change from or to TYPE_ZBC with sysfs */
5997 if (sdebug_ptype == TYPE_ZBC)
5998 return -EINVAL;
5999
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006001 if (n == TYPE_ZBC)
6002 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006003 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004 return count;
6005 }
6006 return -EINVAL;
6007}
Akinobu Mita82069372013-10-14 22:48:04 +09006008static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006009
Akinobu Mita82069372013-10-14 22:48:04 +09006010static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006012 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013}
Akinobu Mita82069372013-10-14 22:48:04 +09006014static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
6015 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006017 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018
6019 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006020 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006021 return count;
6022 }
6023 return -EINVAL;
6024}
Akinobu Mita82069372013-10-14 22:48:04 +09006025static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026
Akinobu Mita82069372013-10-14 22:48:04 +09006027static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04006028{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006029 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04006030}
Akinobu Mita82069372013-10-14 22:48:04 +09006031static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
6032 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04006033{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006034 int n, idx;
Douglas Gilbert23183912006-09-16 20:30:47 -04006035
6036 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006037 bool want_store = (n == 0);
6038 struct sdebug_host_info *sdhp;
6039
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006040 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04006041 sdebug_fake_rw = (sdebug_fake_rw > 0);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006042 if (sdebug_fake_rw == n)
6043 return count; /* not transitioning so do nothing */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006044
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006045 if (want_store) { /* 1 --> 0 transition, set up store */
6046 if (sdeb_first_idx < 0) {
6047 idx = sdebug_add_store();
6048 if (idx < 0)
6049 return idx;
6050 } else {
6051 idx = sdeb_first_idx;
6052 xa_clear_mark(per_store_ap, idx,
6053 SDEB_XA_NOT_IN_USE);
6054 }
6055 /* make all hosts use same store */
6056 list_for_each_entry(sdhp, &sdebug_host_list,
6057 host_list) {
6058 if (sdhp->si_idx != idx) {
6059 xa_set_mark(per_store_ap, sdhp->si_idx,
6060 SDEB_XA_NOT_IN_USE);
6061 sdhp->si_idx = idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006062 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006063 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006064 sdeb_most_recent_idx = idx;
6065 } else { /* 0 --> 1 transition is trigger for shrink */
6066 sdebug_erase_all_stores(true /* apart from first */);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006067 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006068 sdebug_fake_rw = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04006069 return count;
6070 }
6071 return -EINVAL;
6072}
Akinobu Mita82069372013-10-14 22:48:04 +09006073static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04006074
Akinobu Mita82069372013-10-14 22:48:04 +09006075static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006076{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006077 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006078}
Akinobu Mita82069372013-10-14 22:48:04 +09006079static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
6080 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006081{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006082 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006083
6084 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006085 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006086 return count;
6087 }
6088 return -EINVAL;
6089}
Akinobu Mita82069372013-10-14 22:48:04 +09006090static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006091
Akinobu Mita82069372013-10-14 22:48:04 +09006092static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006094 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006095}
Akinobu Mita82069372013-10-14 22:48:04 +09006096static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
6097 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006099 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100
6101 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006102 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 sdebug_max_tgts_luns();
6104 return count;
6105 }
6106 return -EINVAL;
6107}
Akinobu Mita82069372013-10-14 22:48:04 +09006108static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109
Akinobu Mita82069372013-10-14 22:48:04 +09006110static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006112 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113}
Akinobu Mita82069372013-10-14 22:48:04 +09006114static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006116static ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
6117{
6118 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
6119}
6120
6121static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
6122 size_t count)
6123{
6124 bool v;
6125
6126 if (kstrtobool(buf, &v))
6127 return -EINVAL;
6128
6129 sdebug_per_host_store = v;
6130 return count;
6131}
6132static DRIVER_ATTR_RW(per_host_store);
6133
Akinobu Mita82069372013-10-14 22:48:04 +09006134static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006136 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137}
Akinobu Mita82069372013-10-14 22:48:04 +09006138static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139
Akinobu Mita82069372013-10-14 22:48:04 +09006140static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006142 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143}
Akinobu Mita82069372013-10-14 22:48:04 +09006144static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
6145 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006147 int nth;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006148 char work[20];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006149
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006150 if (sscanf(buf, "%10s", work) == 1) {
6151 if (strncasecmp(work, "0x", 2) == 0) {
6152 if (kstrtoint(work + 2, 16, &nth) == 0)
6153 goto every_nth_done;
6154 } else {
6155 if (kstrtoint(work, 10, &nth) == 0)
6156 goto every_nth_done;
Douglas Gilbertc4837392016-05-06 00:40:26 -04006157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158 }
6159 return -EINVAL;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04006160
6161every_nth_done:
6162 sdebug_every_nth = nth;
6163 if (nth && !sdebug_statistics) {
6164 pr_info("every_nth needs statistics=1, set it\n");
6165 sdebug_statistics = true;
6166 }
6167 tweak_cmnd_count();
6168 return count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006169}
Akinobu Mita82069372013-10-14 22:48:04 +09006170static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006172static ssize_t lun_format_show(struct device_driver *ddp, char *buf)
6173{
6174 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
6175}
6176static ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
6177 size_t count)
6178{
6179 int n;
6180 bool changed;
6181
6182 if (kstrtoint(buf, 0, &n))
6183 return -EINVAL;
6184 if (n >= 0) {
6185 if (n > (int)SAM_LUN_AM_FLAT) {
6186 pr_warn("only LUN address methods 0 and 1 are supported\n");
6187 return -EINVAL;
6188 }
6189 changed = ((int)sdebug_lun_am != n);
6190 sdebug_lun_am = n;
6191 if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */
6192 struct sdebug_host_info *sdhp;
6193 struct sdebug_dev_info *dp;
6194
6195 spin_lock(&sdebug_host_list_lock);
6196 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
6197 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
6198 set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
6199 }
6200 }
6201 spin_unlock(&sdebug_host_list_lock);
6202 }
6203 return count;
6204 }
6205 return -EINVAL;
6206}
6207static DRIVER_ATTR_RW(lun_format);
6208
Akinobu Mita82069372013-10-14 22:48:04 +09006209static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006211 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212}
Akinobu Mita82069372013-10-14 22:48:04 +09006213static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
6214 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006216 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05006217 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218
6219 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006220 if (n > 256) {
6221 pr_warn("max_luns can be no more than 256\n");
6222 return -EINVAL;
6223 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006224 changed = (sdebug_max_luns != n);
6225 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04006227 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05006228 struct sdebug_host_info *sdhp;
6229 struct sdebug_dev_info *dp;
6230
6231 spin_lock(&sdebug_host_list_lock);
6232 list_for_each_entry(sdhp, &sdebug_host_list,
6233 host_list) {
6234 list_for_each_entry(dp, &sdhp->dev_info_list,
6235 dev_list) {
6236 set_bit(SDEBUG_UA_LUNS_CHANGED,
6237 dp->uas_bm);
6238 }
6239 }
6240 spin_unlock(&sdebug_host_list_lock);
6241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242 return count;
6243 }
6244 return -EINVAL;
6245}
Akinobu Mita82069372013-10-14 22:48:04 +09006246static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247
Akinobu Mita82069372013-10-14 22:48:04 +09006248static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006249{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006250 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006251}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006252/* N.B. max_queue can be changed while there are queued commands. In flight
6253 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09006254static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
6255 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006256{
Douglas Gilbertc4837392016-05-06 00:40:26 -04006257 int j, n, k, a;
6258 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006259
6260 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
John Garryc10fa552020-07-09 20:23:20 +08006261 (n <= SDEBUG_CANQUEUE) &&
6262 (sdebug_host_max_queue == 0)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04006263 block_unblock_all_queues(true);
6264 k = 0;
6265 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
6266 ++j, ++sqp) {
6267 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
6268 if (a > k)
6269 k = a;
6270 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006271 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04006272 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006273 atomic_set(&retired_max_queue, 0);
6274 else if (k >= n)
6275 atomic_set(&retired_max_queue, k + 1);
6276 else
6277 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04006278 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006279 return count;
6280 }
6281 return -EINVAL;
6282}
Akinobu Mita82069372013-10-14 22:48:04 +09006283static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006284
John Garryc10fa552020-07-09 20:23:20 +08006285static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
6286{
6287 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
6288}
6289
6290/*
6291 * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
6292 * in range [0, sdebug_host_max_queue), we can't change it.
6293 */
6294static DRIVER_ATTR_RO(host_max_queue);
6295
Akinobu Mita82069372013-10-14 22:48:04 +09006296static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006297{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006298 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006299}
Akinobu Mita82069372013-10-14 22:48:04 +09006300static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04006301
Akinobu Mita82069372013-10-14 22:48:04 +09006302static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006304 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305}
Akinobu Mita82069372013-10-14 22:48:04 +09006306static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307
Akinobu Mita82069372013-10-14 22:48:04 +09006308static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006309{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006310 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006311}
Akinobu Mita82069372013-10-14 22:48:04 +09006312static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
6313 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006314{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006315 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006316 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006317
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006318 /* Ignore capacity change for ZBC drives for now */
6319 if (sdeb_zbc_in_use)
6320 return -ENOTSUPP;
6321
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006322 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006323 changed = (sdebug_virtual_gb != n);
6324 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006325 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006326 if (changed) {
6327 struct sdebug_host_info *sdhp;
6328 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006329
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05006330 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006331 list_for_each_entry(sdhp, &sdebug_host_list,
6332 host_list) {
6333 list_for_each_entry(dp, &sdhp->dev_info_list,
6334 dev_list) {
6335 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
6336 dp->uas_bm);
6337 }
6338 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05006339 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05006340 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006341 return count;
6342 }
6343 return -EINVAL;
6344}
Akinobu Mita82069372013-10-14 22:48:04 +09006345static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04006346
Akinobu Mita82069372013-10-14 22:48:04 +09006347static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006349 /* absolute number of hosts currently active is what is shown */
6350 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351}
6352
Akinobu Mita82069372013-10-14 22:48:04 +09006353static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
6354 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006356 bool found;
6357 unsigned long idx;
6358 struct sdeb_store_info *sip;
6359 bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09006360 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09006362 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006363 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 if (delta_hosts > 0) {
6365 do {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006366 found = false;
6367 if (want_phs) {
6368 xa_for_each_marked(per_store_ap, idx, sip,
6369 SDEB_XA_NOT_IN_USE) {
6370 sdeb_most_recent_idx = (int)idx;
6371 found = true;
6372 break;
6373 }
6374 if (found) /* re-use case */
6375 sdebug_add_host_helper((int)idx);
6376 else
6377 sdebug_do_add_host(true);
6378 } else {
6379 sdebug_do_add_host(false);
6380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381 } while (--delta_hosts);
6382 } else if (delta_hosts < 0) {
6383 do {
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006384 sdebug_do_remove_host(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385 } while (++delta_hosts);
6386 }
6387 return count;
6388}
Akinobu Mita82069372013-10-14 22:48:04 +09006389static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390
Akinobu Mita82069372013-10-14 22:48:04 +09006391static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04006392{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006393 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04006394}
Akinobu Mita82069372013-10-14 22:48:04 +09006395static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
6396 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04006397{
6398 int n;
6399
6400 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006401 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04006402 return count;
6403 }
6404 return -EINVAL;
6405}
Akinobu Mita82069372013-10-14 22:48:04 +09006406static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04006407
Douglas Gilbertc4837392016-05-06 00:40:26 -04006408static ssize_t statistics_show(struct device_driver *ddp, char *buf)
6409{
6410 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
6411}
6412static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
6413 size_t count)
6414{
6415 int n;
6416
6417 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
6418 if (n > 0)
6419 sdebug_statistics = true;
6420 else {
6421 clear_queue_stats();
6422 sdebug_statistics = false;
6423 }
6424 return count;
6425 }
6426 return -EINVAL;
6427}
6428static DRIVER_ATTR_RW(statistics);
6429
Akinobu Mita82069372013-10-14 22:48:04 +09006430static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006431{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006432 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006433}
Akinobu Mita82069372013-10-14 22:48:04 +09006434static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006435
Douglas Gilbertc4837392016-05-06 00:40:26 -04006436static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
6437{
6438 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
6439}
6440static DRIVER_ATTR_RO(submit_queues);
6441
Akinobu Mita82069372013-10-14 22:48:04 +09006442static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006443{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006444 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006445}
Akinobu Mita82069372013-10-14 22:48:04 +09006446static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006447
Akinobu Mita82069372013-10-14 22:48:04 +09006448static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006449{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006450 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006451}
Akinobu Mita82069372013-10-14 22:48:04 +09006452static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006453
Akinobu Mita82069372013-10-14 22:48:04 +09006454static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006455{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006456 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006457}
Akinobu Mita82069372013-10-14 22:48:04 +09006458static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006459
Akinobu Mita82069372013-10-14 22:48:04 +09006460static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006461{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006462 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006463}
Akinobu Mita82069372013-10-14 22:48:04 +09006464static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006465
Akinobu Mita82069372013-10-14 22:48:04 +09006466static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04006467{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006468 ssize_t count = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006469
Martin K. Petersen5b94e232011-03-08 02:08:11 -05006470 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04006471 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
6472 sdebug_store_sectors);
6473
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006474 if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
6475 struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
6476
6477 if (sip)
6478 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
6479 (int)map_size, sip->map_storep);
6480 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04006481 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08006482 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04006483
6484 return count;
6485}
Akinobu Mita82069372013-10-14 22:48:04 +09006486static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04006487
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04006488static ssize_t random_show(struct device_driver *ddp, char *buf)
6489{
6490 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
6491}
6492
6493static ssize_t random_store(struct device_driver *ddp, const char *buf,
6494 size_t count)
6495{
6496 bool v;
6497
6498 if (kstrtobool(buf, &v))
6499 return -EINVAL;
6500
6501 sdebug_random = v;
6502 return count;
6503}
6504static DRIVER_ATTR_RW(random);
6505
Akinobu Mita82069372013-10-14 22:48:04 +09006506static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02006507{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006508 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02006509}
Akinobu Mita82069372013-10-14 22:48:04 +09006510static ssize_t removable_store(struct device_driver *ddp, const char *buf,
6511 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02006512{
6513 int n;
6514
6515 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006516 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02006517 return count;
6518 }
6519 return -EINVAL;
6520}
Akinobu Mita82069372013-10-14 22:48:04 +09006521static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02006522
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006523static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
6524{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006525 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006526}
Douglas Gilbert185dd232016-04-25 12:16:29 -04006527/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006528static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
6529 size_t count)
6530{
Douglas Gilbert185dd232016-04-25 12:16:29 -04006531 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006532
6533 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04006534 sdebug_host_lock = (n > 0);
6535 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006536 }
6537 return -EINVAL;
6538}
6539static DRIVER_ATTR_RW(host_lock);
6540
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006541static ssize_t strict_show(struct device_driver *ddp, char *buf)
6542{
Douglas Gilbert773642d2016-04-25 12:16:28 -04006543 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006544}
6545static ssize_t strict_store(struct device_driver *ddp, const char *buf,
6546 size_t count)
6547{
6548 int n;
6549
6550 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006551 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006552 return count;
6553 }
6554 return -EINVAL;
6555}
6556static DRIVER_ATTR_RW(strict);
6557
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04006558static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
6559{
6560 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
6561}
6562static DRIVER_ATTR_RO(uuid_ctl);
6563
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05006564static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
6565{
6566 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
6567}
6568static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
6569 size_t count)
6570{
6571 int ret, n;
6572
6573 ret = kstrtoint(buf, 0, &n);
6574 if (ret)
6575 return ret;
6576 sdebug_cdb_len = n;
6577 all_config_cdb_len();
6578 return count;
6579}
6580static DRIVER_ATTR_RW(cdb_len);
6581
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006582static const char * const zbc_model_strs_a[] = {
6583 [BLK_ZONED_NONE] = "none",
6584 [BLK_ZONED_HA] = "host-aware",
6585 [BLK_ZONED_HM] = "host-managed",
6586};
6587
6588static const char * const zbc_model_strs_b[] = {
6589 [BLK_ZONED_NONE] = "no",
6590 [BLK_ZONED_HA] = "aware",
6591 [BLK_ZONED_HM] = "managed",
6592};
6593
6594static const char * const zbc_model_strs_c[] = {
6595 [BLK_ZONED_NONE] = "0",
6596 [BLK_ZONED_HA] = "1",
6597 [BLK_ZONED_HM] = "2",
6598};
6599
6600static int sdeb_zbc_model_str(const char *cp)
6601{
6602 int res = sysfs_match_string(zbc_model_strs_a, cp);
6603
6604 if (res < 0) {
6605 res = sysfs_match_string(zbc_model_strs_b, cp);
6606 if (res < 0) {
6607 res = sysfs_match_string(zbc_model_strs_c, cp);
Dan Carpenter47742bd2020-05-09 13:04:08 +03006608 if (res < 0)
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006609 return -EINVAL;
6610 }
6611 }
6612 return res;
6613}
6614
6615static ssize_t zbc_show(struct device_driver *ddp, char *buf)
6616{
6617 return scnprintf(buf, PAGE_SIZE, "%s\n",
6618 zbc_model_strs_a[sdeb_zbc_model]);
6619}
6620static DRIVER_ATTR_RO(zbc);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006621
Douglas Gilbertfc136382020-07-24 11:55:31 -04006622static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
6623{
6624 return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
6625}
6626static DRIVER_ATTR_RO(tur_ms_to_ready);
6627
Akinobu Mita82069372013-10-14 22:48:04 +09006628/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04006629 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
6630 files (over those found in the /sys/module/scsi_debug/parameters
6631 directory) is that auxiliary actions can be triggered when an attribute
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006632 is changed. For example see: add_host_store() above.
Douglas Gilbert23183912006-09-16 20:30:47 -04006633 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006634
Akinobu Mita82069372013-10-14 22:48:04 +09006635static struct attribute *sdebug_drv_attrs[] = {
6636 &driver_attr_delay.attr,
6637 &driver_attr_opts.attr,
6638 &driver_attr_ptype.attr,
6639 &driver_attr_dsense.attr,
6640 &driver_attr_fake_rw.attr,
John Garryc10fa552020-07-09 20:23:20 +08006641 &driver_attr_host_max_queue.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006642 &driver_attr_no_lun_0.attr,
6643 &driver_attr_num_tgts.attr,
6644 &driver_attr_dev_size_mb.attr,
6645 &driver_attr_num_parts.attr,
6646 &driver_attr_every_nth.attr,
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006647 &driver_attr_lun_format.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006648 &driver_attr_max_luns.attr,
6649 &driver_attr_max_queue.attr,
6650 &driver_attr_no_uld.attr,
6651 &driver_attr_scsi_level.attr,
6652 &driver_attr_virtual_gb.attr,
6653 &driver_attr_add_host.attr,
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006654 &driver_attr_per_host_store.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006655 &driver_attr_vpd_use_hostno.attr,
6656 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04006657 &driver_attr_statistics.attr,
6658 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006659 &driver_attr_dix.attr,
6660 &driver_attr_dif.attr,
6661 &driver_attr_guard.attr,
6662 &driver_attr_ato.attr,
6663 &driver_attr_map.attr,
Douglas Gilbert0c4bc912020-04-21 11:14:17 -04006664 &driver_attr_random.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006665 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006666 &driver_attr_host_lock.attr,
6667 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05006668 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04006669 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05006670 &driver_attr_cdb_len.attr,
Douglas Gilbertfc136382020-07-24 11:55:31 -04006671 &driver_attr_tur_ms_to_ready.attr,
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006672 &driver_attr_zbc.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09006673 NULL,
6674};
6675ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676
Akinobu Mita11ddcec2014-02-26 22:56:59 +09006677static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09006678
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679static int __init scsi_debug_init(void)
6680{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006681 bool want_store = (sdebug_fake_rw == 0);
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09006682 unsigned long sz;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006683 int k, ret, hosts_to_add;
6684 int idx = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006686 ramdisk_lck_a[0] = &atomic_rw;
6687 ramdisk_lck_a[1] = &atomic_rw2;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006688 atomic_set(&retired_max_queue, 0);
6689
Douglas Gilbert773642d2016-04-25 12:16:28 -04006690 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006691 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04006692 sdebug_ndelay = 0;
6693 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04006694 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04006695
Douglas Gilbert773642d2016-04-25 12:16:28 -04006696 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006697 case 512:
6698 case 1024:
6699 case 2048:
6700 case 4096:
6701 break;
6702 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04006703 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04006704 return -EINVAL;
6705 }
6706
Douglas Gilbert773642d2016-04-25 12:16:28 -04006707 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02006708 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04006709 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02006710 case T10_PI_TYPE1_PROTECTION:
6711 case T10_PI_TYPE2_PROTECTION:
6712 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04006713 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006714 break;
6715
6716 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03006717 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006718 return -EINVAL;
6719 }
6720
Maurizio Lombardiaa5334c2019-11-15 17:37:27 +01006721 if (sdebug_num_tgts < 0) {
6722 pr_err("num_tgts must be >= 0\n");
6723 return -EINVAL;
6724 }
6725
Douglas Gilbert773642d2016-04-25 12:16:28 -04006726 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006727 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006728 return -EINVAL;
6729 }
6730
Douglas Gilbert773642d2016-04-25 12:16:28 -04006731 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006732 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05006733 return -EINVAL;
6734 }
6735
Douglas Gilbert773642d2016-04-25 12:16:28 -04006736 if (sdebug_physblk_exp > 15) {
6737 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006738 return -EINVAL;
6739 }
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006740
6741 sdebug_lun_am = sdebug_lun_am_i;
6742 if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
6743 pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
6744 sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
6745 }
6746
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006747 if (sdebug_max_luns > 256) {
Douglas Gilbertad0c7772020-08-21 00:22:49 -04006748 if (sdebug_max_luns > 16384) {
6749 pr_warn("max_luns can be no more than 16384, use default\n");
6750 sdebug_max_luns = DEF_MAX_LUNS;
6751 }
6752 sdebug_lun_am = SAM_LUN_AM_FLAT;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04006753 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006754
Douglas Gilbert773642d2016-04-25 12:16:28 -04006755 if (sdebug_lowest_aligned > 0x3fff) {
6756 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04006757 return -EINVAL;
6758 }
6759
Douglas Gilbertc4837392016-05-06 00:40:26 -04006760 if (submit_queues < 1) {
6761 pr_err("submit_queues must be 1 or more\n");
6762 return -EINVAL;
6763 }
John Garryc87bf242020-07-09 20:23:19 +08006764
6765 if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
6766 pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
6767 return -EINVAL;
6768 }
6769
John Garryc10fa552020-07-09 20:23:20 +08006770 if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
6771 (sdebug_host_max_queue < 0)) {
6772 pr_err("host_max_queue must be in range [0 %d]\n",
6773 SDEBUG_CANQUEUE);
6774 return -EINVAL;
6775 }
6776
6777 if (sdebug_host_max_queue &&
6778 (sdebug_max_queue != sdebug_host_max_queue)) {
6779 sdebug_max_queue = sdebug_host_max_queue;
6780 pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
6781 sdebug_max_queue);
6782 }
6783
Douglas Gilbertc4837392016-05-06 00:40:26 -04006784 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
6785 GFP_KERNEL);
6786 if (sdebug_q_arr == NULL)
6787 return -ENOMEM;
6788 for (k = 0; k < submit_queues; ++k)
6789 spin_lock_init(&sdebug_q_arr[k].qc_lock);
6790
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006791 /*
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006792 * check for host managed zoned block device specified with
6793 * ptype=0x14 or zbc=XXX.
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006794 */
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006795 if (sdebug_ptype == TYPE_ZBC) {
6796 sdeb_zbc_model = BLK_ZONED_HM;
6797 } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
6798 k = sdeb_zbc_model_str(sdeb_zbc_model_s);
6799 if (k < 0) {
6800 ret = k;
Dinghao Liu3b01d7e2020-12-26 14:15:03 +08006801 goto free_q_arr;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006802 }
6803 sdeb_zbc_model = k;
6804 switch (sdeb_zbc_model) {
6805 case BLK_ZONED_NONE:
Damien Le Moal64e14ec2020-04-22 19:42:21 +09006806 case BLK_ZONED_HA:
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006807 sdebug_ptype = TYPE_DISK;
6808 break;
6809 case BLK_ZONED_HM:
6810 sdebug_ptype = TYPE_ZBC;
6811 break;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006812 default:
6813 pr_err("Invalid ZBC model\n");
Dinghao Liu3b01d7e2020-12-26 14:15:03 +08006814 ret = -EINVAL;
6815 goto free_q_arr;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006816 }
6817 }
6818 if (sdeb_zbc_model != BLK_ZONED_NONE) {
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006819 sdeb_zbc_in_use = true;
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006820 if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
6821 sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
6822 }
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09006823
Douglas Gilbert9267e0e2020-04-22 19:42:17 +09006824 if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
6825 sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006826 if (sdebug_dev_size_mb < 1)
6827 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
6828 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
6829 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09006830 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831
6832 /* play around with geometry, don't waste too much on track 0 */
6833 sdebug_heads = 8;
6834 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006835 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006836 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006837 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02006838 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
6840 (sdebug_sectors_per * sdebug_heads);
6841 if (sdebug_cylinders_per >= 1024) {
6842 /* other LLDs do this; implies >= 1GB ram disk ... */
6843 sdebug_heads = 255;
6844 sdebug_sectors_per = 63;
6845 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
6846 (sdebug_sectors_per * sdebug_heads);
6847 }
Martin K. Petersen5b94e232011-03-08 02:08:11 -05006848 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04006849 sdebug_unmap_max_blocks =
6850 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04006851
Douglas Gilbert773642d2016-04-25 12:16:28 -04006852 sdebug_unmap_max_desc =
6853 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04006854
Douglas Gilbert773642d2016-04-25 12:16:28 -04006855 sdebug_unmap_granularity =
6856 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04006857
Douglas Gilbert773642d2016-04-25 12:16:28 -04006858 if (sdebug_unmap_alignment &&
6859 sdebug_unmap_granularity <=
6860 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006861 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04006862 ret = -EINVAL;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006863 goto free_q_arr;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006864 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006865 }
6866 xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
6867 if (want_store) {
6868 idx = sdebug_add_store();
6869 if (idx < 0) {
6870 ret = idx;
6871 goto free_q_arr;
Martin K. Petersen44d92692009-10-15 14:45:27 -04006872 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04006873 }
6874
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006875 pseudo_primary = root_device_register("pseudo_0");
6876 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006877 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006878 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006879 goto free_vm;
6880 }
6881 ret = bus_register(&pseudo_lld_bus);
6882 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006883 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006884 goto dev_unreg;
6885 }
6886 ret = driver_register(&sdebug_driverfs_driver);
6887 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03006888 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006889 goto bus_unreg;
6890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006891
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006892 hosts_to_add = sdebug_add_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04006893 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006894
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006895 for (k = 0; k < hosts_to_add; k++) {
6896 if (want_store && k == 0) {
6897 ret = sdebug_add_host_helper(idx);
6898 if (ret < 0) {
6899 pr_err("add_host_helper k=%d, error=%d\n",
6900 k, -ret);
6901 break;
6902 }
6903 } else {
6904 ret = sdebug_do_add_host(want_store &&
6905 sdebug_per_host_store);
6906 if (ret < 0) {
6907 pr_err("add_host k=%d error=%d\n", k, -ret);
6908 break;
6909 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05006910 }
6911 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04006912 if (sdebug_verbose)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006913 pr_info("built %d host(s)\n", sdebug_num_hosts);
Tomas Winklerc12879702015-07-28 16:54:20 +03006914
Linus Torvalds1da177e2005-04-16 15:20:36 -07006915 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006916
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006917bus_unreg:
6918 bus_unregister(&pseudo_lld_bus);
6919dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006920 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006921free_vm:
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006922 sdebug_erase_store(idx, NULL);
Douglas Gilbertc4837392016-05-06 00:40:26 -04006923free_q_arr:
6924 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07006925 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006926}
6927
6928static void __exit scsi_debug_exit(void)
6929{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006930 int k = sdebug_num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006931
6932 stop_all_queued();
6933 for (; k; k--)
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006934 sdebug_do_remove_host(true);
Luis Henriques52ab9762018-06-18 17:08:03 +01006935 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006936 driver_unregister(&sdebug_driverfs_driver);
6937 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07006938 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006939
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006940 sdebug_erase_all_stores(false);
6941 xa_destroy(per_store_ap);
Maurizio Lombardif852c592021-02-08 12:17:34 +01006942 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943}
6944
6945device_initcall(scsi_debug_init);
6946module_exit(scsi_debug_exit);
6947
John Pittman91d4c752018-02-09 21:12:43 -05006948static void sdebug_release_adapter(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006949{
Douglas Gilbert9a051012017-12-23 12:48:10 -05006950 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006951
6952 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05006953 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006954}
6955
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006956/* idx must be valid, if sip is NULL then it will be obtained using idx */
6957static void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006958{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04006959 if (idx < 0)
6960 return;
6961 if (!sip) {
6962 if (xa_empty(per_store_ap))
6963 return;
6964 sip = xa_load(per_store_ap, idx);
6965 if (!sip)
6966 return;
6967 }
6968 vfree(sip->map_storep);
6969 vfree(sip->dif_storep);
6970 vfree(sip->storep);
6971 xa_erase(per_store_ap, idx);
6972 kfree(sip);
6973}
6974
6975/* Assume apart_from_first==false only in shutdown case. */
6976static void sdebug_erase_all_stores(bool apart_from_first)
6977{
6978 unsigned long idx;
6979 struct sdeb_store_info *sip = NULL;
6980
6981 xa_for_each(per_store_ap, idx, sip) {
6982 if (apart_from_first)
6983 apart_from_first = false;
6984 else
6985 sdebug_erase_store(idx, sip);
6986 }
6987 if (apart_from_first)
6988 sdeb_most_recent_idx = sdeb_first_idx;
6989}
6990
6991/*
6992 * Returns store xarray new element index (idx) if >=0 else negated errno.
6993 * Limit the number of stores to 65536.
6994 */
6995static int sdebug_add_store(void)
6996{
6997 int res;
6998 u32 n_idx;
6999 unsigned long iflags;
7000 unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
7001 struct sdeb_store_info *sip = NULL;
7002 struct xa_limit xal = { .max = 1 << 16, .min = 0 };
7003
7004 sip = kzalloc(sizeof(*sip), GFP_KERNEL);
7005 if (!sip)
7006 return -ENOMEM;
7007
7008 xa_lock_irqsave(per_store_ap, iflags);
7009 res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
7010 if (unlikely(res < 0)) {
7011 xa_unlock_irqrestore(per_store_ap, iflags);
7012 kfree(sip);
7013 pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
7014 return res;
7015 }
7016 sdeb_most_recent_idx = n_idx;
7017 if (sdeb_first_idx < 0)
7018 sdeb_first_idx = n_idx;
7019 xa_unlock_irqrestore(per_store_ap, iflags);
7020
7021 res = -ENOMEM;
7022 sip->storep = vzalloc(sz);
7023 if (!sip->storep) {
7024 pr_err("user data oom\n");
7025 goto err;
7026 }
7027 if (sdebug_num_parts > 0)
7028 sdebug_build_parts(sip->storep, sz);
7029
7030 /* DIF/DIX: what T10 calls Protection Information (PI) */
7031 if (sdebug_dix) {
7032 int dif_size;
7033
7034 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
7035 sip->dif_storep = vmalloc(dif_size);
7036
7037 pr_info("dif_storep %u bytes @ %pK\n", dif_size,
7038 sip->dif_storep);
7039
7040 if (!sip->dif_storep) {
7041 pr_err("DIX oom\n");
7042 goto err;
7043 }
7044 memset(sip->dif_storep, 0xff, dif_size);
7045 }
7046 /* Logical Block Provisioning */
7047 if (scsi_debug_lbp()) {
7048 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
7049 sip->map_storep = vmalloc(array_size(sizeof(long),
7050 BITS_TO_LONGS(map_size)));
7051
7052 pr_info("%lu provisioning blocks\n", map_size);
7053
7054 if (!sip->map_storep) {
7055 pr_err("LBP map oom\n");
7056 goto err;
7057 }
7058
7059 bitmap_zero(sip->map_storep, map_size);
7060
7061 /* Map first 1KB for partition table */
7062 if (sdebug_num_parts)
7063 map_region(sip, 0, 2);
7064 }
7065
7066 rwlock_init(&sip->macc_lck);
7067 return (int)n_idx;
7068err:
7069 sdebug_erase_store((int)n_idx, sip);
7070 pr_warn("%s: failed, errno=%d\n", __func__, -res);
7071 return res;
7072}
7073
7074static int sdebug_add_host_helper(int per_host_idx)
7075{
7076 int k, devs_per_host, idx;
7077 int error = -ENOMEM;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007078 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007079 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007080
Douglas Gilbert9a051012017-12-23 12:48:10 -05007081 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007082 if (!sdbg_host)
Douglas Gilbert9a051012017-12-23 12:48:10 -05007083 return -ENOMEM;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007084 idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
7085 if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
7086 xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
7087 sdbg_host->si_idx = idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088
Douglas Gilbert9a051012017-12-23 12:48:10 -05007089 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090
Douglas Gilbert773642d2016-04-25 12:16:28 -04007091 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007092 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09007093 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007094 if (!sdbg_devinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007097
Douglas Gilbert9a051012017-12-23 12:48:10 -05007098 spin_lock(&sdebug_host_list_lock);
7099 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
7100 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101
Douglas Gilbert9a051012017-12-23 12:48:10 -05007102 sdbg_host->dev.bus = &pseudo_lld_bus;
7103 sdbg_host->dev.parent = pseudo_primary;
7104 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007105 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007106
Douglas Gilbert9a051012017-12-23 12:48:10 -05007107 error = device_register(&sdbg_host->dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007108 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007109 goto clean;
7110
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007111 ++sdebug_num_hosts;
7112 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113
7114clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007115 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
7116 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117 list_del(&sdbg_devinfo->dev_list);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09007118 kfree(sdbg_devinfo->zstate);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007119 kfree(sdbg_devinfo);
7120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007121 kfree(sdbg_host);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007122 pr_warn("%s: failed, errno=%d\n", __func__, -error);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007123 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124}
7125
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007126static int sdebug_do_add_host(bool mk_new_store)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007127{
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007128 int ph_idx = sdeb_most_recent_idx;
7129
7130 if (mk_new_store) {
7131 ph_idx = sdebug_add_store();
7132 if (ph_idx < 0)
7133 return ph_idx;
7134 }
7135 return sdebug_add_host_helper(ph_idx);
7136}
7137
7138static void sdebug_do_remove_host(bool the_end)
7139{
7140 int idx = -1;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007141 struct sdebug_host_info *sdbg_host = NULL;
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007142 struct sdebug_host_info *sdbg_host2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007143
Douglas Gilbert9a051012017-12-23 12:48:10 -05007144 spin_lock(&sdebug_host_list_lock);
7145 if (!list_empty(&sdebug_host_list)) {
7146 sdbg_host = list_entry(sdebug_host_list.prev,
7147 struct sdebug_host_info, host_list);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007148 idx = sdbg_host->si_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007149 }
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007150 if (!the_end && idx >= 0) {
7151 bool unique = true;
7152
7153 list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
7154 if (sdbg_host2 == sdbg_host)
7155 continue;
7156 if (idx == sdbg_host2->si_idx) {
7157 unique = false;
7158 break;
7159 }
7160 }
7161 if (unique) {
7162 xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
7163 if (idx == sdeb_most_recent_idx)
7164 --sdeb_most_recent_idx;
7165 }
7166 }
7167 if (sdbg_host)
7168 list_del(&sdbg_host->host_list);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007169 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007170
7171 if (!sdbg_host)
7172 return;
7173
Douglas Gilbert773642d2016-04-25 12:16:28 -04007174 device_unregister(&sdbg_host->dev);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007175 --sdebug_num_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007176}
7177
Douglas Gilbertfd321192016-04-25 12:16:33 -04007178static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007179{
7180 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007181 struct sdebug_dev_info *devip;
7182
Douglas Gilbertc4837392016-05-06 00:40:26 -04007183 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007184 devip = (struct sdebug_dev_info *)sdev->hostdata;
7185 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007186 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007187 return -ENODEV;
7188 }
7189 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007190
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007191 if (qdepth > SDEBUG_CANQUEUE) {
7192 qdepth = SDEBUG_CANQUEUE;
7193 pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__,
7194 qdepth, SDEBUG_CANQUEUE);
7195 }
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007196 if (qdepth < 1)
7197 qdepth = 1;
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007198 if (qdepth != sdev->queue_depth)
7199 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007200
Douglas Gilbert773642d2016-04-25 12:16:28 -04007201 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007202 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007203 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007204 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007205 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007206 return sdev->queue_depth;
7207}
7208
Douglas Gilbertc4837392016-05-06 00:40:26 -04007209static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05007210{
Douglas Gilbertc4837392016-05-06 00:40:26 -04007211 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04007212 if (sdebug_every_nth < -1)
7213 sdebug_every_nth = -1;
7214 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04007215 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04007216 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05007217 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04007218 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05007219 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007220 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05007221}
7222
Douglas Gilbertfc136382020-07-24 11:55:31 -04007223/* Response to TUR or media access command when device stopped */
7224static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
7225{
7226 int stopped_state;
7227 u64 diff_ns = 0;
7228 ktime_t now_ts = ktime_get_boottime();
7229 struct scsi_device *sdp = scp->device;
7230
7231 stopped_state = atomic_read(&devip->stopped);
7232 if (stopped_state == 2) {
7233 if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
7234 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
7235 if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
7236 /* tur_ms_to_ready timer extinguished */
7237 atomic_set(&devip->stopped, 0);
7238 return 0;
7239 }
7240 }
7241 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
7242 if (sdebug_verbose)
7243 sdev_printk(KERN_INFO, sdp,
7244 "%s: Not ready: in process of becoming ready\n", my_name);
7245 if (scp->cmnd[0] == TEST_UNIT_READY) {
7246 u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
7247
7248 if (diff_ns <= tur_nanosecs_to_ready)
7249 diff_ns = tur_nanosecs_to_ready - diff_ns;
7250 else
7251 diff_ns = tur_nanosecs_to_ready;
7252 /* As per 20-061r2 approved for spc6 by T10 on 20200716 */
7253 do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */
7254 scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
7255 diff_ns);
7256 return check_condition_result;
7257 }
7258 }
7259 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
7260 if (sdebug_verbose)
7261 sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
7262 my_name);
7263 return check_condition_result;
7264}
7265
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307266static int sdebug_map_queues(struct Scsi_Host *shost)
7267{
7268 int i, qoff;
7269
7270 if (shost->nr_hw_queues == 1)
7271 return 0;
7272
7273 for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) {
7274 struct blk_mq_queue_map *map = &shost->tag_set.map[i];
7275
7276 map->nr_queues = 0;
7277
7278 if (i == HCTX_TYPE_DEFAULT)
7279 map->nr_queues = submit_queues - poll_queues;
7280 else if (i == HCTX_TYPE_POLL)
7281 map->nr_queues = poll_queues;
7282
7283 if (!map->nr_queues) {
7284 BUG_ON(i == HCTX_TYPE_DEFAULT);
7285 continue;
7286 }
7287
7288 map->queue_offset = qoff;
7289 blk_mq_map_queues(map);
7290
7291 qoff += map->nr_queues;
7292 }
7293
7294 return 0;
7295
7296}
7297
7298static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
7299{
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307300 bool first;
7301 bool retiring = false;
7302 int num_entries = 0;
7303 unsigned int qc_idx = 0;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307304 unsigned long iflags;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307305 ktime_t kt_from_boot = ktime_get_boottime();
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307306 struct sdebug_queue *sqp;
7307 struct sdebug_queued_cmd *sqcp;
7308 struct scsi_cmnd *scp;
7309 struct sdebug_dev_info *devip;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307310 struct sdebug_defer *sd_dp;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307311
7312 sqp = sdebug_q_arr + queue_num;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307313 spin_lock_irqsave(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307314
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307315 for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) {
7316 if (first) {
7317 qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
7318 first = false;
7319 } else {
7320 qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
7321 }
7322 if (unlikely(qc_idx >= sdebug_max_queue))
7323 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307324
7325 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307326 sd_dp = sqcp->sd_dp;
7327 if (unlikely(!sd_dp))
7328 continue;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307329 scp = sqcp->a_cmnd;
7330 if (unlikely(scp == NULL)) {
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307331 pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n",
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307332 queue_num, qc_idx, __func__);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307333 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307334 }
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307335 if (sd_dp->defer_t == SDEB_DEFER_POLL) {
7336 if (kt_from_boot < sd_dp->cmpl_ts)
7337 continue;
7338
Christoph Hellwig6ce913f2021-10-12 13:12:21 +02007339 } else /* ignoring non REQ_POLLED requests */
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307340 continue;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307341 devip = (struct sdebug_dev_info *)scp->device->hostdata;
7342 if (likely(devip))
7343 atomic_dec(&devip->num_in_q);
7344 else
7345 pr_err("devip=NULL from %s\n", __func__);
7346 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307347 retiring = true;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307348
7349 sqcp->a_cmnd = NULL;
7350 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307351 pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n",
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307352 sqp, queue_num, qc_idx, __func__);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307353 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307354 }
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307355 if (unlikely(retiring)) { /* user has reduced max_queue */
7356 int k, retval;
7357
7358 retval = atomic_read(&retired_max_queue);
7359 if (qc_idx >= retval) {
7360 pr_err("index %d too large\n", retval);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307361 break;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307362 }
7363 k = find_last_bit(sqp->in_use_bm, retval);
7364 if ((k < sdebug_max_queue) || (k == retval))
7365 atomic_set(&retired_max_queue, 0);
7366 else
7367 atomic_set(&retired_max_queue, k + 1);
7368 }
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307369 sd_dp->defer_t = SDEB_DEFER_NONE;
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307370 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Bart Van Assche6c2c7d62021-10-07 13:29:04 -07007371 scsi_done(scp); /* callback to mid level */
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307372 spin_lock_irqsave(&sqp->qc_lock, iflags);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307373 num_entries++;
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307374 }
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307375 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert4a0c6f42021-02-15 13:10:47 +05307376 if (num_entries > 0)
7377 atomic_add(num_entries, &sdeb_mq_poll_count);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307378 return num_entries;
7379}
7380
Douglas Gilbertfd321192016-04-25 12:16:33 -04007381static int scsi_debug_queuecommand(struct Scsi_Host *shost,
7382 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007383{
7384 u8 sdeb_i;
7385 struct scsi_device *sdp = scp->device;
7386 const struct opcode_info_t *oip;
7387 const struct opcode_info_t *r_oip;
7388 struct sdebug_dev_info *devip;
7389 u8 *cmd = scp->cmnd;
7390 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
Martin Wilckf66b8512018-02-14 11:05:57 +01007391 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007392 int k, na;
7393 int errsts = 0;
Douglas Gilbertad0c7772020-08-21 00:22:49 -04007394 u64 lun_index = sdp->lun & 0x3FFF;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007395 u32 flags;
7396 u16 sa;
7397 u8 opcode = cmd[0];
7398 bool has_wlun_rl;
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007399 bool inject_now;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007400
7401 scsi_set_resid(scp, 0);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007402 if (sdebug_statistics) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007403 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007404 inject_now = inject_on_this_cmd();
7405 } else {
7406 inject_now = false;
7407 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007408 if (unlikely(sdebug_verbose &&
7409 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007410 char b[120];
7411 int n, len, sb;
7412
7413 len = scp->cmd_len;
7414 sb = (int)sizeof(b);
7415 if (len > 32)
7416 strcpy(b, "too long, over 32 bytes");
7417 else {
7418 for (k = 0, n = 0; k < len && n < sb; ++k)
7419 n += scnprintf(b + n, sb - n, "%02x ",
7420 (u32)cmd[k]);
7421 }
Bart Van Assche458df782018-01-26 08:52:19 -08007422 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
Bart Van Asschea6e76e62021-08-09 16:03:44 -07007423 blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007424 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007425 if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08007426 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03007427 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertad0c7772020-08-21 00:22:49 -04007428 if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007429 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007430
7431 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
7432 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
7433 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007434 if (unlikely(!devip)) {
7435 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007436 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007437 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007438 }
Douglas Gilbert3a90a632020-07-12 14:29:26 -04007439 if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
7440 atomic_set(&sdeb_inject_pending, 1);
7441
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007442 na = oip->num_attached;
7443 r_pfp = oip->pfp;
7444 if (na) { /* multiple commands with this opcode */
7445 r_oip = oip;
7446 if (FF_SA & r_oip->flags) {
7447 if (F_SA_LOW & oip->flags)
7448 sa = 0x1f & cmd[1];
7449 else
7450 sa = get_unaligned_be16(cmd + 8);
7451 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7452 if (opcode == oip->opcode && sa == oip->sa)
7453 break;
7454 }
7455 } else { /* since no service action only check opcode */
7456 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
7457 if (opcode == oip->opcode)
7458 break;
7459 }
7460 }
7461 if (k > na) {
7462 if (F_SA_LOW & r_oip->flags)
7463 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
7464 else if (F_SA_HIGH & r_oip->flags)
7465 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
7466 else
7467 mk_sense_invalid_opcode(scp);
7468 goto check_cond;
7469 }
7470 } /* else (when na==0) we assume the oip is a match */
7471 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007472 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007473 mk_sense_invalid_opcode(scp);
7474 goto check_cond;
7475 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007476 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04007477 if (sdebug_verbose)
7478 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
7479 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007480 mk_sense_invalid_opcode(scp);
7481 goto check_cond;
7482 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007483 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007484 u8 rem;
7485 int j;
7486
7487 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
7488 rem = ~oip->len_mask[k] & cmd[k];
7489 if (rem) {
7490 for (j = 7; j >= 0; --j, rem <<= 1) {
7491 if (0x80 & rem)
7492 break;
7493 }
7494 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
7495 goto check_cond;
7496 }
7497 }
7498 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007499 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04007500 find_first_bit(devip->uas_bm,
7501 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007502 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007503 if (errsts)
7504 goto check_cond;
7505 }
Douglas Gilbertfc136382020-07-24 11:55:31 -04007506 if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
7507 atomic_read(&devip->stopped))) {
7508 errsts = resp_not_ready(scp, devip);
7509 if (errsts)
7510 goto fini;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007511 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04007512 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007513 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007514 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04007515 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007516 return 0; /* ignore command: make trouble */
7517 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007518 if (likely(oip->pfp))
Martin Wilckf66b8512018-02-14 11:05:57 +01007519 pfp = oip->pfp; /* calls a resp_* function */
7520 else
7521 pfp = r_pfp; /* if leaf function ptr NULL, try the root's */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007522
7523fini:
Douglas Gilbert67da4132020-04-21 11:14:20 -04007524 if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */
Martin Wilckf66b8512018-02-14 11:05:57 +01007525 return schedule_resp(scp, devip, errsts, pfp, 0, 0);
Douglas Gilbert75aa3202018-07-12 13:35:42 -04007526 else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
7527 sdebug_ndelay > 10000)) {
Douglas Gilbert80c49562018-02-09 21:36:39 -05007528 /*
Douglas Gilbert75aa3202018-07-12 13:35:42 -04007529 * Skip long delays if ndelay <= 10 microseconds. Otherwise
7530 * for Start Stop Unit (SSU) want at least 1 second delay and
7531 * if sdebug_jdelay>1 want a long delay of that many seconds.
7532 * For Synchronize Cache want 1/20 of SSU's delay.
Douglas Gilbert80c49562018-02-09 21:36:39 -05007533 */
7534 int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04007535 int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
Douglas Gilbert80c49562018-02-09 21:36:39 -05007536
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04007537 jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
Martin Wilckf66b8512018-02-14 11:05:57 +01007538 return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05007539 } else
Martin Wilckf66b8512018-02-14 11:05:57 +01007540 return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
Douglas Gilbert10bde982018-01-10 16:57:31 -05007541 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007542check_cond:
Martin Wilckf66b8512018-02-14 11:05:57 +01007543 return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007544err_out:
Martin Wilckf66b8512018-02-14 11:05:57 +01007545 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05007546}
7547
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007548static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04007549 .show_info = scsi_debug_show_info,
7550 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007551 .proc_name = sdebug_proc_name,
7552 .name = "SCSI DEBUG",
7553 .info = scsi_debug_info,
7554 .slave_alloc = scsi_debug_slave_alloc,
7555 .slave_configure = scsi_debug_slave_configure,
7556 .slave_destroy = scsi_debug_slave_destroy,
7557 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04007558 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007559 .change_queue_depth = sdebug_change_qdepth,
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307560 .map_queues = sdebug_map_queues,
7561 .mq_poll = sdebug_blk_mq_poll,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007562 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007563 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007564 .eh_target_reset_handler = scsi_debug_target_reset,
7565 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007566 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04007567 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007568 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07007569 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007570 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09007571 .max_sectors = -1U,
Christoph Hellwig50c2e912018-12-13 16:17:03 +01007572 .max_segment_size = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007573 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01007574 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09007575};
7576
John Pittman91d4c752018-02-09 21:12:43 -05007577static int sdebug_driver_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007578{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05007579 int error = 0;
7580 struct sdebug_host_info *sdbg_host;
7581 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007582 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007583
7584 sdbg_host = to_sdebug_host(dev);
7585
John Garryf7c4cdc2020-08-19 23:20:33 +08007586 sdebug_driver_template.can_queue = sdebug_max_queue;
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007587 sdebug_driver_template.cmd_per_lun = sdebug_max_queue;
Christoph Hellwig2a3d4eb2018-12-13 16:17:02 +01007588 if (!sdebug_clustering)
Christoph Hellwig4af14d12018-12-13 16:17:09 +01007589 sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
7590
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007591 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
7592 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007593 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007594 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007595 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04007596 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04007597 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07007598 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04007599 my_name, submit_queues, nr_cpu_ids);
7600 submit_queues = nr_cpu_ids;
7601 }
John Garryc10fa552020-07-09 20:23:20 +08007602 /*
7603 * Decide whether to tell scsi subsystem that we want mq. The
John Garryf7c4cdc2020-08-19 23:20:33 +08007604 * following should give the same answer for each host.
John Garryc10fa552020-07-09 20:23:20 +08007605 */
John Garryf7c4cdc2020-08-19 23:20:33 +08007606 hpnt->nr_hw_queues = submit_queues;
7607 if (sdebug_host_max_queue)
7608 hpnt->host_tagset = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007609
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307610 /* poll queues are possible for nr_hw_queues > 1 */
7611 if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) {
7612 pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n",
7613 my_name, poll_queues, hpnt->nr_hw_queues);
7614 poll_queues = 0;
7615 }
7616
7617 /*
7618 * Poll queues don't need interrupts, but we need at least one I/O queue
7619 * left over for non-polled I/O.
7620 * If condition not met, trim poll_queues to 1 (just for simplicity).
7621 */
7622 if (poll_queues >= submit_queues) {
Douglas Gilbertfc09acb2021-04-14 21:50:31 -04007623 if (submit_queues < 3)
7624 pr_warn("%s: trim poll_queues to 1\n", my_name);
7625 else
7626 pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n",
7627 my_name, submit_queues - 1);
Kashyap Desaic4b57d892021-02-15 13:10:46 +05307628 poll_queues = 1;
7629 }
7630 if (poll_queues)
7631 hpnt->nr_maps = 3;
7632
Douglas Gilbert9a051012017-12-23 12:48:10 -05007633 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007634 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007635 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
7636 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04007638 hpnt->max_id = sdebug_num_tgts;
7639 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03007640 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007641
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007642 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007643
Douglas Gilbert773642d2016-04-25 12:16:28 -04007644 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007645
Christoph Hellwig8475c812016-09-11 19:35:41 +02007646 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007647 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007648 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007649 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007650 break;
7651
Christoph Hellwig8475c812016-09-11 19:35:41 +02007652 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007653 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007654 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007655 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007656 break;
7657
Christoph Hellwig8475c812016-09-11 19:35:41 +02007658 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007659 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04007660 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007661 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007662 break;
7663
7664 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04007665 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007666 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007667 break;
7668 }
7669
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007670 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007671
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04007672 if (have_dif_prot || sdebug_dix)
7673 pr_info("host protection%s%s%s%s%s%s%s\n",
7674 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
7675 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
7676 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
7677 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
7678 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
7679 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
7680 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007681
Douglas Gilbert773642d2016-04-25 12:16:28 -04007682 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05007683 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
7684 else
7685 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
7686
Douglas Gilbert773642d2016-04-25 12:16:28 -04007687 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
7688 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04007689 if (sdebug_every_nth) /* need stats counters for every_nth */
7690 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05007691 error = scsi_add_host(hpnt, &sdbg_host->dev);
7692 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03007693 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05007694 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007695 scsi_host_put(hpnt);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007696 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007697 scsi_scan_host(hpnt);
Douglas Gilbert87c715d2020-04-21 11:14:18 -04007698 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007699
Douglas Gilbertcbf67842014-07-26 11:55:35 -04007700 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007701}
7702
Uwe Kleine-Königfc7a6202021-07-13 21:35:22 +02007703static void sdebug_driver_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007704{
Douglas Gilbert9a051012017-12-23 12:48:10 -05007705 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007706 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707
7708 sdbg_host = to_sdebug_host(dev);
7709
Douglas Gilbert9a051012017-12-23 12:48:10 -05007710 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007711
FUJITA Tomonori8b402282008-03-20 11:09:18 +09007712 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
7713 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05007714 list_del(&sdbg_devinfo->dev_list);
Douglas Gilbertf0d1cf92020-04-22 19:42:16 +09007715 kfree(sdbg_devinfo->zstate);
Douglas Gilbert9a051012017-12-23 12:48:10 -05007716 kfree(sdbg_devinfo);
7717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007718
Douglas Gilbert9a051012017-12-23 12:48:10 -05007719 scsi_host_put(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007720}
7721
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007722static int pseudo_lld_bus_match(struct device *dev,
7723 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007724{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007725 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007726}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007727
7728static struct bus_type pseudo_lld_bus = {
7729 .name = "pseudo",
7730 .match = pseudo_lld_bus_match,
7731 .probe = sdebug_driver_probe,
7732 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09007733 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09007734};