18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
48c2ecf20Sopenharmony_ci *  Copyright (C) 1992  Eric Youngdale
58c2ecf20Sopenharmony_ci *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
68c2ecf20Sopenharmony_ci *  to make sure that we are not getting blocks mixed up, and PANIC if
78c2ecf20Sopenharmony_ci *  anything out of the ordinary is seen.
88c2ecf20Sopenharmony_ci * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2020 Douglas Gilbert
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci *  For documentation see http://sg.danny.cz/sg/scsi_debug.html
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/kernel.h>
218c2ecf20Sopenharmony_ci#include <linux/errno.h>
228c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/types.h>
258c2ecf20Sopenharmony_ci#include <linux/string.h>
268c2ecf20Sopenharmony_ci#include <linux/genhd.h>
278c2ecf20Sopenharmony_ci#include <linux/fs.h>
288c2ecf20Sopenharmony_ci#include <linux/init.h>
298c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
308c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
318c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
328c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
338c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
348c2ecf20Sopenharmony_ci#include <linux/crc-t10dif.h>
358c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
368c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
378c2ecf20Sopenharmony_ci#include <linux/atomic.h>
388c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
398c2ecf20Sopenharmony_ci#include <linux/uuid.h>
408c2ecf20Sopenharmony_ci#include <linux/t10-pi.h>
418c2ecf20Sopenharmony_ci#include <linux/msdos_partition.h>
428c2ecf20Sopenharmony_ci#include <linux/random.h>
438c2ecf20Sopenharmony_ci#include <linux/xarray.h>
448c2ecf20Sopenharmony_ci#include <linux/prefetch.h>
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#include <net/checksum.h>
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
518c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
528c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
538c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
548c2ecf20Sopenharmony_ci#include <scsi/scsicam.h>
558c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h>
568c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
578c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h>
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#include "sd.h"
608c2ecf20Sopenharmony_ci#include "scsi_logging.h"
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* make sure inq_product_rev string corresponds to this version */
638c2ecf20Sopenharmony_ci#define SDEBUG_VERSION "0190"	/* format to fit INQUIRY revision field */
648c2ecf20Sopenharmony_cistatic const char *sdebug_version_date = "20200710";
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define MY_NAME "scsi_debug"
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* Additional Sense Code (ASC) */
698c2ecf20Sopenharmony_ci#define NO_ADDITIONAL_SENSE 0x0
708c2ecf20Sopenharmony_ci#define LOGICAL_UNIT_NOT_READY 0x4
718c2ecf20Sopenharmony_ci#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
728c2ecf20Sopenharmony_ci#define UNRECOVERED_READ_ERR 0x11
738c2ecf20Sopenharmony_ci#define PARAMETER_LIST_LENGTH_ERR 0x1a
748c2ecf20Sopenharmony_ci#define INVALID_OPCODE 0x20
758c2ecf20Sopenharmony_ci#define LBA_OUT_OF_RANGE 0x21
768c2ecf20Sopenharmony_ci#define INVALID_FIELD_IN_CDB 0x24
778c2ecf20Sopenharmony_ci#define INVALID_FIELD_IN_PARAM_LIST 0x26
788c2ecf20Sopenharmony_ci#define WRITE_PROTECTED 0x27
798c2ecf20Sopenharmony_ci#define UA_RESET_ASC 0x29
808c2ecf20Sopenharmony_ci#define UA_CHANGED_ASC 0x2a
818c2ecf20Sopenharmony_ci#define TARGET_CHANGED_ASC 0x3f
828c2ecf20Sopenharmony_ci#define LUNS_CHANGED_ASCQ 0x0e
838c2ecf20Sopenharmony_ci#define INSUFF_RES_ASC 0x55
848c2ecf20Sopenharmony_ci#define INSUFF_RES_ASCQ 0x3
858c2ecf20Sopenharmony_ci#define POWER_ON_RESET_ASCQ 0x0
868c2ecf20Sopenharmony_ci#define BUS_RESET_ASCQ 0x2	/* scsi bus reset occurred */
878c2ecf20Sopenharmony_ci#define MODE_CHANGED_ASCQ 0x1	/* mode parameters changed */
888c2ecf20Sopenharmony_ci#define CAPACITY_CHANGED_ASCQ 0x9
898c2ecf20Sopenharmony_ci#define SAVING_PARAMS_UNSUP 0x39
908c2ecf20Sopenharmony_ci#define TRANSPORT_PROBLEM 0x4b
918c2ecf20Sopenharmony_ci#define THRESHOLD_EXCEEDED 0x5d
928c2ecf20Sopenharmony_ci#define LOW_POWER_COND_ON 0x5e
938c2ecf20Sopenharmony_ci#define MISCOMPARE_VERIFY_ASC 0x1d
948c2ecf20Sopenharmony_ci#define MICROCODE_CHANGED_ASCQ 0x1	/* with TARGET_CHANGED_ASC */
958c2ecf20Sopenharmony_ci#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
968c2ecf20Sopenharmony_ci#define WRITE_ERROR_ASC 0xc
978c2ecf20Sopenharmony_ci#define UNALIGNED_WRITE_ASCQ 0x4
988c2ecf20Sopenharmony_ci#define WRITE_BOUNDARY_ASCQ 0x5
998c2ecf20Sopenharmony_ci#define READ_INVDATA_ASCQ 0x6
1008c2ecf20Sopenharmony_ci#define READ_BOUNDARY_ASCQ 0x7
1018c2ecf20Sopenharmony_ci#define INSUFF_ZONE_ASCQ 0xe
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/* Additional Sense Code Qualifier (ASCQ) */
1048c2ecf20Sopenharmony_ci#define ACK_NAK_TO 0x3
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* Default values for driver parameters */
1078c2ecf20Sopenharmony_ci#define DEF_NUM_HOST   1
1088c2ecf20Sopenharmony_ci#define DEF_NUM_TGTS   1
1098c2ecf20Sopenharmony_ci#define DEF_MAX_LUNS   1
1108c2ecf20Sopenharmony_ci/* With these defaults, this driver will make 1 host with 1 target
1118c2ecf20Sopenharmony_ci * (id 0) containing 1 logical unit (lun 0). That is 1 device.
1128c2ecf20Sopenharmony_ci */
1138c2ecf20Sopenharmony_ci#define DEF_ATO 1
1148c2ecf20Sopenharmony_ci#define DEF_CDB_LEN 10
1158c2ecf20Sopenharmony_ci#define DEF_JDELAY   1		/* if > 0 unit is a jiffy */
1168c2ecf20Sopenharmony_ci#define DEF_DEV_SIZE_PRE_INIT   0
1178c2ecf20Sopenharmony_ci#define DEF_DEV_SIZE_MB   8
1188c2ecf20Sopenharmony_ci#define DEF_ZBC_DEV_SIZE_MB   128
1198c2ecf20Sopenharmony_ci#define DEF_DIF 0
1208c2ecf20Sopenharmony_ci#define DEF_DIX 0
1218c2ecf20Sopenharmony_ci#define DEF_PER_HOST_STORE false
1228c2ecf20Sopenharmony_ci#define DEF_D_SENSE   0
1238c2ecf20Sopenharmony_ci#define DEF_EVERY_NTH   0
1248c2ecf20Sopenharmony_ci#define DEF_FAKE_RW	0
1258c2ecf20Sopenharmony_ci#define DEF_GUARD 0
1268c2ecf20Sopenharmony_ci#define DEF_HOST_LOCK 0
1278c2ecf20Sopenharmony_ci#define DEF_LBPU 0
1288c2ecf20Sopenharmony_ci#define DEF_LBPWS 0
1298c2ecf20Sopenharmony_ci#define DEF_LBPWS10 0
1308c2ecf20Sopenharmony_ci#define DEF_LBPRZ 1
1318c2ecf20Sopenharmony_ci#define DEF_LOWEST_ALIGNED 0
1328c2ecf20Sopenharmony_ci#define DEF_NDELAY   0		/* if > 0 unit is a nanosecond */
1338c2ecf20Sopenharmony_ci#define DEF_NO_LUN_0   0
1348c2ecf20Sopenharmony_ci#define DEF_NUM_PARTS   0
1358c2ecf20Sopenharmony_ci#define DEF_OPTS   0
1368c2ecf20Sopenharmony_ci#define DEF_OPT_BLKS 1024
1378c2ecf20Sopenharmony_ci#define DEF_PHYSBLK_EXP 0
1388c2ecf20Sopenharmony_ci#define DEF_OPT_XFERLEN_EXP 0
1398c2ecf20Sopenharmony_ci#define DEF_PTYPE   TYPE_DISK
1408c2ecf20Sopenharmony_ci#define DEF_RANDOM false
1418c2ecf20Sopenharmony_ci#define DEF_REMOVABLE false
1428c2ecf20Sopenharmony_ci#define DEF_SCSI_LEVEL   7    /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
1438c2ecf20Sopenharmony_ci#define DEF_SECTOR_SIZE 512
1448c2ecf20Sopenharmony_ci#define DEF_UNMAP_ALIGNMENT 0
1458c2ecf20Sopenharmony_ci#define DEF_UNMAP_GRANULARITY 1
1468c2ecf20Sopenharmony_ci#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
1478c2ecf20Sopenharmony_ci#define DEF_UNMAP_MAX_DESC 256
1488c2ecf20Sopenharmony_ci#define DEF_VIRTUAL_GB   0
1498c2ecf20Sopenharmony_ci#define DEF_VPD_USE_HOSTNO 1
1508c2ecf20Sopenharmony_ci#define DEF_WRITESAME_LENGTH 0xFFFF
1518c2ecf20Sopenharmony_ci#define DEF_STRICT 0
1528c2ecf20Sopenharmony_ci#define DEF_STATISTICS false
1538c2ecf20Sopenharmony_ci#define DEF_SUBMIT_QUEUES 1
1548c2ecf20Sopenharmony_ci#define DEF_TUR_MS_TO_READY 0
1558c2ecf20Sopenharmony_ci#define DEF_UUID_CTL 0
1568c2ecf20Sopenharmony_ci#define JDELAY_OVERRIDDEN -9999
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/* Default parameters for ZBC drives */
1598c2ecf20Sopenharmony_ci#define DEF_ZBC_ZONE_SIZE_MB	128
1608c2ecf20Sopenharmony_ci#define DEF_ZBC_MAX_OPEN_ZONES	8
1618c2ecf20Sopenharmony_ci#define DEF_ZBC_NR_CONV_ZONES	1
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci#define SDEBUG_LUN_0_VAL 0
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/* bit mask values for sdebug_opts */
1668c2ecf20Sopenharmony_ci#define SDEBUG_OPT_NOISE		1
1678c2ecf20Sopenharmony_ci#define SDEBUG_OPT_MEDIUM_ERR		2
1688c2ecf20Sopenharmony_ci#define SDEBUG_OPT_TIMEOUT		4
1698c2ecf20Sopenharmony_ci#define SDEBUG_OPT_RECOVERED_ERR	8
1708c2ecf20Sopenharmony_ci#define SDEBUG_OPT_TRANSPORT_ERR	16
1718c2ecf20Sopenharmony_ci#define SDEBUG_OPT_DIF_ERR		32
1728c2ecf20Sopenharmony_ci#define SDEBUG_OPT_DIX_ERR		64
1738c2ecf20Sopenharmony_ci#define SDEBUG_OPT_MAC_TIMEOUT		128
1748c2ecf20Sopenharmony_ci#define SDEBUG_OPT_SHORT_TRANSFER	0x100
1758c2ecf20Sopenharmony_ci#define SDEBUG_OPT_Q_NOISE		0x200
1768c2ecf20Sopenharmony_ci#define SDEBUG_OPT_ALL_TSF		0x400
1778c2ecf20Sopenharmony_ci#define SDEBUG_OPT_RARE_TSF		0x800
1788c2ecf20Sopenharmony_ci#define SDEBUG_OPT_N_WCE		0x1000
1798c2ecf20Sopenharmony_ci#define SDEBUG_OPT_RESET_NOISE		0x2000
1808c2ecf20Sopenharmony_ci#define SDEBUG_OPT_NO_CDB_NOISE		0x4000
1818c2ecf20Sopenharmony_ci#define SDEBUG_OPT_HOST_BUSY		0x8000
1828c2ecf20Sopenharmony_ci#define SDEBUG_OPT_CMD_ABORT		0x10000
1838c2ecf20Sopenharmony_ci#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
1848c2ecf20Sopenharmony_ci			      SDEBUG_OPT_RESET_NOISE)
1858c2ecf20Sopenharmony_ci#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
1868c2ecf20Sopenharmony_ci				  SDEBUG_OPT_TRANSPORT_ERR | \
1878c2ecf20Sopenharmony_ci				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
1888c2ecf20Sopenharmony_ci				  SDEBUG_OPT_SHORT_TRANSFER | \
1898c2ecf20Sopenharmony_ci				  SDEBUG_OPT_HOST_BUSY | \
1908c2ecf20Sopenharmony_ci				  SDEBUG_OPT_CMD_ABORT)
1918c2ecf20Sopenharmony_ci#define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \
1928c2ecf20Sopenharmony_ci				  SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR)
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
1958c2ecf20Sopenharmony_ci * priority order. In the subset implemented here lower numbers have higher
1968c2ecf20Sopenharmony_ci * priority. The UA numbers should be a sequence starting from 0 with
1978c2ecf20Sopenharmony_ci * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
1988c2ecf20Sopenharmony_ci#define SDEBUG_UA_POR 0		/* Power on, reset, or bus device reset */
1998c2ecf20Sopenharmony_ci#define SDEBUG_UA_BUS_RESET 1
2008c2ecf20Sopenharmony_ci#define SDEBUG_UA_MODE_CHANGED 2
2018c2ecf20Sopenharmony_ci#define SDEBUG_UA_CAPACITY_CHANGED 3
2028c2ecf20Sopenharmony_ci#define SDEBUG_UA_LUNS_CHANGED 4
2038c2ecf20Sopenharmony_ci#define SDEBUG_UA_MICROCODE_CHANGED 5	/* simulate firmware change */
2048c2ecf20Sopenharmony_ci#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
2058c2ecf20Sopenharmony_ci#define SDEBUG_NUM_UAS 7
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
2088c2ecf20Sopenharmony_ci * sector on read commands: */
2098c2ecf20Sopenharmony_ci#define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
2108c2ecf20Sopenharmony_ci#define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
2138c2ecf20Sopenharmony_ci * (for response) per submit queue at one time. Can be reduced by max_queue
2148c2ecf20Sopenharmony_ci * option. Command responses are not queued when jdelay=0 and ndelay=0. The
2158c2ecf20Sopenharmony_ci * per-device DEF_CMD_PER_LUN can be changed via sysfs:
2168c2ecf20Sopenharmony_ci * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
2178c2ecf20Sopenharmony_ci * but cannot exceed SDEBUG_CANQUEUE .
2188c2ecf20Sopenharmony_ci */
2198c2ecf20Sopenharmony_ci#define SDEBUG_CANQUEUE_WORDS  3	/* a WORD is bits in a long */
2208c2ecf20Sopenharmony_ci#define SDEBUG_CANQUEUE  (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
2218c2ecf20Sopenharmony_ci#define DEF_CMD_PER_LUN  255
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */
2248c2ecf20Sopenharmony_ci#define F_D_IN			1	/* Data-in command (e.g. READ) */
2258c2ecf20Sopenharmony_ci#define F_D_OUT			2	/* Data-out command (e.g. WRITE) */
2268c2ecf20Sopenharmony_ci#define F_D_OUT_MAYBE		4	/* WRITE SAME, NDOB bit */
2278c2ecf20Sopenharmony_ci#define F_D_UNKN		8
2288c2ecf20Sopenharmony_ci#define F_RL_WLUN_OK		0x10	/* allowed with REPORT LUNS W-LUN */
2298c2ecf20Sopenharmony_ci#define F_SKIP_UA		0x20	/* bypass UAs (e.g. INQUIRY command) */
2308c2ecf20Sopenharmony_ci#define F_DELAY_OVERR		0x40	/* for commands like INQUIRY */
2318c2ecf20Sopenharmony_ci#define F_SA_LOW		0x80	/* SA is in cdb byte 1, bits 4 to 0 */
2328c2ecf20Sopenharmony_ci#define F_SA_HIGH		0x100	/* SA is in cdb bytes 8 and 9 */
2338c2ecf20Sopenharmony_ci#define F_INV_OP		0x200	/* invalid opcode (not supported) */
2348c2ecf20Sopenharmony_ci#define F_FAKE_RW		0x400	/* bypass resp_*() when fake_rw set */
2358c2ecf20Sopenharmony_ci#define F_M_ACCESS		0x800	/* media access, reacts to SSU state */
2368c2ecf20Sopenharmony_ci#define F_SSU_DELAY		0x1000	/* SSU command delay (long-ish) */
2378c2ecf20Sopenharmony_ci#define F_SYNC_DELAY		0x2000	/* SYNCHRONIZE CACHE delay */
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci/* Useful combinations of the above flags */
2408c2ecf20Sopenharmony_ci#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
2418c2ecf20Sopenharmony_ci#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
2428c2ecf20Sopenharmony_ci#define FF_SA (F_SA_HIGH | F_SA_LOW)
2438c2ecf20Sopenharmony_ci#define F_LONG_DELAY		(F_SSU_DELAY | F_SYNC_DELAY)
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci#define SDEBUG_MAX_PARTS 4
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci#define SDEBUG_MAX_CMD_LEN 32
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci#define SDEB_XA_NOT_IN_USE XA_MARK_1
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/* Zone types (zbcr05 table 25) */
2528c2ecf20Sopenharmony_cienum sdebug_z_type {
2538c2ecf20Sopenharmony_ci	ZBC_ZONE_TYPE_CNV	= 0x1,
2548c2ecf20Sopenharmony_ci	ZBC_ZONE_TYPE_SWR	= 0x2,
2558c2ecf20Sopenharmony_ci	ZBC_ZONE_TYPE_SWP	= 0x3,
2568c2ecf20Sopenharmony_ci};
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/* enumeration names taken from table 26, zbcr05 */
2598c2ecf20Sopenharmony_cienum sdebug_z_cond {
2608c2ecf20Sopenharmony_ci	ZBC_NOT_WRITE_POINTER	= 0x0,
2618c2ecf20Sopenharmony_ci	ZC1_EMPTY		= 0x1,
2628c2ecf20Sopenharmony_ci	ZC2_IMPLICIT_OPEN	= 0x2,
2638c2ecf20Sopenharmony_ci	ZC3_EXPLICIT_OPEN	= 0x3,
2648c2ecf20Sopenharmony_ci	ZC4_CLOSED		= 0x4,
2658c2ecf20Sopenharmony_ci	ZC6_READ_ONLY		= 0xd,
2668c2ecf20Sopenharmony_ci	ZC5_FULL		= 0xe,
2678c2ecf20Sopenharmony_ci	ZC7_OFFLINE		= 0xf,
2688c2ecf20Sopenharmony_ci};
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistruct sdeb_zone_state {	/* ZBC: per zone state */
2718c2ecf20Sopenharmony_ci	enum sdebug_z_type z_type;
2728c2ecf20Sopenharmony_ci	enum sdebug_z_cond z_cond;
2738c2ecf20Sopenharmony_ci	bool z_non_seq_resource;
2748c2ecf20Sopenharmony_ci	unsigned int z_size;
2758c2ecf20Sopenharmony_ci	sector_t z_start;
2768c2ecf20Sopenharmony_ci	sector_t z_wp;
2778c2ecf20Sopenharmony_ci};
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistruct sdebug_dev_info {
2808c2ecf20Sopenharmony_ci	struct list_head dev_list;
2818c2ecf20Sopenharmony_ci	unsigned int channel;
2828c2ecf20Sopenharmony_ci	unsigned int target;
2838c2ecf20Sopenharmony_ci	u64 lun;
2848c2ecf20Sopenharmony_ci	uuid_t lu_name;
2858c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
2868c2ecf20Sopenharmony_ci	unsigned long uas_bm[1];
2878c2ecf20Sopenharmony_ci	atomic_t num_in_q;
2888c2ecf20Sopenharmony_ci	atomic_t stopped;	/* 1: by SSU, 2: device start */
2898c2ecf20Sopenharmony_ci	bool used;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* For ZBC devices */
2928c2ecf20Sopenharmony_ci	enum blk_zoned_model zmodel;
2938c2ecf20Sopenharmony_ci	unsigned int zsize;
2948c2ecf20Sopenharmony_ci	unsigned int zsize_shift;
2958c2ecf20Sopenharmony_ci	unsigned int nr_zones;
2968c2ecf20Sopenharmony_ci	unsigned int nr_conv_zones;
2978c2ecf20Sopenharmony_ci	unsigned int nr_imp_open;
2988c2ecf20Sopenharmony_ci	unsigned int nr_exp_open;
2998c2ecf20Sopenharmony_ci	unsigned int nr_closed;
3008c2ecf20Sopenharmony_ci	unsigned int max_open;
3018c2ecf20Sopenharmony_ci	ktime_t create_ts;	/* time since bootup that this device was created */
3028c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zstate;
3038c2ecf20Sopenharmony_ci};
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistruct sdebug_host_info {
3068c2ecf20Sopenharmony_ci	struct list_head host_list;
3078c2ecf20Sopenharmony_ci	int si_idx;	/* sdeb_store_info (per host) xarray index */
3088c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
3098c2ecf20Sopenharmony_ci	struct device dev;
3108c2ecf20Sopenharmony_ci	struct list_head dev_info_list;
3118c2ecf20Sopenharmony_ci};
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci/* There is an xarray of pointers to this struct's objects, one per host */
3148c2ecf20Sopenharmony_cistruct sdeb_store_info {
3158c2ecf20Sopenharmony_ci	rwlock_t macc_lck;	/* for atomic media access on this store */
3168c2ecf20Sopenharmony_ci	u8 *storep;		/* user data storage (ram) */
3178c2ecf20Sopenharmony_ci	struct t10_pi_tuple *dif_storep; /* protection info */
3188c2ecf20Sopenharmony_ci	void *map_storep;	/* provisioning map */
3198c2ecf20Sopenharmony_ci};
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci#define to_sdebug_host(d)	\
3228c2ecf20Sopenharmony_ci	container_of(d, struct sdebug_host_info, dev)
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cienum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
3258c2ecf20Sopenharmony_ci		      SDEB_DEFER_WQ = 2};
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistruct sdebug_defer {
3288c2ecf20Sopenharmony_ci	struct hrtimer hrt;
3298c2ecf20Sopenharmony_ci	struct execute_work ew;
3308c2ecf20Sopenharmony_ci	int sqa_idx;	/* index of sdebug_queue array */
3318c2ecf20Sopenharmony_ci	int qc_idx;	/* index of sdebug_queued_cmd array within sqa_idx */
3328c2ecf20Sopenharmony_ci	int hc_idx;	/* hostwide tag index */
3338c2ecf20Sopenharmony_ci	int issuing_cpu;
3348c2ecf20Sopenharmony_ci	bool init_hrt;
3358c2ecf20Sopenharmony_ci	bool init_wq;
3368c2ecf20Sopenharmony_ci	bool aborted;	/* true when blk_abort_request() already called */
3378c2ecf20Sopenharmony_ci	enum sdeb_defer_type defer_t;
3388c2ecf20Sopenharmony_ci};
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistruct sdebug_queued_cmd {
3418c2ecf20Sopenharmony_ci	/* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
3428c2ecf20Sopenharmony_ci	 * instance indicates this slot is in use.
3438c2ecf20Sopenharmony_ci	 */
3448c2ecf20Sopenharmony_ci	struct sdebug_defer *sd_dp;
3458c2ecf20Sopenharmony_ci	struct scsi_cmnd *a_cmnd;
3468c2ecf20Sopenharmony_ci};
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistruct sdebug_queue {
3498c2ecf20Sopenharmony_ci	struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
3508c2ecf20Sopenharmony_ci	unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
3518c2ecf20Sopenharmony_ci	spinlock_t qc_lock;
3528c2ecf20Sopenharmony_ci	atomic_t blocked;	/* to temporarily stop more being queued */
3538c2ecf20Sopenharmony_ci};
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic atomic_t sdebug_cmnd_count;   /* number of incoming commands */
3568c2ecf20Sopenharmony_cistatic atomic_t sdebug_completions;  /* count of deferred completions */
3578c2ecf20Sopenharmony_cistatic atomic_t sdebug_miss_cpus;    /* submission + completion cpus differ */
3588c2ecf20Sopenharmony_cistatic atomic_t sdebug_a_tsf;	     /* 'almost task set full' counter */
3598c2ecf20Sopenharmony_cistatic atomic_t sdeb_inject_pending;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistruct opcode_info_t {
3628c2ecf20Sopenharmony_ci	u8 num_attached;	/* 0 if this is it (i.e. a leaf); use 0xff */
3638c2ecf20Sopenharmony_ci				/* for terminating element */
3648c2ecf20Sopenharmony_ci	u8 opcode;		/* if num_attached > 0, preferred */
3658c2ecf20Sopenharmony_ci	u16 sa;			/* service action */
3668c2ecf20Sopenharmony_ci	u32 flags;		/* OR-ed set of SDEB_F_* */
3678c2ecf20Sopenharmony_ci	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
3688c2ecf20Sopenharmony_ci	const struct opcode_info_t *arrp;  /* num_attached elements or NULL */
3698c2ecf20Sopenharmony_ci	u8 len_mask[16];	/* len_mask[0]-->cdb_len, then mask for cdb */
3708c2ecf20Sopenharmony_ci				/* 1 to min(cdb_len, 15); ignore cdb[15...] */
3718c2ecf20Sopenharmony_ci};
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
3748c2ecf20Sopenharmony_cienum sdeb_opcode_index {
3758c2ecf20Sopenharmony_ci	SDEB_I_INVALID_OPCODE =	0,
3768c2ecf20Sopenharmony_ci	SDEB_I_INQUIRY = 1,
3778c2ecf20Sopenharmony_ci	SDEB_I_REPORT_LUNS = 2,
3788c2ecf20Sopenharmony_ci	SDEB_I_REQUEST_SENSE = 3,
3798c2ecf20Sopenharmony_ci	SDEB_I_TEST_UNIT_READY = 4,
3808c2ecf20Sopenharmony_ci	SDEB_I_MODE_SENSE = 5,		/* 6, 10 */
3818c2ecf20Sopenharmony_ci	SDEB_I_MODE_SELECT = 6,		/* 6, 10 */
3828c2ecf20Sopenharmony_ci	SDEB_I_LOG_SENSE = 7,
3838c2ecf20Sopenharmony_ci	SDEB_I_READ_CAPACITY = 8,	/* 10; 16 is in SA_IN(16) */
3848c2ecf20Sopenharmony_ci	SDEB_I_READ = 9,		/* 6, 10, 12, 16 */
3858c2ecf20Sopenharmony_ci	SDEB_I_WRITE = 10,		/* 6, 10, 12, 16 */
3868c2ecf20Sopenharmony_ci	SDEB_I_START_STOP = 11,
3878c2ecf20Sopenharmony_ci	SDEB_I_SERV_ACT_IN_16 = 12,	/* add ...SERV_ACT_IN_12 if needed */
3888c2ecf20Sopenharmony_ci	SDEB_I_SERV_ACT_OUT_16 = 13,	/* add ...SERV_ACT_OUT_12 if needed */
3898c2ecf20Sopenharmony_ci	SDEB_I_MAINT_IN = 14,
3908c2ecf20Sopenharmony_ci	SDEB_I_MAINT_OUT = 15,
3918c2ecf20Sopenharmony_ci	SDEB_I_VERIFY = 16,		/* VERIFY(10), VERIFY(16) */
3928c2ecf20Sopenharmony_ci	SDEB_I_VARIABLE_LEN = 17,	/* READ(32), WRITE(32), WR_SCAT(32) */
3938c2ecf20Sopenharmony_ci	SDEB_I_RESERVE = 18,		/* 6, 10 */
3948c2ecf20Sopenharmony_ci	SDEB_I_RELEASE = 19,		/* 6, 10 */
3958c2ecf20Sopenharmony_ci	SDEB_I_ALLOW_REMOVAL = 20,	/* PREVENT ALLOW MEDIUM REMOVAL */
3968c2ecf20Sopenharmony_ci	SDEB_I_REZERO_UNIT = 21,	/* REWIND in SSC */
3978c2ecf20Sopenharmony_ci	SDEB_I_ATA_PT = 22,		/* 12, 16 */
3988c2ecf20Sopenharmony_ci	SDEB_I_SEND_DIAG = 23,
3998c2ecf20Sopenharmony_ci	SDEB_I_UNMAP = 24,
4008c2ecf20Sopenharmony_ci	SDEB_I_WRITE_BUFFER = 25,
4018c2ecf20Sopenharmony_ci	SDEB_I_WRITE_SAME = 26,		/* 10, 16 */
4028c2ecf20Sopenharmony_ci	SDEB_I_SYNC_CACHE = 27,		/* 10, 16 */
4038c2ecf20Sopenharmony_ci	SDEB_I_COMP_WRITE = 28,
4048c2ecf20Sopenharmony_ci	SDEB_I_PRE_FETCH = 29,		/* 10, 16 */
4058c2ecf20Sopenharmony_ci	SDEB_I_ZONE_OUT = 30,		/* 0x94+SA; includes no data xfer */
4068c2ecf20Sopenharmony_ci	SDEB_I_ZONE_IN = 31,		/* 0x95+SA; all have data-in */
4078c2ecf20Sopenharmony_ci	SDEB_I_LAST_ELEM_P1 = 32,	/* keep this last (previous + 1) */
4088c2ecf20Sopenharmony_ci};
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic const unsigned char opcode_ind_arr[256] = {
4128c2ecf20Sopenharmony_ci/* 0x0; 0x0->0x1f: 6 byte cdbs */
4138c2ecf20Sopenharmony_ci	SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
4148c2ecf20Sopenharmony_ci	    0, 0, 0, 0,
4158c2ecf20Sopenharmony_ci	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
4168c2ecf20Sopenharmony_ci	0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
4178c2ecf20Sopenharmony_ci	    SDEB_I_RELEASE,
4188c2ecf20Sopenharmony_ci	0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
4198c2ecf20Sopenharmony_ci	    SDEB_I_ALLOW_REMOVAL, 0,
4208c2ecf20Sopenharmony_ci/* 0x20; 0x20->0x3f: 10 byte cdbs */
4218c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
4228c2ecf20Sopenharmony_ci	SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
4238c2ecf20Sopenharmony_ci	0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0,
4248c2ecf20Sopenharmony_ci	0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
4258c2ecf20Sopenharmony_ci/* 0x40; 0x40->0x5f: 10 byte cdbs */
4268c2ecf20Sopenharmony_ci	0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
4278c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
4288c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
4298c2ecf20Sopenharmony_ci	    SDEB_I_RELEASE,
4308c2ecf20Sopenharmony_ci	0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
4318c2ecf20Sopenharmony_ci/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
4328c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4338c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4348c2ecf20Sopenharmony_ci	0, SDEB_I_VARIABLE_LEN,
4358c2ecf20Sopenharmony_ci/* 0x80; 0x80->0x9f: 16 byte cdbs */
4368c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
4378c2ecf20Sopenharmony_ci	SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0,
4388c2ecf20Sopenharmony_ci	0, 0, 0, SDEB_I_VERIFY,
4398c2ecf20Sopenharmony_ci	SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME,
4408c2ecf20Sopenharmony_ci	SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0,
4418c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
4428c2ecf20Sopenharmony_ci/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
4438c2ecf20Sopenharmony_ci	SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
4448c2ecf20Sopenharmony_ci	     SDEB_I_MAINT_OUT, 0, 0, 0,
4458c2ecf20Sopenharmony_ci	SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
4468c2ecf20Sopenharmony_ci	     0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
4478c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0,
4488c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0,
4498c2ecf20Sopenharmony_ci/* 0xc0; 0xc0->0xff: vendor specific */
4508c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4518c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4528c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4538c2ecf20Sopenharmony_ci	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4548c2ecf20Sopenharmony_ci};
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci/*
4578c2ecf20Sopenharmony_ci * The following "response" functions return the SCSI mid-level's 4 byte
4588c2ecf20Sopenharmony_ci * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
4598c2ecf20Sopenharmony_ci * command completion, they can mask their return value with
4608c2ecf20Sopenharmony_ci * SDEG_RES_IMMED_MASK .
4618c2ecf20Sopenharmony_ci */
4628c2ecf20Sopenharmony_ci#define SDEG_RES_IMMED_MASK 0x40000000
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
4658c2ecf20Sopenharmony_cistatic int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
4668c2ecf20Sopenharmony_cistatic int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
4678c2ecf20Sopenharmony_cistatic int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
4688c2ecf20Sopenharmony_cistatic int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
4698c2ecf20Sopenharmony_cistatic int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
4708c2ecf20Sopenharmony_cistatic int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
4718c2ecf20Sopenharmony_cistatic int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
4728c2ecf20Sopenharmony_cistatic int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
4738c2ecf20Sopenharmony_cistatic int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
4748c2ecf20Sopenharmony_cistatic int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
4758c2ecf20Sopenharmony_cistatic int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
4768c2ecf20Sopenharmony_cistatic int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
4778c2ecf20Sopenharmony_cistatic int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
4788c2ecf20Sopenharmony_cistatic int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
4798c2ecf20Sopenharmony_cistatic int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
4808c2ecf20Sopenharmony_cistatic int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
4818c2ecf20Sopenharmony_cistatic int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *);
4828c2ecf20Sopenharmony_cistatic int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
4838c2ecf20Sopenharmony_cistatic int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
4848c2ecf20Sopenharmony_cistatic int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
4858c2ecf20Sopenharmony_cistatic int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
4868c2ecf20Sopenharmony_cistatic int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
4878c2ecf20Sopenharmony_cistatic int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *);
4888c2ecf20Sopenharmony_cistatic int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *);
4898c2ecf20Sopenharmony_cistatic int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
4908c2ecf20Sopenharmony_cistatic int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
4918c2ecf20Sopenharmony_cistatic int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
4928c2ecf20Sopenharmony_cistatic int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *);
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic int sdebug_do_add_host(bool mk_new_store);
4958c2ecf20Sopenharmony_cistatic int sdebug_add_host_helper(int per_host_idx);
4968c2ecf20Sopenharmony_cistatic void sdebug_do_remove_host(bool the_end);
4978c2ecf20Sopenharmony_cistatic int sdebug_add_store(void);
4988c2ecf20Sopenharmony_cistatic void sdebug_erase_store(int idx, struct sdeb_store_info *sip);
4998c2ecf20Sopenharmony_cistatic void sdebug_erase_all_stores(bool apart_from_first);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci/*
5028c2ecf20Sopenharmony_ci * The following are overflow arrays for cdbs that "hit" the same index in
5038c2ecf20Sopenharmony_ci * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
5048c2ecf20Sopenharmony_ci * should be placed in opcode_info_arr[], the others should be placed here.
5058c2ecf20Sopenharmony_ci */
5068c2ecf20Sopenharmony_cistatic const struct opcode_info_t msense_iarr[] = {
5078c2ecf20Sopenharmony_ci	{0, 0x1a, 0, F_D_IN, NULL, NULL,
5088c2ecf20Sopenharmony_ci	    {6,  0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
5098c2ecf20Sopenharmony_ci};
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic const struct opcode_info_t mselect_iarr[] = {
5128c2ecf20Sopenharmony_ci	{0, 0x15, 0, F_D_OUT, NULL, NULL,
5138c2ecf20Sopenharmony_ci	    {6,  0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
5148c2ecf20Sopenharmony_ci};
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic const struct opcode_info_t read_iarr[] = {
5178c2ecf20Sopenharmony_ci	{0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
5188c2ecf20Sopenharmony_ci	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
5198c2ecf20Sopenharmony_ci	     0, 0, 0, 0} },
5208c2ecf20Sopenharmony_ci	{0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
5218c2ecf20Sopenharmony_ci	    {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
5228c2ecf20Sopenharmony_ci	{0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
5238c2ecf20Sopenharmony_ci	    {12,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
5248c2ecf20Sopenharmony_ci	     0xc7, 0, 0, 0, 0} },
5258c2ecf20Sopenharmony_ci};
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic const struct opcode_info_t write_iarr[] = {
5288c2ecf20Sopenharmony_ci	{0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(10) */
5298c2ecf20Sopenharmony_ci	    NULL, {10,  0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
5308c2ecf20Sopenharmony_ci		   0, 0, 0, 0, 0, 0} },
5318c2ecf20Sopenharmony_ci	{0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,   /* WRITE(6) */
5328c2ecf20Sopenharmony_ci	    NULL, {6,  0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
5338c2ecf20Sopenharmony_ci		   0, 0, 0} },
5348c2ecf20Sopenharmony_ci	{0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0,  /* WRITE(12) */
5358c2ecf20Sopenharmony_ci	    NULL, {12,  0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
5368c2ecf20Sopenharmony_ci		   0xbf, 0xc7, 0, 0, 0, 0} },
5378c2ecf20Sopenharmony_ci};
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic const struct opcode_info_t verify_iarr[] = {
5408c2ecf20Sopenharmony_ci	{0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */
5418c2ecf20Sopenharmony_ci	    NULL, {10,  0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7,
5428c2ecf20Sopenharmony_ci		   0, 0, 0, 0, 0, 0} },
5438c2ecf20Sopenharmony_ci};
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_cistatic const struct opcode_info_t sa_in_16_iarr[] = {
5468c2ecf20Sopenharmony_ci	{0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
5478c2ecf20Sopenharmony_ci	    {16,  0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
5488c2ecf20Sopenharmony_ci	     0xff, 0xff, 0xff, 0, 0xc7} },	/* GET LBA STATUS(16) */
5498c2ecf20Sopenharmony_ci};
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic const struct opcode_info_t vl_iarr[] = {	/* VARIABLE LENGTH */
5528c2ecf20Sopenharmony_ci	{0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
5538c2ecf20Sopenharmony_ci	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
5548c2ecf20Sopenharmony_ci		   0, 0xff, 0xff, 0xff, 0xff} },	/* WRITE(32) */
5558c2ecf20Sopenharmony_ci	{0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
5568c2ecf20Sopenharmony_ci	    NULL, {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
5578c2ecf20Sopenharmony_ci		   0, 0xff, 0xff, 0x0, 0x0} },	/* WRITE SCATTERED(32) */
5588c2ecf20Sopenharmony_ci};
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic const struct opcode_info_t maint_in_iarr[] = {	/* MAINT IN */
5618c2ecf20Sopenharmony_ci	{0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
5628c2ecf20Sopenharmony_ci	    {12,  0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
5638c2ecf20Sopenharmony_ci	     0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
5648c2ecf20Sopenharmony_ci	{0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
5658c2ecf20Sopenharmony_ci	    {12,  0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
5668c2ecf20Sopenharmony_ci	     0, 0} },	/* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
5678c2ecf20Sopenharmony_ci};
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic const struct opcode_info_t write_same_iarr[] = {
5708c2ecf20Sopenharmony_ci	{0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
5718c2ecf20Sopenharmony_ci	    {16,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
5728c2ecf20Sopenharmony_ci	     0xff, 0xff, 0xff, 0x3f, 0xc7} },		/* WRITE SAME(16) */
5738c2ecf20Sopenharmony_ci};
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic const struct opcode_info_t reserve_iarr[] = {
5768c2ecf20Sopenharmony_ci	{0, 0x16, 0, F_D_OUT, NULL, NULL,		/* RESERVE(6) */
5778c2ecf20Sopenharmony_ci	    {6,  0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
5788c2ecf20Sopenharmony_ci};
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cistatic const struct opcode_info_t release_iarr[] = {
5818c2ecf20Sopenharmony_ci	{0, 0x17, 0, F_D_OUT, NULL, NULL,		/* RELEASE(6) */
5828c2ecf20Sopenharmony_ci	    {6,  0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
5838c2ecf20Sopenharmony_ci};
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_cistatic const struct opcode_info_t sync_cache_iarr[] = {
5868c2ecf20Sopenharmony_ci	{0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
5878c2ecf20Sopenharmony_ci	    {16,  0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
5888c2ecf20Sopenharmony_ci	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* SYNC_CACHE (16) */
5898c2ecf20Sopenharmony_ci};
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic const struct opcode_info_t pre_fetch_iarr[] = {
5928c2ecf20Sopenharmony_ci	{0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL,
5938c2ecf20Sopenharmony_ci	    {16,  0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
5948c2ecf20Sopenharmony_ci	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },	/* PRE-FETCH (16) */
5958c2ecf20Sopenharmony_ci};
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic const struct opcode_info_t zone_out_iarr[] = {	/* ZONE OUT(16) */
5988c2ecf20Sopenharmony_ci	{0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL,
5998c2ecf20Sopenharmony_ci	    {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6008c2ecf20Sopenharmony_ci	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* CLOSE ZONE */
6018c2ecf20Sopenharmony_ci	{0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL,
6028c2ecf20Sopenharmony_ci	    {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6038c2ecf20Sopenharmony_ci	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },	/* FINISH ZONE */
6048c2ecf20Sopenharmony_ci	{0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL,
6058c2ecf20Sopenharmony_ci	    {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6068c2ecf20Sopenharmony_ci	     0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} },  /* RESET WRITE POINTER */
6078c2ecf20Sopenharmony_ci};
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic const struct opcode_info_t zone_in_iarr[] = {	/* ZONE IN(16) */
6108c2ecf20Sopenharmony_ci	{0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL,
6118c2ecf20Sopenharmony_ci	    {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6128c2ecf20Sopenharmony_ci	     0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */
6138c2ecf20Sopenharmony_ci};
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
6178c2ecf20Sopenharmony_ci * plus the terminating elements for logic that scans this table such as
6188c2ecf20Sopenharmony_ci * REPORT SUPPORTED OPERATION CODES. */
6198c2ecf20Sopenharmony_cistatic const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
6208c2ecf20Sopenharmony_ci/* 0 */
6218c2ecf20Sopenharmony_ci	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,	/* unknown opcodes */
6228c2ecf20Sopenharmony_ci	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6238c2ecf20Sopenharmony_ci	{0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
6248c2ecf20Sopenharmony_ci	    {6,  0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6258c2ecf20Sopenharmony_ci	{0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
6268c2ecf20Sopenharmony_ci	    {12,  0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
6278c2ecf20Sopenharmony_ci	     0, 0} },					/* REPORT LUNS */
6288c2ecf20Sopenharmony_ci	{0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
6298c2ecf20Sopenharmony_ci	    {6,  0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6308c2ecf20Sopenharmony_ci	{0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
6318c2ecf20Sopenharmony_ci	    {6,  0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6328c2ecf20Sopenharmony_ci/* 5 */
6338c2ecf20Sopenharmony_ci	{ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN,	/* MODE SENSE(10) */
6348c2ecf20Sopenharmony_ci	    resp_mode_sense, msense_iarr, {10,  0xf8, 0xff, 0xff, 0, 0, 0,
6358c2ecf20Sopenharmony_ci		0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
6368c2ecf20Sopenharmony_ci	{ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT,	/* MODE SELECT(10) */
6378c2ecf20Sopenharmony_ci	    resp_mode_select, mselect_iarr, {10,  0xf1, 0, 0, 0, 0, 0, 0xff,
6388c2ecf20Sopenharmony_ci		0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
6398c2ecf20Sopenharmony_ci	{0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,	/* LOG SENSE */
6408c2ecf20Sopenharmony_ci	    {10,  0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
6418c2ecf20Sopenharmony_ci	     0, 0, 0} },
6428c2ecf20Sopenharmony_ci	{0, 0x25, 0, F_D_IN, resp_readcap, NULL,    /* READ CAPACITY(10) */
6438c2ecf20Sopenharmony_ci	    {10,  0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
6448c2ecf20Sopenharmony_ci	     0, 0} },
6458c2ecf20Sopenharmony_ci	{ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
6468c2ecf20Sopenharmony_ci	    resp_read_dt0, read_iarr, {16,  0xfe, 0xff, 0xff, 0xff, 0xff,
6478c2ecf20Sopenharmony_ci	    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6488c2ecf20Sopenharmony_ci/* 10 */
6498c2ecf20Sopenharmony_ci	{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
6508c2ecf20Sopenharmony_ci	    resp_write_dt0, write_iarr,			/* WRITE(16) */
6518c2ecf20Sopenharmony_ci		{16,  0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6528c2ecf20Sopenharmony_ci		 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
6538c2ecf20Sopenharmony_ci	{0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
6548c2ecf20Sopenharmony_ci	    {6,  0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6558c2ecf20Sopenharmony_ci	{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
6568c2ecf20Sopenharmony_ci	    resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
6578c2ecf20Sopenharmony_ci		{16,  0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6588c2ecf20Sopenharmony_ci		 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
6598c2ecf20Sopenharmony_ci	{0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
6608c2ecf20Sopenharmony_ci	    NULL, {16,  0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
6618c2ecf20Sopenharmony_ci	    0xff, 0xff, 0xff, 0xff, 0xc7} },  /* SA_OUT(16), WRITE SCAT(16) */
6628c2ecf20Sopenharmony_ci	{ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
6638c2ecf20Sopenharmony_ci	    resp_report_tgtpgs,	/* MAINT IN, REPORT TARGET PORT GROUPS */
6648c2ecf20Sopenharmony_ci		maint_in_iarr, {12,  0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
6658c2ecf20Sopenharmony_ci				0xff, 0, 0xc7, 0, 0, 0, 0} },
6668c2ecf20Sopenharmony_ci/* 15 */
6678c2ecf20Sopenharmony_ci	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
6688c2ecf20Sopenharmony_ci	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6698c2ecf20Sopenharmony_ci	{ARRAY_SIZE(verify_iarr), 0x8f, 0,
6708c2ecf20Sopenharmony_ci	    F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,	/* VERIFY(16) */
6718c2ecf20Sopenharmony_ci	    verify_iarr, {16,  0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
6728c2ecf20Sopenharmony_ci			  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} },
6738c2ecf20Sopenharmony_ci	{ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
6748c2ecf20Sopenharmony_ci	    resp_read_dt0, vl_iarr,	/* VARIABLE LENGTH, READ(32) */
6758c2ecf20Sopenharmony_ci	    {32,  0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
6768c2ecf20Sopenharmony_ci	     0xff, 0xff} },
6778c2ecf20Sopenharmony_ci	{ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
6788c2ecf20Sopenharmony_ci	    NULL, reserve_iarr,	/* RESERVE(10) <no response function> */
6798c2ecf20Sopenharmony_ci	    {10,  0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
6808c2ecf20Sopenharmony_ci	     0} },
6818c2ecf20Sopenharmony_ci	{ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
6828c2ecf20Sopenharmony_ci	    NULL, release_iarr, /* RELEASE(10) <no response function> */
6838c2ecf20Sopenharmony_ci	    {10,  0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
6848c2ecf20Sopenharmony_ci	     0} },
6858c2ecf20Sopenharmony_ci/* 20 */
6868c2ecf20Sopenharmony_ci	{0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
6878c2ecf20Sopenharmony_ci	    {6,  0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6888c2ecf20Sopenharmony_ci	{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
6898c2ecf20Sopenharmony_ci	    {6,  0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6908c2ecf20Sopenharmony_ci	{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
6918c2ecf20Sopenharmony_ci	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6928c2ecf20Sopenharmony_ci	{0, 0x1d, F_D_OUT, 0, NULL, NULL,	/* SEND DIAGNOSTIC */
6938c2ecf20Sopenharmony_ci	    {6,  0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
6948c2ecf20Sopenharmony_ci	{0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
6958c2ecf20Sopenharmony_ci	    {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
6968c2ecf20Sopenharmony_ci/* 25 */
6978c2ecf20Sopenharmony_ci	{0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
6988c2ecf20Sopenharmony_ci	    {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
6998c2ecf20Sopenharmony_ci	     0, 0, 0, 0} },			/* WRITE_BUFFER */
7008c2ecf20Sopenharmony_ci	{ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
7018c2ecf20Sopenharmony_ci	    resp_write_same_10, write_same_iarr,	/* WRITE SAME(10) */
7028c2ecf20Sopenharmony_ci		{10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
7038c2ecf20Sopenharmony_ci		 0, 0, 0, 0, 0} },
7048c2ecf20Sopenharmony_ci	{ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
7058c2ecf20Sopenharmony_ci	    resp_sync_cache, sync_cache_iarr,
7068c2ecf20Sopenharmony_ci	    {10,  0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
7078c2ecf20Sopenharmony_ci	     0, 0, 0, 0} },			/* SYNC_CACHE (10) */
7088c2ecf20Sopenharmony_ci	{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
7098c2ecf20Sopenharmony_ci	    {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
7108c2ecf20Sopenharmony_ci	     0, 0xff, 0x3f, 0xc7} },		/* COMPARE AND WRITE */
7118c2ecf20Sopenharmony_ci	{ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO,
7128c2ecf20Sopenharmony_ci	    resp_pre_fetch, pre_fetch_iarr,
7138c2ecf20Sopenharmony_ci	    {10,  0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
7148c2ecf20Sopenharmony_ci	     0, 0, 0, 0} },			/* PRE-FETCH (10) */
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci/* 30 */
7178c2ecf20Sopenharmony_ci	{ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS,
7188c2ecf20Sopenharmony_ci	    resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */
7198c2ecf20Sopenharmony_ci		{16,  0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
7208c2ecf20Sopenharmony_ci		 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} },
7218c2ecf20Sopenharmony_ci	{ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS,
7228c2ecf20Sopenharmony_ci	    resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */
7238c2ecf20Sopenharmony_ci		{16,  0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
7248c2ecf20Sopenharmony_ci		 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} },
7258c2ecf20Sopenharmony_ci/* sentinel */
7268c2ecf20Sopenharmony_ci	{0xff, 0, 0, 0, NULL, NULL,		/* terminating element */
7278c2ecf20Sopenharmony_ci	    {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
7288c2ecf20Sopenharmony_ci};
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_cistatic int sdebug_num_hosts;
7318c2ecf20Sopenharmony_cistatic int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
7328c2ecf20Sopenharmony_cistatic int sdebug_ato = DEF_ATO;
7338c2ecf20Sopenharmony_cistatic int sdebug_cdb_len = DEF_CDB_LEN;
7348c2ecf20Sopenharmony_cistatic int sdebug_jdelay = DEF_JDELAY;	/* if > 0 then unit is jiffies */
7358c2ecf20Sopenharmony_cistatic int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT;
7368c2ecf20Sopenharmony_cistatic int sdebug_dif = DEF_DIF;
7378c2ecf20Sopenharmony_cistatic int sdebug_dix = DEF_DIX;
7388c2ecf20Sopenharmony_cistatic int sdebug_dsense = DEF_D_SENSE;
7398c2ecf20Sopenharmony_cistatic int sdebug_every_nth = DEF_EVERY_NTH;
7408c2ecf20Sopenharmony_cistatic int sdebug_fake_rw = DEF_FAKE_RW;
7418c2ecf20Sopenharmony_cistatic unsigned int sdebug_guard = DEF_GUARD;
7428c2ecf20Sopenharmony_cistatic int sdebug_host_max_queue;	/* per host */
7438c2ecf20Sopenharmony_cistatic int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
7448c2ecf20Sopenharmony_cistatic int sdebug_max_luns = DEF_MAX_LUNS;
7458c2ecf20Sopenharmony_cistatic int sdebug_max_queue = SDEBUG_CANQUEUE;	/* per submit queue */
7468c2ecf20Sopenharmony_cistatic unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
7478c2ecf20Sopenharmony_cistatic int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
7488c2ecf20Sopenharmony_cistatic atomic_t retired_max_queue;	/* if > 0 then was prior max_queue */
7498c2ecf20Sopenharmony_cistatic int sdebug_ndelay = DEF_NDELAY;	/* if > 0 then unit is nanoseconds */
7508c2ecf20Sopenharmony_cistatic int sdebug_no_lun_0 = DEF_NO_LUN_0;
7518c2ecf20Sopenharmony_cistatic int sdebug_no_uld;
7528c2ecf20Sopenharmony_cistatic int sdebug_num_parts = DEF_NUM_PARTS;
7538c2ecf20Sopenharmony_cistatic int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
7548c2ecf20Sopenharmony_cistatic int sdebug_opt_blks = DEF_OPT_BLKS;
7558c2ecf20Sopenharmony_cistatic int sdebug_opts = DEF_OPTS;
7568c2ecf20Sopenharmony_cistatic int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
7578c2ecf20Sopenharmony_cistatic int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
7588c2ecf20Sopenharmony_cistatic int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
7598c2ecf20Sopenharmony_cistatic int sdebug_scsi_level = DEF_SCSI_LEVEL;
7608c2ecf20Sopenharmony_cistatic int sdebug_sector_size = DEF_SECTOR_SIZE;
7618c2ecf20Sopenharmony_cistatic int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY;
7628c2ecf20Sopenharmony_cistatic int sdebug_virtual_gb = DEF_VIRTUAL_GB;
7638c2ecf20Sopenharmony_cistatic int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
7648c2ecf20Sopenharmony_cistatic unsigned int sdebug_lbpu = DEF_LBPU;
7658c2ecf20Sopenharmony_cistatic unsigned int sdebug_lbpws = DEF_LBPWS;
7668c2ecf20Sopenharmony_cistatic unsigned int sdebug_lbpws10 = DEF_LBPWS10;
7678c2ecf20Sopenharmony_cistatic unsigned int sdebug_lbprz = DEF_LBPRZ;
7688c2ecf20Sopenharmony_cistatic unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
7698c2ecf20Sopenharmony_cistatic unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
7708c2ecf20Sopenharmony_cistatic unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
7718c2ecf20Sopenharmony_cistatic unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
7728c2ecf20Sopenharmony_cistatic unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
7738c2ecf20Sopenharmony_cistatic int sdebug_uuid_ctl = DEF_UUID_CTL;
7748c2ecf20Sopenharmony_cistatic bool sdebug_random = DEF_RANDOM;
7758c2ecf20Sopenharmony_cistatic bool sdebug_per_host_store = DEF_PER_HOST_STORE;
7768c2ecf20Sopenharmony_cistatic bool sdebug_removable = DEF_REMOVABLE;
7778c2ecf20Sopenharmony_cistatic bool sdebug_clustering;
7788c2ecf20Sopenharmony_cistatic bool sdebug_host_lock = DEF_HOST_LOCK;
7798c2ecf20Sopenharmony_cistatic bool sdebug_strict = DEF_STRICT;
7808c2ecf20Sopenharmony_cistatic bool sdebug_any_injecting_opt;
7818c2ecf20Sopenharmony_cistatic bool sdebug_verbose;
7828c2ecf20Sopenharmony_cistatic bool have_dif_prot;
7838c2ecf20Sopenharmony_cistatic bool write_since_sync;
7848c2ecf20Sopenharmony_cistatic bool sdebug_statistics = DEF_STATISTICS;
7858c2ecf20Sopenharmony_cistatic bool sdebug_wp;
7868c2ecf20Sopenharmony_ci/* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */
7878c2ecf20Sopenharmony_cistatic enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE;
7888c2ecf20Sopenharmony_cistatic char *sdeb_zbc_model_s;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cienum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0,
7918c2ecf20Sopenharmony_ci			  SAM_LUN_AM_FLAT = 0x1,
7928c2ecf20Sopenharmony_ci			  SAM_LUN_AM_LOGICAL_UNIT = 0x2,
7938c2ecf20Sopenharmony_ci			  SAM_LUN_AM_EXTENDED = 0x3};
7948c2ecf20Sopenharmony_cistatic enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
7958c2ecf20Sopenharmony_cistatic int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic unsigned int sdebug_store_sectors;
7988c2ecf20Sopenharmony_cistatic sector_t sdebug_capacity;	/* in sectors */
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci/* old BIOS stuff, kernel may get rid of them but some mode sense pages
8018c2ecf20Sopenharmony_ci   may still need them */
8028c2ecf20Sopenharmony_cistatic int sdebug_heads;		/* heads per disk */
8038c2ecf20Sopenharmony_cistatic int sdebug_cylinders_per;	/* cylinders per surface */
8048c2ecf20Sopenharmony_cistatic int sdebug_sectors_per;		/* sectors per cylinder */
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_cistatic LIST_HEAD(sdebug_host_list);
8078c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(sdebug_host_list_lock);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_cistatic struct xarray per_store_arr;
8108c2ecf20Sopenharmony_cistatic struct xarray *per_store_ap = &per_store_arr;
8118c2ecf20Sopenharmony_cistatic int sdeb_first_idx = -1;		/* invalid index ==> none created */
8128c2ecf20Sopenharmony_cistatic int sdeb_most_recent_idx = -1;
8138c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(sdeb_fake_rw_lck);	/* need a RW lock when fake_rw=1 */
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_cistatic unsigned long map_size;
8168c2ecf20Sopenharmony_cistatic int num_aborts;
8178c2ecf20Sopenharmony_cistatic int num_dev_resets;
8188c2ecf20Sopenharmony_cistatic int num_target_resets;
8198c2ecf20Sopenharmony_cistatic int num_bus_resets;
8208c2ecf20Sopenharmony_cistatic int num_host_resets;
8218c2ecf20Sopenharmony_cistatic int dix_writes;
8228c2ecf20Sopenharmony_cistatic int dix_reads;
8238c2ecf20Sopenharmony_cistatic int dif_errors;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci/* ZBC global data */
8268c2ecf20Sopenharmony_cistatic bool sdeb_zbc_in_use;	/* true for host-aware and host-managed disks */
8278c2ecf20Sopenharmony_cistatic int sdeb_zbc_zone_size_mb;
8288c2ecf20Sopenharmony_cistatic int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
8298c2ecf20Sopenharmony_cistatic int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_cistatic int submit_queues = DEF_SUBMIT_QUEUES;  /* > 1 for multi-queue (mq) */
8328c2ecf20Sopenharmony_cistatic struct sdebug_queue *sdebug_q_arr;  /* ptr to array of submit queues */
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(atomic_rw);
8358c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(atomic_rw2);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic rwlock_t *ramdisk_lck_a[2];
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_cistatic char sdebug_proc_name[] = MY_NAME;
8408c2ecf20Sopenharmony_cistatic const char *my_name = MY_NAME;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_cistatic struct bus_type pseudo_lld_bus;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic struct device_driver sdebug_driverfs_driver = {
8458c2ecf20Sopenharmony_ci	.name 		= sdebug_proc_name,
8468c2ecf20Sopenharmony_ci	.bus		= &pseudo_lld_bus,
8478c2ecf20Sopenharmony_ci};
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic const int check_condition_result =
8508c2ecf20Sopenharmony_ci		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_cistatic const int illegal_condition_result =
8538c2ecf20Sopenharmony_ci	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_cistatic const int device_qfull_result =
8568c2ecf20Sopenharmony_ci	(DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic const int condition_met_result = SAM_STAT_CONDITION_MET;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci/* Only do the extra work involved in logical block provisioning if one or
8628c2ecf20Sopenharmony_ci * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
8638c2ecf20Sopenharmony_ci * real reads and writes (i.e. not skipping them for speed).
8648c2ecf20Sopenharmony_ci */
8658c2ecf20Sopenharmony_cistatic inline bool scsi_debug_lbp(void)
8668c2ecf20Sopenharmony_ci{
8678c2ecf20Sopenharmony_ci	return 0 == sdebug_fake_rw &&
8688c2ecf20Sopenharmony_ci		(sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_cistatic void *lba2fake_store(struct sdeb_store_info *sip,
8728c2ecf20Sopenharmony_ci			    unsigned long long lba)
8738c2ecf20Sopenharmony_ci{
8748c2ecf20Sopenharmony_ci	struct sdeb_store_info *lsip = sip;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	lba = do_div(lba, sdebug_store_sectors);
8778c2ecf20Sopenharmony_ci	if (!sip || !sip->storep) {
8788c2ecf20Sopenharmony_ci		WARN_ON_ONCE(true);
8798c2ecf20Sopenharmony_ci		lsip = xa_load(per_store_ap, 0);  /* should never be NULL */
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci	return lsip->storep + lba * sdebug_sector_size;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip,
8858c2ecf20Sopenharmony_ci				      sector_t sector)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	sector = sector_div(sector, sdebug_store_sectors);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	return sip->dif_storep + sector;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic void sdebug_max_tgts_luns(void)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
8958c2ecf20Sopenharmony_ci	struct Scsi_Host *hpnt;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	spin_lock(&sdebug_host_list_lock);
8988c2ecf20Sopenharmony_ci	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
8998c2ecf20Sopenharmony_ci		hpnt = sdbg_host->shost;
9008c2ecf20Sopenharmony_ci		if ((hpnt->this_id >= 0) &&
9018c2ecf20Sopenharmony_ci		    (sdebug_num_tgts > hpnt->this_id))
9028c2ecf20Sopenharmony_ci			hpnt->max_id = sdebug_num_tgts + 1;
9038c2ecf20Sopenharmony_ci		else
9048c2ecf20Sopenharmony_ci			hpnt->max_id = sdebug_num_tgts;
9058c2ecf20Sopenharmony_ci		/* sdebug_max_luns; */
9068c2ecf20Sopenharmony_ci		hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
9078c2ecf20Sopenharmony_ci	}
9088c2ecf20Sopenharmony_ci	spin_unlock(&sdebug_host_list_lock);
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_cienum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci/* Set in_bit to -1 to indicate no bit position of invalid field */
9148c2ecf20Sopenharmony_cistatic void mk_sense_invalid_fld(struct scsi_cmnd *scp,
9158c2ecf20Sopenharmony_ci				 enum sdeb_cmd_data c_d,
9168c2ecf20Sopenharmony_ci				 int in_byte, int in_bit)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	unsigned char *sbuff;
9198c2ecf20Sopenharmony_ci	u8 sks[4];
9208c2ecf20Sopenharmony_ci	int sl, asc;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	sbuff = scp->sense_buffer;
9238c2ecf20Sopenharmony_ci	if (!sbuff) {
9248c2ecf20Sopenharmony_ci		sdev_printk(KERN_ERR, scp->device,
9258c2ecf20Sopenharmony_ci			    "%s: sense_buffer is NULL\n", __func__);
9268c2ecf20Sopenharmony_ci		return;
9278c2ecf20Sopenharmony_ci	}
9288c2ecf20Sopenharmony_ci	asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
9298c2ecf20Sopenharmony_ci	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
9308c2ecf20Sopenharmony_ci	scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
9318c2ecf20Sopenharmony_ci	memset(sks, 0, sizeof(sks));
9328c2ecf20Sopenharmony_ci	sks[0] = 0x80;
9338c2ecf20Sopenharmony_ci	if (c_d)
9348c2ecf20Sopenharmony_ci		sks[0] |= 0x40;
9358c2ecf20Sopenharmony_ci	if (in_bit >= 0) {
9368c2ecf20Sopenharmony_ci		sks[0] |= 0x8;
9378c2ecf20Sopenharmony_ci		sks[0] |= 0x7 & in_bit;
9388c2ecf20Sopenharmony_ci	}
9398c2ecf20Sopenharmony_ci	put_unaligned_be16(in_byte, sks + 1);
9408c2ecf20Sopenharmony_ci	if (sdebug_dsense) {
9418c2ecf20Sopenharmony_ci		sl = sbuff[7] + 8;
9428c2ecf20Sopenharmony_ci		sbuff[7] = sl;
9438c2ecf20Sopenharmony_ci		sbuff[sl] = 0x2;
9448c2ecf20Sopenharmony_ci		sbuff[sl + 1] = 0x6;
9458c2ecf20Sopenharmony_ci		memcpy(sbuff + sl + 4, sks, 3);
9468c2ecf20Sopenharmony_ci	} else
9478c2ecf20Sopenharmony_ci		memcpy(sbuff + 15, sks, 3);
9488c2ecf20Sopenharmony_ci	if (sdebug_verbose)
9498c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, scp->device, "%s:  [sense_key,asc,ascq"
9508c2ecf20Sopenharmony_ci			    "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
9518c2ecf20Sopenharmony_ci			    my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	unsigned char *sbuff;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	sbuff = scp->sense_buffer;
9598c2ecf20Sopenharmony_ci	if (!sbuff) {
9608c2ecf20Sopenharmony_ci		sdev_printk(KERN_ERR, scp->device,
9618c2ecf20Sopenharmony_ci			    "%s: sense_buffer is NULL\n", __func__);
9628c2ecf20Sopenharmony_ci		return;
9638c2ecf20Sopenharmony_ci	}
9648c2ecf20Sopenharmony_ci	memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (sdebug_verbose)
9698c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, scp->device,
9708c2ecf20Sopenharmony_ci			    "%s:  [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
9718c2ecf20Sopenharmony_ci			    my_name, key, asc, asq);
9728c2ecf20Sopenharmony_ci}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_cistatic void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_cistatic int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
9808c2ecf20Sopenharmony_ci			    void __user *arg)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	if (sdebug_verbose) {
9838c2ecf20Sopenharmony_ci		if (0x1261 == cmd)
9848c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, dev,
9858c2ecf20Sopenharmony_ci				    "%s: BLKFLSBUF [0x1261]\n", __func__);
9868c2ecf20Sopenharmony_ci		else if (0x5331 == cmd)
9878c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, dev,
9888c2ecf20Sopenharmony_ci				    "%s: CDROM_GET_CAPABILITY [0x5331]\n",
9898c2ecf20Sopenharmony_ci				    __func__);
9908c2ecf20Sopenharmony_ci		else
9918c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
9928c2ecf20Sopenharmony_ci				    __func__, cmd);
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci	return -EINVAL;
9958c2ecf20Sopenharmony_ci	/* return -ENOTTY; // correct return but upsets fdisk */
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic void config_cdb_len(struct scsi_device *sdev)
9998c2ecf20Sopenharmony_ci{
10008c2ecf20Sopenharmony_ci	switch (sdebug_cdb_len) {
10018c2ecf20Sopenharmony_ci	case 6:	/* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
10028c2ecf20Sopenharmony_ci		sdev->use_10_for_rw = false;
10038c2ecf20Sopenharmony_ci		sdev->use_16_for_rw = false;
10048c2ecf20Sopenharmony_ci		sdev->use_10_for_ms = false;
10058c2ecf20Sopenharmony_ci		break;
10068c2ecf20Sopenharmony_ci	case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
10078c2ecf20Sopenharmony_ci		sdev->use_10_for_rw = true;
10088c2ecf20Sopenharmony_ci		sdev->use_16_for_rw = false;
10098c2ecf20Sopenharmony_ci		sdev->use_10_for_ms = false;
10108c2ecf20Sopenharmony_ci		break;
10118c2ecf20Sopenharmony_ci	case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
10128c2ecf20Sopenharmony_ci		sdev->use_10_for_rw = true;
10138c2ecf20Sopenharmony_ci		sdev->use_16_for_rw = false;
10148c2ecf20Sopenharmony_ci		sdev->use_10_for_ms = true;
10158c2ecf20Sopenharmony_ci		break;
10168c2ecf20Sopenharmony_ci	case 16:
10178c2ecf20Sopenharmony_ci		sdev->use_10_for_rw = false;
10188c2ecf20Sopenharmony_ci		sdev->use_16_for_rw = true;
10198c2ecf20Sopenharmony_ci		sdev->use_10_for_ms = true;
10208c2ecf20Sopenharmony_ci		break;
10218c2ecf20Sopenharmony_ci	case 32: /* No knobs to suggest this so same as 16 for now */
10228c2ecf20Sopenharmony_ci		sdev->use_10_for_rw = false;
10238c2ecf20Sopenharmony_ci		sdev->use_16_for_rw = true;
10248c2ecf20Sopenharmony_ci		sdev->use_10_for_ms = true;
10258c2ecf20Sopenharmony_ci		break;
10268c2ecf20Sopenharmony_ci	default:
10278c2ecf20Sopenharmony_ci		pr_warn("unexpected cdb_len=%d, force to 10\n",
10288c2ecf20Sopenharmony_ci			sdebug_cdb_len);
10298c2ecf20Sopenharmony_ci		sdev->use_10_for_rw = true;
10308c2ecf20Sopenharmony_ci		sdev->use_16_for_rw = false;
10318c2ecf20Sopenharmony_ci		sdev->use_10_for_ms = false;
10328c2ecf20Sopenharmony_ci		sdebug_cdb_len = 10;
10338c2ecf20Sopenharmony_ci		break;
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic void all_config_cdb_len(void)
10388c2ecf20Sopenharmony_ci{
10398c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
10408c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
10418c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	spin_lock(&sdebug_host_list_lock);
10448c2ecf20Sopenharmony_ci	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
10458c2ecf20Sopenharmony_ci		shost = sdbg_host->shost;
10468c2ecf20Sopenharmony_ci		shost_for_each_device(sdev, shost) {
10478c2ecf20Sopenharmony_ci			config_cdb_len(sdev);
10488c2ecf20Sopenharmony_ci		}
10498c2ecf20Sopenharmony_ci	}
10508c2ecf20Sopenharmony_ci	spin_unlock(&sdebug_host_list_lock);
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdhp;
10568c2ecf20Sopenharmony_ci	struct sdebug_dev_info *dp;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	spin_lock(&sdebug_host_list_lock);
10598c2ecf20Sopenharmony_ci	list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
10608c2ecf20Sopenharmony_ci		list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
10618c2ecf20Sopenharmony_ci			if ((devip->sdbg_host == dp->sdbg_host) &&
10628c2ecf20Sopenharmony_ci			    (devip->target == dp->target))
10638c2ecf20Sopenharmony_ci				clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
10648c2ecf20Sopenharmony_ci		}
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci	spin_unlock(&sdebug_host_list_lock);
10678c2ecf20Sopenharmony_ci}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_cistatic int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
10708c2ecf20Sopenharmony_ci{
10718c2ecf20Sopenharmony_ci	int k;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
10748c2ecf20Sopenharmony_ci	if (k != SDEBUG_NUM_UAS) {
10758c2ecf20Sopenharmony_ci		const char *cp = NULL;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci		switch (k) {
10788c2ecf20Sopenharmony_ci		case SDEBUG_UA_POR:
10798c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
10808c2ecf20Sopenharmony_ci					POWER_ON_RESET_ASCQ);
10818c2ecf20Sopenharmony_ci			if (sdebug_verbose)
10828c2ecf20Sopenharmony_ci				cp = "power on reset";
10838c2ecf20Sopenharmony_ci			break;
10848c2ecf20Sopenharmony_ci		case SDEBUG_UA_BUS_RESET:
10858c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
10868c2ecf20Sopenharmony_ci					BUS_RESET_ASCQ);
10878c2ecf20Sopenharmony_ci			if (sdebug_verbose)
10888c2ecf20Sopenharmony_ci				cp = "bus reset";
10898c2ecf20Sopenharmony_ci			break;
10908c2ecf20Sopenharmony_ci		case SDEBUG_UA_MODE_CHANGED:
10918c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
10928c2ecf20Sopenharmony_ci					MODE_CHANGED_ASCQ);
10938c2ecf20Sopenharmony_ci			if (sdebug_verbose)
10948c2ecf20Sopenharmony_ci				cp = "mode parameters changed";
10958c2ecf20Sopenharmony_ci			break;
10968c2ecf20Sopenharmony_ci		case SDEBUG_UA_CAPACITY_CHANGED:
10978c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
10988c2ecf20Sopenharmony_ci					CAPACITY_CHANGED_ASCQ);
10998c2ecf20Sopenharmony_ci			if (sdebug_verbose)
11008c2ecf20Sopenharmony_ci				cp = "capacity data changed";
11018c2ecf20Sopenharmony_ci			break;
11028c2ecf20Sopenharmony_ci		case SDEBUG_UA_MICROCODE_CHANGED:
11038c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, UNIT_ATTENTION,
11048c2ecf20Sopenharmony_ci					TARGET_CHANGED_ASC,
11058c2ecf20Sopenharmony_ci					MICROCODE_CHANGED_ASCQ);
11068c2ecf20Sopenharmony_ci			if (sdebug_verbose)
11078c2ecf20Sopenharmony_ci				cp = "microcode has been changed";
11088c2ecf20Sopenharmony_ci			break;
11098c2ecf20Sopenharmony_ci		case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
11108c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, UNIT_ATTENTION,
11118c2ecf20Sopenharmony_ci					TARGET_CHANGED_ASC,
11128c2ecf20Sopenharmony_ci					MICROCODE_CHANGED_WO_RESET_ASCQ);
11138c2ecf20Sopenharmony_ci			if (sdebug_verbose)
11148c2ecf20Sopenharmony_ci				cp = "microcode has been changed without reset";
11158c2ecf20Sopenharmony_ci			break;
11168c2ecf20Sopenharmony_ci		case SDEBUG_UA_LUNS_CHANGED:
11178c2ecf20Sopenharmony_ci			/*
11188c2ecf20Sopenharmony_ci			 * SPC-3 behavior is to report a UNIT ATTENTION with
11198c2ecf20Sopenharmony_ci			 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
11208c2ecf20Sopenharmony_ci			 * on the target, until a REPORT LUNS command is
11218c2ecf20Sopenharmony_ci			 * received.  SPC-4 behavior is to report it only once.
11228c2ecf20Sopenharmony_ci			 * NOTE:  sdebug_scsi_level does not use the same
11238c2ecf20Sopenharmony_ci			 * values as struct scsi_device->scsi_level.
11248c2ecf20Sopenharmony_ci			 */
11258c2ecf20Sopenharmony_ci			if (sdebug_scsi_level >= 6)	/* SPC-4 and above */
11268c2ecf20Sopenharmony_ci				clear_luns_changed_on_target(devip);
11278c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, UNIT_ATTENTION,
11288c2ecf20Sopenharmony_ci					TARGET_CHANGED_ASC,
11298c2ecf20Sopenharmony_ci					LUNS_CHANGED_ASCQ);
11308c2ecf20Sopenharmony_ci			if (sdebug_verbose)
11318c2ecf20Sopenharmony_ci				cp = "reported luns data has changed";
11328c2ecf20Sopenharmony_ci			break;
11338c2ecf20Sopenharmony_ci		default:
11348c2ecf20Sopenharmony_ci			pr_warn("unexpected unit attention code=%d\n", k);
11358c2ecf20Sopenharmony_ci			if (sdebug_verbose)
11368c2ecf20Sopenharmony_ci				cp = "unknown";
11378c2ecf20Sopenharmony_ci			break;
11388c2ecf20Sopenharmony_ci		}
11398c2ecf20Sopenharmony_ci		clear_bit(k, devip->uas_bm);
11408c2ecf20Sopenharmony_ci		if (sdebug_verbose)
11418c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, scp->device,
11428c2ecf20Sopenharmony_ci				   "%s reports: Unit attention: %s\n",
11438c2ecf20Sopenharmony_ci				   my_name, cp);
11448c2ecf20Sopenharmony_ci		return check_condition_result;
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci	return 0;
11478c2ecf20Sopenharmony_ci}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
11508c2ecf20Sopenharmony_cistatic int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11518c2ecf20Sopenharmony_ci				int arr_len)
11528c2ecf20Sopenharmony_ci{
11538c2ecf20Sopenharmony_ci	int act_len;
11548c2ecf20Sopenharmony_ci	struct scsi_data_buffer *sdb = &scp->sdb;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	if (!sdb->length)
11578c2ecf20Sopenharmony_ci		return 0;
11588c2ecf20Sopenharmony_ci	if (scp->sc_data_direction != DMA_FROM_DEVICE)
11598c2ecf20Sopenharmony_ci		return DID_ERROR << 16;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
11628c2ecf20Sopenharmony_ci				      arr, arr_len);
11638c2ecf20Sopenharmony_ci	scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
11698c2ecf20Sopenharmony_ci * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
11708c2ecf20Sopenharmony_ci * calls, not required to write in ascending offset order. Assumes resid
11718c2ecf20Sopenharmony_ci * set to scsi_bufflen() prior to any calls.
11728c2ecf20Sopenharmony_ci */
11738c2ecf20Sopenharmony_cistatic int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
11748c2ecf20Sopenharmony_ci				  int arr_len, unsigned int off_dst)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	unsigned int act_len, n;
11778c2ecf20Sopenharmony_ci	struct scsi_data_buffer *sdb = &scp->sdb;
11788c2ecf20Sopenharmony_ci	off_t skip = off_dst;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	if (sdb->length <= off_dst)
11818c2ecf20Sopenharmony_ci		return 0;
11828c2ecf20Sopenharmony_ci	if (scp->sc_data_direction != DMA_FROM_DEVICE)
11838c2ecf20Sopenharmony_ci		return DID_ERROR << 16;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
11868c2ecf20Sopenharmony_ci				       arr, arr_len, skip);
11878c2ecf20Sopenharmony_ci	pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
11888c2ecf20Sopenharmony_ci		 __func__, off_dst, scsi_bufflen(scp), act_len,
11898c2ecf20Sopenharmony_ci		 scsi_get_resid(scp));
11908c2ecf20Sopenharmony_ci	n = scsi_bufflen(scp) - (off_dst + act_len);
11918c2ecf20Sopenharmony_ci	scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n));
11928c2ecf20Sopenharmony_ci	return 0;
11938c2ecf20Sopenharmony_ci}
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
11968c2ecf20Sopenharmony_ci * 'arr' or -1 if error.
11978c2ecf20Sopenharmony_ci */
11988c2ecf20Sopenharmony_cistatic int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
11998c2ecf20Sopenharmony_ci			       int arr_len)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	if (!scsi_bufflen(scp))
12028c2ecf20Sopenharmony_ci		return 0;
12038c2ecf20Sopenharmony_ci	if (scp->sc_data_direction != DMA_TO_DEVICE)
12048c2ecf20Sopenharmony_ci		return -1;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	return scsi_sg_copy_to_buffer(scp, arr, arr_len);
12078c2ecf20Sopenharmony_ci}
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_cistatic char sdebug_inq_vendor_id[9] = "Linux   ";
12118c2ecf20Sopenharmony_cistatic char sdebug_inq_product_id[17] = "scsi_debug      ";
12128c2ecf20Sopenharmony_cistatic char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
12138c2ecf20Sopenharmony_ci/* Use some locally assigned NAAs for SAS addresses. */
12148c2ecf20Sopenharmony_cistatic const u64 naa3_comp_a = 0x3222222000000000ULL;
12158c2ecf20Sopenharmony_cistatic const u64 naa3_comp_b = 0x3333333000000000ULL;
12168c2ecf20Sopenharmony_cistatic const u64 naa3_comp_c = 0x3111111000000000ULL;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci/* Device identification VPD page. Returns number of bytes placed in arr */
12198c2ecf20Sopenharmony_cistatic int inquiry_vpd_83(unsigned char *arr, int port_group_id,
12208c2ecf20Sopenharmony_ci			  int target_dev_id, int dev_id_num,
12218c2ecf20Sopenharmony_ci			  const char *dev_id_str, int dev_id_str_len,
12228c2ecf20Sopenharmony_ci			  const uuid_t *lu_name)
12238c2ecf20Sopenharmony_ci{
12248c2ecf20Sopenharmony_ci	int num, port_a;
12258c2ecf20Sopenharmony_ci	char b[32];
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	port_a = target_dev_id + 1;
12288c2ecf20Sopenharmony_ci	/* T10 vendor identifier field format (faked) */
12298c2ecf20Sopenharmony_ci	arr[0] = 0x2;	/* ASCII */
12308c2ecf20Sopenharmony_ci	arr[1] = 0x1;
12318c2ecf20Sopenharmony_ci	arr[2] = 0x0;
12328c2ecf20Sopenharmony_ci	memcpy(&arr[4], sdebug_inq_vendor_id, 8);
12338c2ecf20Sopenharmony_ci	memcpy(&arr[12], sdebug_inq_product_id, 16);
12348c2ecf20Sopenharmony_ci	memcpy(&arr[28], dev_id_str, dev_id_str_len);
12358c2ecf20Sopenharmony_ci	num = 8 + 16 + dev_id_str_len;
12368c2ecf20Sopenharmony_ci	arr[3] = num;
12378c2ecf20Sopenharmony_ci	num += 4;
12388c2ecf20Sopenharmony_ci	if (dev_id_num >= 0) {
12398c2ecf20Sopenharmony_ci		if (sdebug_uuid_ctl) {
12408c2ecf20Sopenharmony_ci			/* Locally assigned UUID */
12418c2ecf20Sopenharmony_ci			arr[num++] = 0x1;  /* binary (not necessarily sas) */
12428c2ecf20Sopenharmony_ci			arr[num++] = 0xa;  /* PIV=0, lu, naa */
12438c2ecf20Sopenharmony_ci			arr[num++] = 0x0;
12448c2ecf20Sopenharmony_ci			arr[num++] = 0x12;
12458c2ecf20Sopenharmony_ci			arr[num++] = 0x10; /* uuid type=1, locally assigned */
12468c2ecf20Sopenharmony_ci			arr[num++] = 0x0;
12478c2ecf20Sopenharmony_ci			memcpy(arr + num, lu_name, 16);
12488c2ecf20Sopenharmony_ci			num += 16;
12498c2ecf20Sopenharmony_ci		} else {
12508c2ecf20Sopenharmony_ci			/* NAA-3, Logical unit identifier (binary) */
12518c2ecf20Sopenharmony_ci			arr[num++] = 0x1;  /* binary (not necessarily sas) */
12528c2ecf20Sopenharmony_ci			arr[num++] = 0x3;  /* PIV=0, lu, naa */
12538c2ecf20Sopenharmony_ci			arr[num++] = 0x0;
12548c2ecf20Sopenharmony_ci			arr[num++] = 0x8;
12558c2ecf20Sopenharmony_ci			put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
12568c2ecf20Sopenharmony_ci			num += 8;
12578c2ecf20Sopenharmony_ci		}
12588c2ecf20Sopenharmony_ci		/* Target relative port number */
12598c2ecf20Sopenharmony_ci		arr[num++] = 0x61;	/* proto=sas, binary */
12608c2ecf20Sopenharmony_ci		arr[num++] = 0x94;	/* PIV=1, target port, rel port */
12618c2ecf20Sopenharmony_ci		arr[num++] = 0x0;	/* reserved */
12628c2ecf20Sopenharmony_ci		arr[num++] = 0x4;	/* length */
12638c2ecf20Sopenharmony_ci		arr[num++] = 0x0;	/* reserved */
12648c2ecf20Sopenharmony_ci		arr[num++] = 0x0;	/* reserved */
12658c2ecf20Sopenharmony_ci		arr[num++] = 0x0;
12668c2ecf20Sopenharmony_ci		arr[num++] = 0x1;	/* relative port A */
12678c2ecf20Sopenharmony_ci	}
12688c2ecf20Sopenharmony_ci	/* NAA-3, Target port identifier */
12698c2ecf20Sopenharmony_ci	arr[num++] = 0x61;	/* proto=sas, binary */
12708c2ecf20Sopenharmony_ci	arr[num++] = 0x93;	/* piv=1, target port, naa */
12718c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
12728c2ecf20Sopenharmony_ci	arr[num++] = 0x8;
12738c2ecf20Sopenharmony_ci	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
12748c2ecf20Sopenharmony_ci	num += 8;
12758c2ecf20Sopenharmony_ci	/* NAA-3, Target port group identifier */
12768c2ecf20Sopenharmony_ci	arr[num++] = 0x61;	/* proto=sas, binary */
12778c2ecf20Sopenharmony_ci	arr[num++] = 0x95;	/* piv=1, target port group id */
12788c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
12798c2ecf20Sopenharmony_ci	arr[num++] = 0x4;
12808c2ecf20Sopenharmony_ci	arr[num++] = 0;
12818c2ecf20Sopenharmony_ci	arr[num++] = 0;
12828c2ecf20Sopenharmony_ci	put_unaligned_be16(port_group_id, arr + num);
12838c2ecf20Sopenharmony_ci	num += 2;
12848c2ecf20Sopenharmony_ci	/* NAA-3, Target device identifier */
12858c2ecf20Sopenharmony_ci	arr[num++] = 0x61;	/* proto=sas, binary */
12868c2ecf20Sopenharmony_ci	arr[num++] = 0xa3;	/* piv=1, target device, naa */
12878c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
12888c2ecf20Sopenharmony_ci	arr[num++] = 0x8;
12898c2ecf20Sopenharmony_ci	put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
12908c2ecf20Sopenharmony_ci	num += 8;
12918c2ecf20Sopenharmony_ci	/* SCSI name string: Target device identifier */
12928c2ecf20Sopenharmony_ci	arr[num++] = 0x63;	/* proto=sas, UTF-8 */
12938c2ecf20Sopenharmony_ci	arr[num++] = 0xa8;	/* piv=1, target device, SCSI name string */
12948c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
12958c2ecf20Sopenharmony_ci	arr[num++] = 24;
12968c2ecf20Sopenharmony_ci	memcpy(arr + num, "naa.32222220", 12);
12978c2ecf20Sopenharmony_ci	num += 12;
12988c2ecf20Sopenharmony_ci	snprintf(b, sizeof(b), "%08X", target_dev_id);
12998c2ecf20Sopenharmony_ci	memcpy(arr + num, b, 8);
13008c2ecf20Sopenharmony_ci	num += 8;
13018c2ecf20Sopenharmony_ci	memset(arr + num, 0, 4);
13028c2ecf20Sopenharmony_ci	num += 4;
13038c2ecf20Sopenharmony_ci	return num;
13048c2ecf20Sopenharmony_ci}
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_cistatic unsigned char vpd84_data[] = {
13078c2ecf20Sopenharmony_ci/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
13088c2ecf20Sopenharmony_ci    0x22,0x22,0x22,0x0,0xbb,0x1,
13098c2ecf20Sopenharmony_ci    0x22,0x22,0x22,0x0,0xbb,0x2,
13108c2ecf20Sopenharmony_ci};
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci/*  Software interface identification VPD page */
13138c2ecf20Sopenharmony_cistatic int inquiry_vpd_84(unsigned char *arr)
13148c2ecf20Sopenharmony_ci{
13158c2ecf20Sopenharmony_ci	memcpy(arr, vpd84_data, sizeof(vpd84_data));
13168c2ecf20Sopenharmony_ci	return sizeof(vpd84_data);
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci/* Management network addresses VPD page */
13208c2ecf20Sopenharmony_cistatic int inquiry_vpd_85(unsigned char *arr)
13218c2ecf20Sopenharmony_ci{
13228c2ecf20Sopenharmony_ci	int num = 0;
13238c2ecf20Sopenharmony_ci	const char *na1 = "https://www.kernel.org/config";
13248c2ecf20Sopenharmony_ci	const char *na2 = "http://www.kernel.org/log";
13258c2ecf20Sopenharmony_ci	int plen, olen;
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	arr[num++] = 0x1;	/* lu, storage config */
13288c2ecf20Sopenharmony_ci	arr[num++] = 0x0;	/* reserved */
13298c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
13308c2ecf20Sopenharmony_ci	olen = strlen(na1);
13318c2ecf20Sopenharmony_ci	plen = olen + 1;
13328c2ecf20Sopenharmony_ci	if (plen % 4)
13338c2ecf20Sopenharmony_ci		plen = ((plen / 4) + 1) * 4;
13348c2ecf20Sopenharmony_ci	arr[num++] = plen;	/* length, null termianted, padded */
13358c2ecf20Sopenharmony_ci	memcpy(arr + num, na1, olen);
13368c2ecf20Sopenharmony_ci	memset(arr + num + olen, 0, plen - olen);
13378c2ecf20Sopenharmony_ci	num += plen;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	arr[num++] = 0x4;	/* lu, logging */
13408c2ecf20Sopenharmony_ci	arr[num++] = 0x0;	/* reserved */
13418c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
13428c2ecf20Sopenharmony_ci	olen = strlen(na2);
13438c2ecf20Sopenharmony_ci	plen = olen + 1;
13448c2ecf20Sopenharmony_ci	if (plen % 4)
13458c2ecf20Sopenharmony_ci		plen = ((plen / 4) + 1) * 4;
13468c2ecf20Sopenharmony_ci	arr[num++] = plen;	/* length, null terminated, padded */
13478c2ecf20Sopenharmony_ci	memcpy(arr + num, na2, olen);
13488c2ecf20Sopenharmony_ci	memset(arr + num + olen, 0, plen - olen);
13498c2ecf20Sopenharmony_ci	num += plen;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	return num;
13528c2ecf20Sopenharmony_ci}
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci/* SCSI ports VPD page */
13558c2ecf20Sopenharmony_cistatic int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
13568c2ecf20Sopenharmony_ci{
13578c2ecf20Sopenharmony_ci	int num = 0;
13588c2ecf20Sopenharmony_ci	int port_a, port_b;
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ci	port_a = target_dev_id + 1;
13618c2ecf20Sopenharmony_ci	port_b = port_a + 1;
13628c2ecf20Sopenharmony_ci	arr[num++] = 0x0;	/* reserved */
13638c2ecf20Sopenharmony_ci	arr[num++] = 0x0;	/* reserved */
13648c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
13658c2ecf20Sopenharmony_ci	arr[num++] = 0x1;	/* relative port 1 (primary) */
13668c2ecf20Sopenharmony_ci	memset(arr + num, 0, 6);
13678c2ecf20Sopenharmony_ci	num += 6;
13688c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
13698c2ecf20Sopenharmony_ci	arr[num++] = 12;	/* length tp descriptor */
13708c2ecf20Sopenharmony_ci	/* naa-5 target port identifier (A) */
13718c2ecf20Sopenharmony_ci	arr[num++] = 0x61;	/* proto=sas, binary */
13728c2ecf20Sopenharmony_ci	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
13738c2ecf20Sopenharmony_ci	arr[num++] = 0x0;	/* reserved */
13748c2ecf20Sopenharmony_ci	arr[num++] = 0x8;	/* length */
13758c2ecf20Sopenharmony_ci	put_unaligned_be64(naa3_comp_a + port_a, arr + num);
13768c2ecf20Sopenharmony_ci	num += 8;
13778c2ecf20Sopenharmony_ci	arr[num++] = 0x0;	/* reserved */
13788c2ecf20Sopenharmony_ci	arr[num++] = 0x0;	/* reserved */
13798c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
13808c2ecf20Sopenharmony_ci	arr[num++] = 0x2;	/* relative port 2 (secondary) */
13818c2ecf20Sopenharmony_ci	memset(arr + num, 0, 6);
13828c2ecf20Sopenharmony_ci	num += 6;
13838c2ecf20Sopenharmony_ci	arr[num++] = 0x0;
13848c2ecf20Sopenharmony_ci	arr[num++] = 12;	/* length tp descriptor */
13858c2ecf20Sopenharmony_ci	/* naa-5 target port identifier (B) */
13868c2ecf20Sopenharmony_ci	arr[num++] = 0x61;	/* proto=sas, binary */
13878c2ecf20Sopenharmony_ci	arr[num++] = 0x93;	/* PIV=1, target port, NAA */
13888c2ecf20Sopenharmony_ci	arr[num++] = 0x0;	/* reserved */
13898c2ecf20Sopenharmony_ci	arr[num++] = 0x8;	/* length */
13908c2ecf20Sopenharmony_ci	put_unaligned_be64(naa3_comp_a + port_b, arr + num);
13918c2ecf20Sopenharmony_ci	num += 8;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	return num;
13948c2ecf20Sopenharmony_ci}
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_cistatic unsigned char vpd89_data[] = {
13988c2ecf20Sopenharmony_ci/* from 4th byte */ 0,0,0,0,
13998c2ecf20Sopenharmony_ci'l','i','n','u','x',' ',' ',' ',
14008c2ecf20Sopenharmony_ci'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
14018c2ecf20Sopenharmony_ci'1','2','3','4',
14028c2ecf20Sopenharmony_ci0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
14038c2ecf20Sopenharmony_ci0xec,0,0,0,
14048c2ecf20Sopenharmony_ci0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
14058c2ecf20Sopenharmony_ci0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
14068c2ecf20Sopenharmony_ci0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
14078c2ecf20Sopenharmony_ci0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
14088c2ecf20Sopenharmony_ci0x53,0x41,
14098c2ecf20Sopenharmony_ci0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
14108c2ecf20Sopenharmony_ci0x20,0x20,
14118c2ecf20Sopenharmony_ci0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
14128c2ecf20Sopenharmony_ci0x10,0x80,
14138c2ecf20Sopenharmony_ci0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
14148c2ecf20Sopenharmony_ci0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
14158c2ecf20Sopenharmony_ci0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
14168c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
14178c2ecf20Sopenharmony_ci0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
14188c2ecf20Sopenharmony_ci0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
14198c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
14208c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14218c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14228c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14238c2ecf20Sopenharmony_ci0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
14248c2ecf20Sopenharmony_ci0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
14258c2ecf20Sopenharmony_ci0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
14268c2ecf20Sopenharmony_ci0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
14278c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14288c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14298c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14308c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14318c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14328c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14338c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14348c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14358c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14368c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14378c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14388c2ecf20Sopenharmony_ci0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
14398c2ecf20Sopenharmony_ci};
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci/* ATA Information VPD page */
14428c2ecf20Sopenharmony_cistatic int inquiry_vpd_89(unsigned char *arr)
14438c2ecf20Sopenharmony_ci{
14448c2ecf20Sopenharmony_ci	memcpy(arr, vpd89_data, sizeof(vpd89_data));
14458c2ecf20Sopenharmony_ci	return sizeof(vpd89_data);
14468c2ecf20Sopenharmony_ci}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_cistatic unsigned char vpdb0_data[] = {
14508c2ecf20Sopenharmony_ci	/* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
14518c2ecf20Sopenharmony_ci	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14528c2ecf20Sopenharmony_ci	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14538c2ecf20Sopenharmony_ci	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
14548c2ecf20Sopenharmony_ci};
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci/* Block limits VPD page (SBC-3) */
14578c2ecf20Sopenharmony_cistatic int inquiry_vpd_b0(unsigned char *arr)
14588c2ecf20Sopenharmony_ci{
14598c2ecf20Sopenharmony_ci	unsigned int gran;
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	/* Optimal transfer length granularity */
14648c2ecf20Sopenharmony_ci	if (sdebug_opt_xferlen_exp != 0 &&
14658c2ecf20Sopenharmony_ci	    sdebug_physblk_exp < sdebug_opt_xferlen_exp)
14668c2ecf20Sopenharmony_ci		gran = 1 << sdebug_opt_xferlen_exp;
14678c2ecf20Sopenharmony_ci	else
14688c2ecf20Sopenharmony_ci		gran = 1 << sdebug_physblk_exp;
14698c2ecf20Sopenharmony_ci	put_unaligned_be16(gran, arr + 2);
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	/* Maximum Transfer Length */
14728c2ecf20Sopenharmony_ci	if (sdebug_store_sectors > 0x400)
14738c2ecf20Sopenharmony_ci		put_unaligned_be32(sdebug_store_sectors, arr + 4);
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	/* Optimal Transfer Length */
14768c2ecf20Sopenharmony_ci	put_unaligned_be32(sdebug_opt_blks, &arr[8]);
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	if (sdebug_lbpu) {
14798c2ecf20Sopenharmony_ci		/* Maximum Unmap LBA Count */
14808c2ecf20Sopenharmony_ci		put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci		/* Maximum Unmap Block Descriptor Count */
14838c2ecf20Sopenharmony_ci		put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
14848c2ecf20Sopenharmony_ci	}
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	/* Unmap Granularity Alignment */
14878c2ecf20Sopenharmony_ci	if (sdebug_unmap_alignment) {
14888c2ecf20Sopenharmony_ci		put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
14898c2ecf20Sopenharmony_ci		arr[28] |= 0x80; /* UGAVALID */
14908c2ecf20Sopenharmony_ci	}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	/* Optimal Unmap Granularity */
14938c2ecf20Sopenharmony_ci	put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	/* Maximum WRITE SAME Length */
14968c2ecf20Sopenharmony_ci	put_unaligned_be64(sdebug_write_same_length, &arr[32]);
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	return 0x3c; /* Mandatory page length for Logical Block Provisioning */
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	return sizeof(vpdb0_data);
15018c2ecf20Sopenharmony_ci}
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci/* Block device characteristics VPD page (SBC-3) */
15048c2ecf20Sopenharmony_cistatic int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr)
15058c2ecf20Sopenharmony_ci{
15068c2ecf20Sopenharmony_ci	memset(arr, 0, 0x3c);
15078c2ecf20Sopenharmony_ci	arr[0] = 0;
15088c2ecf20Sopenharmony_ci	arr[1] = 1;	/* non rotating medium (e.g. solid state) */
15098c2ecf20Sopenharmony_ci	arr[2] = 0;
15108c2ecf20Sopenharmony_ci	arr[3] = 5;	/* less than 1.8" */
15118c2ecf20Sopenharmony_ci	if (devip->zmodel == BLK_ZONED_HA)
15128c2ecf20Sopenharmony_ci		arr[4] = 1 << 4;	/* zoned field = 01b */
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	return 0x3c;
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci/* Logical block provisioning VPD page (SBC-4) */
15188c2ecf20Sopenharmony_cistatic int inquiry_vpd_b2(unsigned char *arr)
15198c2ecf20Sopenharmony_ci{
15208c2ecf20Sopenharmony_ci	memset(arr, 0, 0x4);
15218c2ecf20Sopenharmony_ci	arr[0] = 0;			/* threshold exponent */
15228c2ecf20Sopenharmony_ci	if (sdebug_lbpu)
15238c2ecf20Sopenharmony_ci		arr[1] = 1 << 7;
15248c2ecf20Sopenharmony_ci	if (sdebug_lbpws)
15258c2ecf20Sopenharmony_ci		arr[1] |= 1 << 6;
15268c2ecf20Sopenharmony_ci	if (sdebug_lbpws10)
15278c2ecf20Sopenharmony_ci		arr[1] |= 1 << 5;
15288c2ecf20Sopenharmony_ci	if (sdebug_lbprz && scsi_debug_lbp())
15298c2ecf20Sopenharmony_ci		arr[1] |= (sdebug_lbprz & 0x7) << 2;  /* sbc4r07 and later */
15308c2ecf20Sopenharmony_ci	/* anc_sup=0; dp=0 (no provisioning group descriptor) */
15318c2ecf20Sopenharmony_ci	/* minimum_percentage=0; provisioning_type=0 (unknown) */
15328c2ecf20Sopenharmony_ci	/* threshold_percentage=0 */
15338c2ecf20Sopenharmony_ci	return 0x4;
15348c2ecf20Sopenharmony_ci}
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci/* Zoned block device characteristics VPD page (ZBC mandatory) */
15378c2ecf20Sopenharmony_cistatic int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
15388c2ecf20Sopenharmony_ci{
15398c2ecf20Sopenharmony_ci	memset(arr, 0, 0x3c);
15408c2ecf20Sopenharmony_ci	arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */
15418c2ecf20Sopenharmony_ci	/*
15428c2ecf20Sopenharmony_ci	 * Set Optimal number of open sequential write preferred zones and
15438c2ecf20Sopenharmony_ci	 * Optimal number of non-sequentially written sequential write
15448c2ecf20Sopenharmony_ci	 * preferred zones fields to 'not reported' (0xffffffff). Leave other
15458c2ecf20Sopenharmony_ci	 * fields set to zero, apart from Max. number of open swrz_s field.
15468c2ecf20Sopenharmony_ci	 */
15478c2ecf20Sopenharmony_ci	put_unaligned_be32(0xffffffff, &arr[4]);
15488c2ecf20Sopenharmony_ci	put_unaligned_be32(0xffffffff, &arr[8]);
15498c2ecf20Sopenharmony_ci	if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open)
15508c2ecf20Sopenharmony_ci		put_unaligned_be32(devip->max_open, &arr[12]);
15518c2ecf20Sopenharmony_ci	else
15528c2ecf20Sopenharmony_ci		put_unaligned_be32(0xffffffff, &arr[12]);
15538c2ecf20Sopenharmony_ci	return 0x3c;
15548c2ecf20Sopenharmony_ci}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci#define SDEBUG_LONG_INQ_SZ 96
15578c2ecf20Sopenharmony_ci#define SDEBUG_MAX_INQ_ARR_SZ 584
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_cistatic int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
15608c2ecf20Sopenharmony_ci{
15618c2ecf20Sopenharmony_ci	unsigned char pq_pdt;
15628c2ecf20Sopenharmony_ci	unsigned char *arr;
15638c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
15648c2ecf20Sopenharmony_ci	u32 alloc_len, n;
15658c2ecf20Sopenharmony_ci	int ret;
15668c2ecf20Sopenharmony_ci	bool have_wlun, is_disk, is_zbc, is_disk_zbc;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	alloc_len = get_unaligned_be16(cmd + 3);
15698c2ecf20Sopenharmony_ci	arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
15708c2ecf20Sopenharmony_ci	if (! arr)
15718c2ecf20Sopenharmony_ci		return DID_REQUEUE << 16;
15728c2ecf20Sopenharmony_ci	is_disk = (sdebug_ptype == TYPE_DISK);
15738c2ecf20Sopenharmony_ci	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
15748c2ecf20Sopenharmony_ci	is_disk_zbc = (is_disk || is_zbc);
15758c2ecf20Sopenharmony_ci	have_wlun = scsi_is_wlun(scp->device->lun);
15768c2ecf20Sopenharmony_ci	if (have_wlun)
15778c2ecf20Sopenharmony_ci		pq_pdt = TYPE_WLUN;	/* present, wlun */
15788c2ecf20Sopenharmony_ci	else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
15798c2ecf20Sopenharmony_ci		pq_pdt = 0x7f;	/* not present, PQ=3, PDT=0x1f */
15808c2ecf20Sopenharmony_ci	else
15818c2ecf20Sopenharmony_ci		pq_pdt = (sdebug_ptype & 0x1f);
15828c2ecf20Sopenharmony_ci	arr[0] = pq_pdt;
15838c2ecf20Sopenharmony_ci	if (0x2 & cmd[1]) {  /* CMDDT bit set */
15848c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
15858c2ecf20Sopenharmony_ci		kfree(arr);
15868c2ecf20Sopenharmony_ci		return check_condition_result;
15878c2ecf20Sopenharmony_ci	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
15888c2ecf20Sopenharmony_ci		int lu_id_num, port_group_id, target_dev_id;
15898c2ecf20Sopenharmony_ci		u32 len;
15908c2ecf20Sopenharmony_ci		char lu_id_str[6];
15918c2ecf20Sopenharmony_ci		int host_no = devip->sdbg_host->shost->host_no;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci		port_group_id = (((host_no + 1) & 0x7f) << 8) +
15948c2ecf20Sopenharmony_ci		    (devip->channel & 0x7f);
15958c2ecf20Sopenharmony_ci		if (sdebug_vpd_use_hostno == 0)
15968c2ecf20Sopenharmony_ci			host_no = 0;
15978c2ecf20Sopenharmony_ci		lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
15988c2ecf20Sopenharmony_ci			    (devip->target * 1000) + devip->lun);
15998c2ecf20Sopenharmony_ci		target_dev_id = ((host_no + 1) * 2000) +
16008c2ecf20Sopenharmony_ci				 (devip->target * 1000) - 3;
16018c2ecf20Sopenharmony_ci		len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
16028c2ecf20Sopenharmony_ci		if (0 == cmd[2]) { /* supported vital product data pages */
16038c2ecf20Sopenharmony_ci			arr[1] = cmd[2];	/*sanity */
16048c2ecf20Sopenharmony_ci			n = 4;
16058c2ecf20Sopenharmony_ci			arr[n++] = 0x0;   /* this page */
16068c2ecf20Sopenharmony_ci			arr[n++] = 0x80;  /* unit serial number */
16078c2ecf20Sopenharmony_ci			arr[n++] = 0x83;  /* device identification */
16088c2ecf20Sopenharmony_ci			arr[n++] = 0x84;  /* software interface ident. */
16098c2ecf20Sopenharmony_ci			arr[n++] = 0x85;  /* management network addresses */
16108c2ecf20Sopenharmony_ci			arr[n++] = 0x86;  /* extended inquiry */
16118c2ecf20Sopenharmony_ci			arr[n++] = 0x87;  /* mode page policy */
16128c2ecf20Sopenharmony_ci			arr[n++] = 0x88;  /* SCSI ports */
16138c2ecf20Sopenharmony_ci			if (is_disk_zbc) {	  /* SBC or ZBC */
16148c2ecf20Sopenharmony_ci				arr[n++] = 0x89;  /* ATA information */
16158c2ecf20Sopenharmony_ci				arr[n++] = 0xb0;  /* Block limits */
16168c2ecf20Sopenharmony_ci				arr[n++] = 0xb1;  /* Block characteristics */
16178c2ecf20Sopenharmony_ci				if (is_disk)
16188c2ecf20Sopenharmony_ci					arr[n++] = 0xb2;  /* LB Provisioning */
16198c2ecf20Sopenharmony_ci				if (is_zbc)
16208c2ecf20Sopenharmony_ci					arr[n++] = 0xb6;  /* ZB dev. char. */
16218c2ecf20Sopenharmony_ci			}
16228c2ecf20Sopenharmony_ci			arr[3] = n - 4;	  /* number of supported VPD pages */
16238c2ecf20Sopenharmony_ci		} else if (0x80 == cmd[2]) { /* unit serial number */
16248c2ecf20Sopenharmony_ci			arr[1] = cmd[2];	/*sanity */
16258c2ecf20Sopenharmony_ci			arr[3] = len;
16268c2ecf20Sopenharmony_ci			memcpy(&arr[4], lu_id_str, len);
16278c2ecf20Sopenharmony_ci		} else if (0x83 == cmd[2]) { /* device identification */
16288c2ecf20Sopenharmony_ci			arr[1] = cmd[2];	/*sanity */
16298c2ecf20Sopenharmony_ci			arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
16308c2ecf20Sopenharmony_ci						target_dev_id, lu_id_num,
16318c2ecf20Sopenharmony_ci						lu_id_str, len,
16328c2ecf20Sopenharmony_ci						&devip->lu_name);
16338c2ecf20Sopenharmony_ci		} else if (0x84 == cmd[2]) { /* Software interface ident. */
16348c2ecf20Sopenharmony_ci			arr[1] = cmd[2];	/*sanity */
16358c2ecf20Sopenharmony_ci			arr[3] = inquiry_vpd_84(&arr[4]);
16368c2ecf20Sopenharmony_ci		} else if (0x85 == cmd[2]) { /* Management network addresses */
16378c2ecf20Sopenharmony_ci			arr[1] = cmd[2];	/*sanity */
16388c2ecf20Sopenharmony_ci			arr[3] = inquiry_vpd_85(&arr[4]);
16398c2ecf20Sopenharmony_ci		} else if (0x86 == cmd[2]) { /* extended inquiry */
16408c2ecf20Sopenharmony_ci			arr[1] = cmd[2];	/*sanity */
16418c2ecf20Sopenharmony_ci			arr[3] = 0x3c;	/* number of following entries */
16428c2ecf20Sopenharmony_ci			if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
16438c2ecf20Sopenharmony_ci				arr[4] = 0x4;	/* SPT: GRD_CHK:1 */
16448c2ecf20Sopenharmony_ci			else if (have_dif_prot)
16458c2ecf20Sopenharmony_ci				arr[4] = 0x5;   /* SPT: GRD_CHK:1, REF_CHK:1 */
16468c2ecf20Sopenharmony_ci			else
16478c2ecf20Sopenharmony_ci				arr[4] = 0x0;   /* no protection stuff */
16488c2ecf20Sopenharmony_ci			arr[5] = 0x7;   /* head of q, ordered + simple q's */
16498c2ecf20Sopenharmony_ci		} else if (0x87 == cmd[2]) { /* mode page policy */
16508c2ecf20Sopenharmony_ci			arr[1] = cmd[2];	/*sanity */
16518c2ecf20Sopenharmony_ci			arr[3] = 0x8;	/* number of following entries */
16528c2ecf20Sopenharmony_ci			arr[4] = 0x2;	/* disconnect-reconnect mp */
16538c2ecf20Sopenharmony_ci			arr[6] = 0x80;	/* mlus, shared */
16548c2ecf20Sopenharmony_ci			arr[8] = 0x18;	 /* protocol specific lu */
16558c2ecf20Sopenharmony_ci			arr[10] = 0x82;	 /* mlus, per initiator port */
16568c2ecf20Sopenharmony_ci		} else if (0x88 == cmd[2]) { /* SCSI Ports */
16578c2ecf20Sopenharmony_ci			arr[1] = cmd[2];	/*sanity */
16588c2ecf20Sopenharmony_ci			arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
16598c2ecf20Sopenharmony_ci		} else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */
16608c2ecf20Sopenharmony_ci			arr[1] = cmd[2];        /*sanity */
16618c2ecf20Sopenharmony_ci			n = inquiry_vpd_89(&arr[4]);
16628c2ecf20Sopenharmony_ci			put_unaligned_be16(n, arr + 2);
16638c2ecf20Sopenharmony_ci		} else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */
16648c2ecf20Sopenharmony_ci			arr[1] = cmd[2];        /*sanity */
16658c2ecf20Sopenharmony_ci			arr[3] = inquiry_vpd_b0(&arr[4]);
16668c2ecf20Sopenharmony_ci		} else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */
16678c2ecf20Sopenharmony_ci			arr[1] = cmd[2];        /*sanity */
16688c2ecf20Sopenharmony_ci			arr[3] = inquiry_vpd_b1(devip, &arr[4]);
16698c2ecf20Sopenharmony_ci		} else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
16708c2ecf20Sopenharmony_ci			arr[1] = cmd[2];        /*sanity */
16718c2ecf20Sopenharmony_ci			arr[3] = inquiry_vpd_b2(&arr[4]);
16728c2ecf20Sopenharmony_ci		} else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */
16738c2ecf20Sopenharmony_ci			arr[1] = cmd[2];        /*sanity */
16748c2ecf20Sopenharmony_ci			arr[3] = inquiry_vpd_b6(devip, &arr[4]);
16758c2ecf20Sopenharmony_ci		} else {
16768c2ecf20Sopenharmony_ci			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
16778c2ecf20Sopenharmony_ci			kfree(arr);
16788c2ecf20Sopenharmony_ci			return check_condition_result;
16798c2ecf20Sopenharmony_ci		}
16808c2ecf20Sopenharmony_ci		len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
16818c2ecf20Sopenharmony_ci		ret = fill_from_dev_buffer(scp, arr,
16828c2ecf20Sopenharmony_ci			    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
16838c2ecf20Sopenharmony_ci		kfree(arr);
16848c2ecf20Sopenharmony_ci		return ret;
16858c2ecf20Sopenharmony_ci	}
16868c2ecf20Sopenharmony_ci	/* drops through here for a standard inquiry */
16878c2ecf20Sopenharmony_ci	arr[1] = sdebug_removable ? 0x80 : 0;	/* Removable disk */
16888c2ecf20Sopenharmony_ci	arr[2] = sdebug_scsi_level;
16898c2ecf20Sopenharmony_ci	arr[3] = 2;    /* response_data_format==2 */
16908c2ecf20Sopenharmony_ci	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
16918c2ecf20Sopenharmony_ci	arr[5] = (int)have_dif_prot;	/* PROTECT bit */
16928c2ecf20Sopenharmony_ci	if (sdebug_vpd_use_hostno == 0)
16938c2ecf20Sopenharmony_ci		arr[5] |= 0x10; /* claim: implicit TPGS */
16948c2ecf20Sopenharmony_ci	arr[6] = 0x10; /* claim: MultiP */
16958c2ecf20Sopenharmony_ci	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
16968c2ecf20Sopenharmony_ci	arr[7] = 0xa; /* claim: LINKED + CMDQUE */
16978c2ecf20Sopenharmony_ci	memcpy(&arr[8], sdebug_inq_vendor_id, 8);
16988c2ecf20Sopenharmony_ci	memcpy(&arr[16], sdebug_inq_product_id, 16);
16998c2ecf20Sopenharmony_ci	memcpy(&arr[32], sdebug_inq_product_rev, 4);
17008c2ecf20Sopenharmony_ci	/* Use Vendor Specific area to place driver date in ASCII hex */
17018c2ecf20Sopenharmony_ci	memcpy(&arr[36], sdebug_version_date, 8);
17028c2ecf20Sopenharmony_ci	/* version descriptors (2 bytes each) follow */
17038c2ecf20Sopenharmony_ci	put_unaligned_be16(0xc0, arr + 58);   /* SAM-6 no version claimed */
17048c2ecf20Sopenharmony_ci	put_unaligned_be16(0x5c0, arr + 60);  /* SPC-5 no version claimed */
17058c2ecf20Sopenharmony_ci	n = 62;
17068c2ecf20Sopenharmony_ci	if (is_disk) {		/* SBC-4 no version claimed */
17078c2ecf20Sopenharmony_ci		put_unaligned_be16(0x600, arr + n);
17088c2ecf20Sopenharmony_ci		n += 2;
17098c2ecf20Sopenharmony_ci	} else if (sdebug_ptype == TYPE_TAPE) {	/* SSC-4 rev 3 */
17108c2ecf20Sopenharmony_ci		put_unaligned_be16(0x525, arr + n);
17118c2ecf20Sopenharmony_ci		n += 2;
17128c2ecf20Sopenharmony_ci	} else if (is_zbc) {	/* ZBC BSR INCITS 536 revision 05 */
17138c2ecf20Sopenharmony_ci		put_unaligned_be16(0x624, arr + n);
17148c2ecf20Sopenharmony_ci		n += 2;
17158c2ecf20Sopenharmony_ci	}
17168c2ecf20Sopenharmony_ci	put_unaligned_be16(0x2100, arr + n);	/* SPL-4 no version claimed */
17178c2ecf20Sopenharmony_ci	ret = fill_from_dev_buffer(scp, arr,
17188c2ecf20Sopenharmony_ci			    min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ));
17198c2ecf20Sopenharmony_ci	kfree(arr);
17208c2ecf20Sopenharmony_ci	return ret;
17218c2ecf20Sopenharmony_ci}
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci/* See resp_iec_m_pg() for how this data is manipulated */
17248c2ecf20Sopenharmony_cistatic unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
17258c2ecf20Sopenharmony_ci				   0, 0, 0x0, 0x0};
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_cistatic int resp_requests(struct scsi_cmnd *scp,
17288c2ecf20Sopenharmony_ci			 struct sdebug_dev_info *devip)
17298c2ecf20Sopenharmony_ci{
17308c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
17318c2ecf20Sopenharmony_ci	unsigned char arr[SCSI_SENSE_BUFFERSIZE];	/* assume >= 18 bytes */
17328c2ecf20Sopenharmony_ci	bool dsense = !!(cmd[1] & 1);
17338c2ecf20Sopenharmony_ci	u32 alloc_len = cmd[4];
17348c2ecf20Sopenharmony_ci	u32 len = 18;
17358c2ecf20Sopenharmony_ci	int stopped_state = atomic_read(&devip->stopped);
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	memset(arr, 0, sizeof(arr));
17388c2ecf20Sopenharmony_ci	if (stopped_state > 0) {	/* some "pollable" data [spc6r02: 5.12.2] */
17398c2ecf20Sopenharmony_ci		if (dsense) {
17408c2ecf20Sopenharmony_ci			arr[0] = 0x72;
17418c2ecf20Sopenharmony_ci			arr[1] = NOT_READY;
17428c2ecf20Sopenharmony_ci			arr[2] = LOGICAL_UNIT_NOT_READY;
17438c2ecf20Sopenharmony_ci			arr[3] = (stopped_state == 2) ? 0x1 : 0x2;
17448c2ecf20Sopenharmony_ci			len = 8;
17458c2ecf20Sopenharmony_ci		} else {
17468c2ecf20Sopenharmony_ci			arr[0] = 0x70;
17478c2ecf20Sopenharmony_ci			arr[2] = NOT_READY;		/* NO_SENSE in sense_key */
17488c2ecf20Sopenharmony_ci			arr[7] = 0xa;			/* 18 byte sense buffer */
17498c2ecf20Sopenharmony_ci			arr[12] = LOGICAL_UNIT_NOT_READY;
17508c2ecf20Sopenharmony_ci			arr[13] = (stopped_state == 2) ? 0x1 : 0x2;
17518c2ecf20Sopenharmony_ci		}
17528c2ecf20Sopenharmony_ci	} else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
17538c2ecf20Sopenharmony_ci		/* Information exceptions control mode page: TEST=1, MRIE=6 */
17548c2ecf20Sopenharmony_ci		if (dsense) {
17558c2ecf20Sopenharmony_ci			arr[0] = 0x72;
17568c2ecf20Sopenharmony_ci			arr[1] = 0x0;		/* NO_SENSE in sense_key */
17578c2ecf20Sopenharmony_ci			arr[2] = THRESHOLD_EXCEEDED;
17588c2ecf20Sopenharmony_ci			arr[3] = 0xff;		/* Failure prediction(false) */
17598c2ecf20Sopenharmony_ci			len = 8;
17608c2ecf20Sopenharmony_ci		} else {
17618c2ecf20Sopenharmony_ci			arr[0] = 0x70;
17628c2ecf20Sopenharmony_ci			arr[2] = 0x0;		/* NO_SENSE in sense_key */
17638c2ecf20Sopenharmony_ci			arr[7] = 0xa;   	/* 18 byte sense buffer */
17648c2ecf20Sopenharmony_ci			arr[12] = THRESHOLD_EXCEEDED;
17658c2ecf20Sopenharmony_ci			arr[13] = 0xff;		/* Failure prediction(false) */
17668c2ecf20Sopenharmony_ci		}
17678c2ecf20Sopenharmony_ci	} else {	/* nothing to report */
17688c2ecf20Sopenharmony_ci		if (dsense) {
17698c2ecf20Sopenharmony_ci			len = 8;
17708c2ecf20Sopenharmony_ci			memset(arr, 0, len);
17718c2ecf20Sopenharmony_ci			arr[0] = 0x72;
17728c2ecf20Sopenharmony_ci		} else {
17738c2ecf20Sopenharmony_ci			memset(arr, 0, len);
17748c2ecf20Sopenharmony_ci			arr[0] = 0x70;
17758c2ecf20Sopenharmony_ci			arr[7] = 0xa;
17768c2ecf20Sopenharmony_ci		}
17778c2ecf20Sopenharmony_ci	}
17788c2ecf20Sopenharmony_ci	return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len));
17798c2ecf20Sopenharmony_ci}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_cistatic int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
17828c2ecf20Sopenharmony_ci{
17838c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
17848c2ecf20Sopenharmony_ci	int power_cond, want_stop, stopped_state;
17858c2ecf20Sopenharmony_ci	bool changing;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	power_cond = (cmd[4] & 0xf0) >> 4;
17888c2ecf20Sopenharmony_ci	if (power_cond) {
17898c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
17908c2ecf20Sopenharmony_ci		return check_condition_result;
17918c2ecf20Sopenharmony_ci	}
17928c2ecf20Sopenharmony_ci	want_stop = !(cmd[4] & 1);
17938c2ecf20Sopenharmony_ci	stopped_state = atomic_read(&devip->stopped);
17948c2ecf20Sopenharmony_ci	if (stopped_state == 2) {
17958c2ecf20Sopenharmony_ci		ktime_t now_ts = ktime_get_boottime();
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
17988c2ecf20Sopenharmony_ci			u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
18018c2ecf20Sopenharmony_ci				/* tur_ms_to_ready timer extinguished */
18028c2ecf20Sopenharmony_ci				atomic_set(&devip->stopped, 0);
18038c2ecf20Sopenharmony_ci				stopped_state = 0;
18048c2ecf20Sopenharmony_ci			}
18058c2ecf20Sopenharmony_ci		}
18068c2ecf20Sopenharmony_ci		if (stopped_state == 2) {
18078c2ecf20Sopenharmony_ci			if (want_stop) {
18088c2ecf20Sopenharmony_ci				stopped_state = 1;	/* dummy up success */
18098c2ecf20Sopenharmony_ci			} else {	/* Disallow tur_ms_to_ready delay to be overridden */
18108c2ecf20Sopenharmony_ci				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */);
18118c2ecf20Sopenharmony_ci				return check_condition_result;
18128c2ecf20Sopenharmony_ci			}
18138c2ecf20Sopenharmony_ci		}
18148c2ecf20Sopenharmony_ci	}
18158c2ecf20Sopenharmony_ci	changing = (stopped_state != want_stop);
18168c2ecf20Sopenharmony_ci	if (changing)
18178c2ecf20Sopenharmony_ci		atomic_xchg(&devip->stopped, want_stop);
18188c2ecf20Sopenharmony_ci	if (!changing || (cmd[1] & 0x1))  /* state unchanged or IMMED bit set in cdb */
18198c2ecf20Sopenharmony_ci		return SDEG_RES_IMMED_MASK;
18208c2ecf20Sopenharmony_ci	else
18218c2ecf20Sopenharmony_ci		return 0;
18228c2ecf20Sopenharmony_ci}
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_cistatic sector_t get_sdebug_capacity(void)
18258c2ecf20Sopenharmony_ci{
18268c2ecf20Sopenharmony_ci	static const unsigned int gibibyte = 1073741824;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci	if (sdebug_virtual_gb > 0)
18298c2ecf20Sopenharmony_ci		return (sector_t)sdebug_virtual_gb *
18308c2ecf20Sopenharmony_ci			(gibibyte / sdebug_sector_size);
18318c2ecf20Sopenharmony_ci	else
18328c2ecf20Sopenharmony_ci		return sdebug_store_sectors;
18338c2ecf20Sopenharmony_ci}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci#define SDEBUG_READCAP_ARR_SZ 8
18368c2ecf20Sopenharmony_cistatic int resp_readcap(struct scsi_cmnd *scp,
18378c2ecf20Sopenharmony_ci			struct sdebug_dev_info *devip)
18388c2ecf20Sopenharmony_ci{
18398c2ecf20Sopenharmony_ci	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
18408c2ecf20Sopenharmony_ci	unsigned int capac;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	/* following just in case virtual_gb changed */
18438c2ecf20Sopenharmony_ci	sdebug_capacity = get_sdebug_capacity();
18448c2ecf20Sopenharmony_ci	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
18458c2ecf20Sopenharmony_ci	if (sdebug_capacity < 0xffffffff) {
18468c2ecf20Sopenharmony_ci		capac = (unsigned int)sdebug_capacity - 1;
18478c2ecf20Sopenharmony_ci		put_unaligned_be32(capac, arr + 0);
18488c2ecf20Sopenharmony_ci	} else
18498c2ecf20Sopenharmony_ci		put_unaligned_be32(0xffffffff, arr + 0);
18508c2ecf20Sopenharmony_ci	put_unaligned_be16(sdebug_sector_size, arr + 6);
18518c2ecf20Sopenharmony_ci	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
18528c2ecf20Sopenharmony_ci}
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci#define SDEBUG_READCAP16_ARR_SZ 32
18558c2ecf20Sopenharmony_cistatic int resp_readcap16(struct scsi_cmnd *scp,
18568c2ecf20Sopenharmony_ci			  struct sdebug_dev_info *devip)
18578c2ecf20Sopenharmony_ci{
18588c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
18598c2ecf20Sopenharmony_ci	unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
18608c2ecf20Sopenharmony_ci	u32 alloc_len;
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci	alloc_len = get_unaligned_be32(cmd + 10);
18638c2ecf20Sopenharmony_ci	/* following just in case virtual_gb changed */
18648c2ecf20Sopenharmony_ci	sdebug_capacity = get_sdebug_capacity();
18658c2ecf20Sopenharmony_ci	memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
18668c2ecf20Sopenharmony_ci	put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
18678c2ecf20Sopenharmony_ci	put_unaligned_be32(sdebug_sector_size, arr + 8);
18688c2ecf20Sopenharmony_ci	arr[13] = sdebug_physblk_exp & 0xf;
18698c2ecf20Sopenharmony_ci	arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	if (scsi_debug_lbp()) {
18728c2ecf20Sopenharmony_ci		arr[14] |= 0x80; /* LBPME */
18738c2ecf20Sopenharmony_ci		/* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
18748c2ecf20Sopenharmony_ci		 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
18758c2ecf20Sopenharmony_ci		 * in the wider field maps to 0 in this field.
18768c2ecf20Sopenharmony_ci		 */
18778c2ecf20Sopenharmony_ci		if (sdebug_lbprz & 1)	/* precisely what the draft requires */
18788c2ecf20Sopenharmony_ci			arr[14] |= 0x40;
18798c2ecf20Sopenharmony_ci	}
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	/*
18828c2ecf20Sopenharmony_ci	 * Since the scsi_debug READ CAPACITY implementation always reports the
18838c2ecf20Sopenharmony_ci	 * total disk capacity, set RC BASIS = 1 for host-managed ZBC devices.
18848c2ecf20Sopenharmony_ci	 */
18858c2ecf20Sopenharmony_ci	if (devip->zmodel == BLK_ZONED_HM)
18868c2ecf20Sopenharmony_ci		arr[12] |= 1 << 4;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	arr[15] = sdebug_lowest_aligned & 0xff;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	if (have_dif_prot) {
18918c2ecf20Sopenharmony_ci		arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
18928c2ecf20Sopenharmony_ci		arr[12] |= 1; /* PROT_EN */
18938c2ecf20Sopenharmony_ci	}
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	return fill_from_dev_buffer(scp, arr,
18968c2ecf20Sopenharmony_ci			    min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ));
18978c2ecf20Sopenharmony_ci}
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_cistatic int resp_report_tgtpgs(struct scsi_cmnd *scp,
19028c2ecf20Sopenharmony_ci			      struct sdebug_dev_info *devip)
19038c2ecf20Sopenharmony_ci{
19048c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
19058c2ecf20Sopenharmony_ci	unsigned char *arr;
19068c2ecf20Sopenharmony_ci	int host_no = devip->sdbg_host->shost->host_no;
19078c2ecf20Sopenharmony_ci	int port_group_a, port_group_b, port_a, port_b;
19088c2ecf20Sopenharmony_ci	u32 alen, n, rlen;
19098c2ecf20Sopenharmony_ci	int ret;
19108c2ecf20Sopenharmony_ci
19118c2ecf20Sopenharmony_ci	alen = get_unaligned_be32(cmd + 6);
19128c2ecf20Sopenharmony_ci	arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
19138c2ecf20Sopenharmony_ci	if (! arr)
19148c2ecf20Sopenharmony_ci		return DID_REQUEUE << 16;
19158c2ecf20Sopenharmony_ci	/*
19168c2ecf20Sopenharmony_ci	 * EVPD page 0x88 states we have two ports, one
19178c2ecf20Sopenharmony_ci	 * real and a fake port with no device connected.
19188c2ecf20Sopenharmony_ci	 * So we create two port groups with one port each
19198c2ecf20Sopenharmony_ci	 * and set the group with port B to unavailable.
19208c2ecf20Sopenharmony_ci	 */
19218c2ecf20Sopenharmony_ci	port_a = 0x1; /* relative port A */
19228c2ecf20Sopenharmony_ci	port_b = 0x2; /* relative port B */
19238c2ecf20Sopenharmony_ci	port_group_a = (((host_no + 1) & 0x7f) << 8) +
19248c2ecf20Sopenharmony_ci			(devip->channel & 0x7f);
19258c2ecf20Sopenharmony_ci	port_group_b = (((host_no + 1) & 0x7f) << 8) +
19268c2ecf20Sopenharmony_ci			(devip->channel & 0x7f) + 0x80;
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	/*
19298c2ecf20Sopenharmony_ci	 * The asymmetric access state is cycled according to the host_id.
19308c2ecf20Sopenharmony_ci	 */
19318c2ecf20Sopenharmony_ci	n = 4;
19328c2ecf20Sopenharmony_ci	if (sdebug_vpd_use_hostno == 0) {
19338c2ecf20Sopenharmony_ci		arr[n++] = host_no % 3; /* Asymm access state */
19348c2ecf20Sopenharmony_ci		arr[n++] = 0x0F; /* claim: all states are supported */
19358c2ecf20Sopenharmony_ci	} else {
19368c2ecf20Sopenharmony_ci		arr[n++] = 0x0; /* Active/Optimized path */
19378c2ecf20Sopenharmony_ci		arr[n++] = 0x01; /* only support active/optimized paths */
19388c2ecf20Sopenharmony_ci	}
19398c2ecf20Sopenharmony_ci	put_unaligned_be16(port_group_a, arr + n);
19408c2ecf20Sopenharmony_ci	n += 2;
19418c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Reserved */
19428c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Status code */
19438c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Vendor unique */
19448c2ecf20Sopenharmony_ci	arr[n++] = 0x1;  /* One port per group */
19458c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Reserved */
19468c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Reserved */
19478c2ecf20Sopenharmony_ci	put_unaligned_be16(port_a, arr + n);
19488c2ecf20Sopenharmony_ci	n += 2;
19498c2ecf20Sopenharmony_ci	arr[n++] = 3;    /* Port unavailable */
19508c2ecf20Sopenharmony_ci	arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
19518c2ecf20Sopenharmony_ci	put_unaligned_be16(port_group_b, arr + n);
19528c2ecf20Sopenharmony_ci	n += 2;
19538c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Reserved */
19548c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Status code */
19558c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Vendor unique */
19568c2ecf20Sopenharmony_ci	arr[n++] = 0x1;  /* One port per group */
19578c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Reserved */
19588c2ecf20Sopenharmony_ci	arr[n++] = 0;    /* Reserved */
19598c2ecf20Sopenharmony_ci	put_unaligned_be16(port_b, arr + n);
19608c2ecf20Sopenharmony_ci	n += 2;
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci	rlen = n - 4;
19638c2ecf20Sopenharmony_ci	put_unaligned_be32(rlen, arr + 0);
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	/*
19668c2ecf20Sopenharmony_ci	 * Return the smallest value of either
19678c2ecf20Sopenharmony_ci	 * - The allocated length
19688c2ecf20Sopenharmony_ci	 * - The constructed command length
19698c2ecf20Sopenharmony_ci	 * - The maximum array size
19708c2ecf20Sopenharmony_ci	 */
19718c2ecf20Sopenharmony_ci	rlen = min(alen, n);
19728c2ecf20Sopenharmony_ci	ret = fill_from_dev_buffer(scp, arr,
19738c2ecf20Sopenharmony_ci			   min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
19748c2ecf20Sopenharmony_ci	kfree(arr);
19758c2ecf20Sopenharmony_ci	return ret;
19768c2ecf20Sopenharmony_ci}
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_cistatic int resp_rsup_opcodes(struct scsi_cmnd *scp,
19798c2ecf20Sopenharmony_ci			     struct sdebug_dev_info *devip)
19808c2ecf20Sopenharmony_ci{
19818c2ecf20Sopenharmony_ci	bool rctd;
19828c2ecf20Sopenharmony_ci	u8 reporting_opts, req_opcode, sdeb_i, supp;
19838c2ecf20Sopenharmony_ci	u16 req_sa, u;
19848c2ecf20Sopenharmony_ci	u32 alloc_len, a_len;
19858c2ecf20Sopenharmony_ci	int k, offset, len, errsts, count, bump, na;
19868c2ecf20Sopenharmony_ci	const struct opcode_info_t *oip;
19878c2ecf20Sopenharmony_ci	const struct opcode_info_t *r_oip;
19888c2ecf20Sopenharmony_ci	u8 *arr;
19898c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	rctd = !!(cmd[2] & 0x80);
19928c2ecf20Sopenharmony_ci	reporting_opts = cmd[2] & 0x7;
19938c2ecf20Sopenharmony_ci	req_opcode = cmd[3];
19948c2ecf20Sopenharmony_ci	req_sa = get_unaligned_be16(cmd + 4);
19958c2ecf20Sopenharmony_ci	alloc_len = get_unaligned_be32(cmd + 6);
19968c2ecf20Sopenharmony_ci	if (alloc_len < 4 || alloc_len > 0xffff) {
19978c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
19988c2ecf20Sopenharmony_ci		return check_condition_result;
19998c2ecf20Sopenharmony_ci	}
20008c2ecf20Sopenharmony_ci	if (alloc_len > 8192)
20018c2ecf20Sopenharmony_ci		a_len = 8192;
20028c2ecf20Sopenharmony_ci	else
20038c2ecf20Sopenharmony_ci		a_len = alloc_len;
20048c2ecf20Sopenharmony_ci	arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
20058c2ecf20Sopenharmony_ci	if (NULL == arr) {
20068c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
20078c2ecf20Sopenharmony_ci				INSUFF_RES_ASCQ);
20088c2ecf20Sopenharmony_ci		return check_condition_result;
20098c2ecf20Sopenharmony_ci	}
20108c2ecf20Sopenharmony_ci	switch (reporting_opts) {
20118c2ecf20Sopenharmony_ci	case 0:	/* all commands */
20128c2ecf20Sopenharmony_ci		/* count number of commands */
20138c2ecf20Sopenharmony_ci		for (count = 0, oip = opcode_info_arr;
20148c2ecf20Sopenharmony_ci		     oip->num_attached != 0xff; ++oip) {
20158c2ecf20Sopenharmony_ci			if (F_INV_OP & oip->flags)
20168c2ecf20Sopenharmony_ci				continue;
20178c2ecf20Sopenharmony_ci			count += (oip->num_attached + 1);
20188c2ecf20Sopenharmony_ci		}
20198c2ecf20Sopenharmony_ci		bump = rctd ? 20 : 8;
20208c2ecf20Sopenharmony_ci		put_unaligned_be32(count * bump, arr);
20218c2ecf20Sopenharmony_ci		for (offset = 4, oip = opcode_info_arr;
20228c2ecf20Sopenharmony_ci		     oip->num_attached != 0xff && offset < a_len; ++oip) {
20238c2ecf20Sopenharmony_ci			if (F_INV_OP & oip->flags)
20248c2ecf20Sopenharmony_ci				continue;
20258c2ecf20Sopenharmony_ci			na = oip->num_attached;
20268c2ecf20Sopenharmony_ci			arr[offset] = oip->opcode;
20278c2ecf20Sopenharmony_ci			put_unaligned_be16(oip->sa, arr + offset + 2);
20288c2ecf20Sopenharmony_ci			if (rctd)
20298c2ecf20Sopenharmony_ci				arr[offset + 5] |= 0x2;
20308c2ecf20Sopenharmony_ci			if (FF_SA & oip->flags)
20318c2ecf20Sopenharmony_ci				arr[offset + 5] |= 0x1;
20328c2ecf20Sopenharmony_ci			put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
20338c2ecf20Sopenharmony_ci			if (rctd)
20348c2ecf20Sopenharmony_ci				put_unaligned_be16(0xa, arr + offset + 8);
20358c2ecf20Sopenharmony_ci			r_oip = oip;
20368c2ecf20Sopenharmony_ci			for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
20378c2ecf20Sopenharmony_ci				if (F_INV_OP & oip->flags)
20388c2ecf20Sopenharmony_ci					continue;
20398c2ecf20Sopenharmony_ci				offset += bump;
20408c2ecf20Sopenharmony_ci				arr[offset] = oip->opcode;
20418c2ecf20Sopenharmony_ci				put_unaligned_be16(oip->sa, arr + offset + 2);
20428c2ecf20Sopenharmony_ci				if (rctd)
20438c2ecf20Sopenharmony_ci					arr[offset + 5] |= 0x2;
20448c2ecf20Sopenharmony_ci				if (FF_SA & oip->flags)
20458c2ecf20Sopenharmony_ci					arr[offset + 5] |= 0x1;
20468c2ecf20Sopenharmony_ci				put_unaligned_be16(oip->len_mask[0],
20478c2ecf20Sopenharmony_ci						   arr + offset + 6);
20488c2ecf20Sopenharmony_ci				if (rctd)
20498c2ecf20Sopenharmony_ci					put_unaligned_be16(0xa,
20508c2ecf20Sopenharmony_ci							   arr + offset + 8);
20518c2ecf20Sopenharmony_ci			}
20528c2ecf20Sopenharmony_ci			oip = r_oip;
20538c2ecf20Sopenharmony_ci			offset += bump;
20548c2ecf20Sopenharmony_ci		}
20558c2ecf20Sopenharmony_ci		break;
20568c2ecf20Sopenharmony_ci	case 1:	/* one command: opcode only */
20578c2ecf20Sopenharmony_ci	case 2:	/* one command: opcode plus service action */
20588c2ecf20Sopenharmony_ci	case 3:	/* one command: if sa==0 then opcode only else opcode+sa */
20598c2ecf20Sopenharmony_ci		sdeb_i = opcode_ind_arr[req_opcode];
20608c2ecf20Sopenharmony_ci		oip = &opcode_info_arr[sdeb_i];
20618c2ecf20Sopenharmony_ci		if (F_INV_OP & oip->flags) {
20628c2ecf20Sopenharmony_ci			supp = 1;
20638c2ecf20Sopenharmony_ci			offset = 4;
20648c2ecf20Sopenharmony_ci		} else {
20658c2ecf20Sopenharmony_ci			if (1 == reporting_opts) {
20668c2ecf20Sopenharmony_ci				if (FF_SA & oip->flags) {
20678c2ecf20Sopenharmony_ci					mk_sense_invalid_fld(scp, SDEB_IN_CDB,
20688c2ecf20Sopenharmony_ci							     2, 2);
20698c2ecf20Sopenharmony_ci					kfree(arr);
20708c2ecf20Sopenharmony_ci					return check_condition_result;
20718c2ecf20Sopenharmony_ci				}
20728c2ecf20Sopenharmony_ci				req_sa = 0;
20738c2ecf20Sopenharmony_ci			} else if (2 == reporting_opts &&
20748c2ecf20Sopenharmony_ci				   0 == (FF_SA & oip->flags)) {
20758c2ecf20Sopenharmony_ci				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
20768c2ecf20Sopenharmony_ci				kfree(arr);	/* point at requested sa */
20778c2ecf20Sopenharmony_ci				return check_condition_result;
20788c2ecf20Sopenharmony_ci			}
20798c2ecf20Sopenharmony_ci			if (0 == (FF_SA & oip->flags) &&
20808c2ecf20Sopenharmony_ci			    req_opcode == oip->opcode)
20818c2ecf20Sopenharmony_ci				supp = 3;
20828c2ecf20Sopenharmony_ci			else if (0 == (FF_SA & oip->flags)) {
20838c2ecf20Sopenharmony_ci				na = oip->num_attached;
20848c2ecf20Sopenharmony_ci				for (k = 0, oip = oip->arrp; k < na;
20858c2ecf20Sopenharmony_ci				     ++k, ++oip) {
20868c2ecf20Sopenharmony_ci					if (req_opcode == oip->opcode)
20878c2ecf20Sopenharmony_ci						break;
20888c2ecf20Sopenharmony_ci				}
20898c2ecf20Sopenharmony_ci				supp = (k >= na) ? 1 : 3;
20908c2ecf20Sopenharmony_ci			} else if (req_sa != oip->sa) {
20918c2ecf20Sopenharmony_ci				na = oip->num_attached;
20928c2ecf20Sopenharmony_ci				for (k = 0, oip = oip->arrp; k < na;
20938c2ecf20Sopenharmony_ci				     ++k, ++oip) {
20948c2ecf20Sopenharmony_ci					if (req_sa == oip->sa)
20958c2ecf20Sopenharmony_ci						break;
20968c2ecf20Sopenharmony_ci				}
20978c2ecf20Sopenharmony_ci				supp = (k >= na) ? 1 : 3;
20988c2ecf20Sopenharmony_ci			} else
20998c2ecf20Sopenharmony_ci				supp = 3;
21008c2ecf20Sopenharmony_ci			if (3 == supp) {
21018c2ecf20Sopenharmony_ci				u = oip->len_mask[0];
21028c2ecf20Sopenharmony_ci				put_unaligned_be16(u, arr + 2);
21038c2ecf20Sopenharmony_ci				arr[4] = oip->opcode;
21048c2ecf20Sopenharmony_ci				for (k = 1; k < u; ++k)
21058c2ecf20Sopenharmony_ci					arr[4 + k] = (k < 16) ?
21068c2ecf20Sopenharmony_ci						 oip->len_mask[k] : 0xff;
21078c2ecf20Sopenharmony_ci				offset = 4 + u;
21088c2ecf20Sopenharmony_ci			} else
21098c2ecf20Sopenharmony_ci				offset = 4;
21108c2ecf20Sopenharmony_ci		}
21118c2ecf20Sopenharmony_ci		arr[1] = (rctd ? 0x80 : 0) | supp;
21128c2ecf20Sopenharmony_ci		if (rctd) {
21138c2ecf20Sopenharmony_ci			put_unaligned_be16(0xa, arr + offset);
21148c2ecf20Sopenharmony_ci			offset += 12;
21158c2ecf20Sopenharmony_ci		}
21168c2ecf20Sopenharmony_ci		break;
21178c2ecf20Sopenharmony_ci	default:
21188c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
21198c2ecf20Sopenharmony_ci		kfree(arr);
21208c2ecf20Sopenharmony_ci		return check_condition_result;
21218c2ecf20Sopenharmony_ci	}
21228c2ecf20Sopenharmony_ci	offset = (offset < a_len) ? offset : a_len;
21238c2ecf20Sopenharmony_ci	len = (offset < alloc_len) ? offset : alloc_len;
21248c2ecf20Sopenharmony_ci	errsts = fill_from_dev_buffer(scp, arr, len);
21258c2ecf20Sopenharmony_ci	kfree(arr);
21268c2ecf20Sopenharmony_ci	return errsts;
21278c2ecf20Sopenharmony_ci}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_cistatic int resp_rsup_tmfs(struct scsi_cmnd *scp,
21308c2ecf20Sopenharmony_ci			  struct sdebug_dev_info *devip)
21318c2ecf20Sopenharmony_ci{
21328c2ecf20Sopenharmony_ci	bool repd;
21338c2ecf20Sopenharmony_ci	u32 alloc_len, len;
21348c2ecf20Sopenharmony_ci	u8 arr[16];
21358c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	memset(arr, 0, sizeof(arr));
21388c2ecf20Sopenharmony_ci	repd = !!(cmd[2] & 0x80);
21398c2ecf20Sopenharmony_ci	alloc_len = get_unaligned_be32(cmd + 6);
21408c2ecf20Sopenharmony_ci	if (alloc_len < 4) {
21418c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
21428c2ecf20Sopenharmony_ci		return check_condition_result;
21438c2ecf20Sopenharmony_ci	}
21448c2ecf20Sopenharmony_ci	arr[0] = 0xc8;		/* ATS | ATSS | LURS */
21458c2ecf20Sopenharmony_ci	arr[1] = 0x1;		/* ITNRS */
21468c2ecf20Sopenharmony_ci	if (repd) {
21478c2ecf20Sopenharmony_ci		arr[3] = 0xc;
21488c2ecf20Sopenharmony_ci		len = 16;
21498c2ecf20Sopenharmony_ci	} else
21508c2ecf20Sopenharmony_ci		len = 4;
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	len = (len < alloc_len) ? len : alloc_len;
21538c2ecf20Sopenharmony_ci	return fill_from_dev_buffer(scp, arr, len);
21548c2ecf20Sopenharmony_ci}
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci/* <<Following mode page info copied from ST318451LW>> */
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_cistatic int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
21598c2ecf20Sopenharmony_ci{	/* Read-Write Error Recovery page for mode_sense */
21608c2ecf20Sopenharmony_ci	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
21618c2ecf20Sopenharmony_ci					5, 0, 0xff, 0xff};
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
21648c2ecf20Sopenharmony_ci	if (1 == pcontrol)
21658c2ecf20Sopenharmony_ci		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
21668c2ecf20Sopenharmony_ci	return sizeof(err_recov_pg);
21678c2ecf20Sopenharmony_ci}
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_cistatic int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
21708c2ecf20Sopenharmony_ci{ 	/* Disconnect-Reconnect page for mode_sense */
21718c2ecf20Sopenharmony_ci	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
21728c2ecf20Sopenharmony_ci					 0, 0, 0, 0, 0, 0, 0, 0};
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
21758c2ecf20Sopenharmony_ci	if (1 == pcontrol)
21768c2ecf20Sopenharmony_ci		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
21778c2ecf20Sopenharmony_ci	return sizeof(disconnect_pg);
21788c2ecf20Sopenharmony_ci}
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_cistatic int resp_format_pg(unsigned char *p, int pcontrol, int target)
21818c2ecf20Sopenharmony_ci{       /* Format device page for mode_sense */
21828c2ecf20Sopenharmony_ci	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
21838c2ecf20Sopenharmony_ci				     0, 0, 0, 0, 0, 0, 0, 0,
21848c2ecf20Sopenharmony_ci				     0, 0, 0, 0, 0x40, 0, 0, 0};
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	memcpy(p, format_pg, sizeof(format_pg));
21878c2ecf20Sopenharmony_ci	put_unaligned_be16(sdebug_sectors_per, p + 10);
21888c2ecf20Sopenharmony_ci	put_unaligned_be16(sdebug_sector_size, p + 12);
21898c2ecf20Sopenharmony_ci	if (sdebug_removable)
21908c2ecf20Sopenharmony_ci		p[20] |= 0x20; /* should agree with INQUIRY */
21918c2ecf20Sopenharmony_ci	if (1 == pcontrol)
21928c2ecf20Sopenharmony_ci		memset(p + 2, 0, sizeof(format_pg) - 2);
21938c2ecf20Sopenharmony_ci	return sizeof(format_pg);
21948c2ecf20Sopenharmony_ci}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_cistatic unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
21978c2ecf20Sopenharmony_ci				     0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
21988c2ecf20Sopenharmony_ci				     0, 0, 0, 0};
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_cistatic int resp_caching_pg(unsigned char *p, int pcontrol, int target)
22018c2ecf20Sopenharmony_ci{ 	/* Caching page for mode_sense */
22028c2ecf20Sopenharmony_ci	unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
22038c2ecf20Sopenharmony_ci		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
22048c2ecf20Sopenharmony_ci	unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
22058c2ecf20Sopenharmony_ci		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci	if (SDEBUG_OPT_N_WCE & sdebug_opts)
22088c2ecf20Sopenharmony_ci		caching_pg[2] &= ~0x4;	/* set WCE=0 (default WCE=1) */
22098c2ecf20Sopenharmony_ci	memcpy(p, caching_pg, sizeof(caching_pg));
22108c2ecf20Sopenharmony_ci	if (1 == pcontrol)
22118c2ecf20Sopenharmony_ci		memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
22128c2ecf20Sopenharmony_ci	else if (2 == pcontrol)
22138c2ecf20Sopenharmony_ci		memcpy(p, d_caching_pg, sizeof(d_caching_pg));
22148c2ecf20Sopenharmony_ci	return sizeof(caching_pg);
22158c2ecf20Sopenharmony_ci}
22168c2ecf20Sopenharmony_ci
22178c2ecf20Sopenharmony_cistatic unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22188c2ecf20Sopenharmony_ci				    0, 0, 0x2, 0x4b};
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_cistatic int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
22218c2ecf20Sopenharmony_ci{ 	/* Control mode page for mode_sense */
22228c2ecf20Sopenharmony_ci	unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
22238c2ecf20Sopenharmony_ci					0, 0, 0, 0};
22248c2ecf20Sopenharmony_ci	unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
22258c2ecf20Sopenharmony_ci				     0, 0, 0x2, 0x4b};
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	if (sdebug_dsense)
22288c2ecf20Sopenharmony_ci		ctrl_m_pg[2] |= 0x4;
22298c2ecf20Sopenharmony_ci	else
22308c2ecf20Sopenharmony_ci		ctrl_m_pg[2] &= ~0x4;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	if (sdebug_ato)
22338c2ecf20Sopenharmony_ci		ctrl_m_pg[5] |= 0x80; /* ATO=1 */
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
22368c2ecf20Sopenharmony_ci	if (1 == pcontrol)
22378c2ecf20Sopenharmony_ci		memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
22388c2ecf20Sopenharmony_ci	else if (2 == pcontrol)
22398c2ecf20Sopenharmony_ci		memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
22408c2ecf20Sopenharmony_ci	return sizeof(ctrl_m_pg);
22418c2ecf20Sopenharmony_ci}
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_cistatic int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
22458c2ecf20Sopenharmony_ci{	/* Informational Exceptions control mode page for mode_sense */
22468c2ecf20Sopenharmony_ci	unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
22478c2ecf20Sopenharmony_ci				       0, 0, 0x0, 0x0};
22488c2ecf20Sopenharmony_ci	unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
22498c2ecf20Sopenharmony_ci				      0, 0, 0x0, 0x0};
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
22528c2ecf20Sopenharmony_ci	if (1 == pcontrol)
22538c2ecf20Sopenharmony_ci		memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
22548c2ecf20Sopenharmony_ci	else if (2 == pcontrol)
22558c2ecf20Sopenharmony_ci		memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
22568c2ecf20Sopenharmony_ci	return sizeof(iec_m_pg);
22578c2ecf20Sopenharmony_ci}
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_cistatic int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
22608c2ecf20Sopenharmony_ci{	/* SAS SSP mode page - short format for mode_sense */
22618c2ecf20Sopenharmony_ci	unsigned char sas_sf_m_pg[] = {0x19, 0x6,
22628c2ecf20Sopenharmony_ci		0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci	memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
22658c2ecf20Sopenharmony_ci	if (1 == pcontrol)
22668c2ecf20Sopenharmony_ci		memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
22678c2ecf20Sopenharmony_ci	return sizeof(sas_sf_m_pg);
22688c2ecf20Sopenharmony_ci}
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_cistatic int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
22728c2ecf20Sopenharmony_ci			      int target_dev_id)
22738c2ecf20Sopenharmony_ci{	/* SAS phy control and discover mode page for mode_sense */
22748c2ecf20Sopenharmony_ci	unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
22758c2ecf20Sopenharmony_ci		    0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
22768c2ecf20Sopenharmony_ci		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
22778c2ecf20Sopenharmony_ci		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
22788c2ecf20Sopenharmony_ci		    0x2, 0, 0, 0, 0, 0, 0, 0,
22798c2ecf20Sopenharmony_ci		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
22808c2ecf20Sopenharmony_ci		    0, 0, 0, 0, 0, 0, 0, 0,
22818c2ecf20Sopenharmony_ci		    0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
22828c2ecf20Sopenharmony_ci		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
22838c2ecf20Sopenharmony_ci		    0, 0, 0, 0, 0, 0, 0, 0,	/* insert SAS addr */
22848c2ecf20Sopenharmony_ci		    0x3, 0, 0, 0, 0, 0, 0, 0,
22858c2ecf20Sopenharmony_ci		    0x88, 0x99, 0, 0, 0, 0, 0, 0,
22868c2ecf20Sopenharmony_ci		    0, 0, 0, 0, 0, 0, 0, 0,
22878c2ecf20Sopenharmony_ci		};
22888c2ecf20Sopenharmony_ci	int port_a, port_b;
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
22918c2ecf20Sopenharmony_ci	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
22928c2ecf20Sopenharmony_ci	put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
22938c2ecf20Sopenharmony_ci	put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
22948c2ecf20Sopenharmony_ci	port_a = target_dev_id + 1;
22958c2ecf20Sopenharmony_ci	port_b = port_a + 1;
22968c2ecf20Sopenharmony_ci	memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
22978c2ecf20Sopenharmony_ci	put_unaligned_be32(port_a, p + 20);
22988c2ecf20Sopenharmony_ci	put_unaligned_be32(port_b, p + 48 + 20);
22998c2ecf20Sopenharmony_ci	if (1 == pcontrol)
23008c2ecf20Sopenharmony_ci		memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
23018c2ecf20Sopenharmony_ci	return sizeof(sas_pcd_m_pg);
23028c2ecf20Sopenharmony_ci}
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_cistatic int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
23058c2ecf20Sopenharmony_ci{	/* SAS SSP shared protocol specific port mode subpage */
23068c2ecf20Sopenharmony_ci	unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
23078c2ecf20Sopenharmony_ci		    0, 0, 0, 0, 0, 0, 0, 0,
23088c2ecf20Sopenharmony_ci		};
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci	memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
23118c2ecf20Sopenharmony_ci	if (1 == pcontrol)
23128c2ecf20Sopenharmony_ci		memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
23138c2ecf20Sopenharmony_ci	return sizeof(sas_sha_m_pg);
23148c2ecf20Sopenharmony_ci}
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci#define SDEBUG_MAX_MSENSE_SZ 256
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_cistatic int resp_mode_sense(struct scsi_cmnd *scp,
23198c2ecf20Sopenharmony_ci			   struct sdebug_dev_info *devip)
23208c2ecf20Sopenharmony_ci{
23218c2ecf20Sopenharmony_ci	int pcontrol, pcode, subpcode, bd_len;
23228c2ecf20Sopenharmony_ci	unsigned char dev_spec;
23238c2ecf20Sopenharmony_ci	u32 alloc_len, offset, len;
23248c2ecf20Sopenharmony_ci	int target_dev_id;
23258c2ecf20Sopenharmony_ci	int target = scp->device->id;
23268c2ecf20Sopenharmony_ci	unsigned char *ap;
23278c2ecf20Sopenharmony_ci	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
23288c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
23298c2ecf20Sopenharmony_ci	bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode;
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci	dbd = !!(cmd[1] & 0x8);		/* disable block descriptors */
23328c2ecf20Sopenharmony_ci	pcontrol = (cmd[2] & 0xc0) >> 6;
23338c2ecf20Sopenharmony_ci	pcode = cmd[2] & 0x3f;
23348c2ecf20Sopenharmony_ci	subpcode = cmd[3];
23358c2ecf20Sopenharmony_ci	msense_6 = (MODE_SENSE == cmd[0]);
23368c2ecf20Sopenharmony_ci	llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
23378c2ecf20Sopenharmony_ci	is_disk = (sdebug_ptype == TYPE_DISK);
23388c2ecf20Sopenharmony_ci	is_zbc = (devip->zmodel != BLK_ZONED_NONE);
23398c2ecf20Sopenharmony_ci	if ((is_disk || is_zbc) && !dbd)
23408c2ecf20Sopenharmony_ci		bd_len = llbaa ? 16 : 8;
23418c2ecf20Sopenharmony_ci	else
23428c2ecf20Sopenharmony_ci		bd_len = 0;
23438c2ecf20Sopenharmony_ci	alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
23448c2ecf20Sopenharmony_ci	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
23458c2ecf20Sopenharmony_ci	if (0x3 == pcontrol) {  /* Saving values not supported */
23468c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
23478c2ecf20Sopenharmony_ci		return check_condition_result;
23488c2ecf20Sopenharmony_ci	}
23498c2ecf20Sopenharmony_ci	target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
23508c2ecf20Sopenharmony_ci			(devip->target * 1000) - 3;
23518c2ecf20Sopenharmony_ci	/* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */
23528c2ecf20Sopenharmony_ci	if (is_disk || is_zbc) {
23538c2ecf20Sopenharmony_ci		dev_spec = 0x10;	/* =0x90 if WP=1 implies read-only */
23548c2ecf20Sopenharmony_ci		if (sdebug_wp)
23558c2ecf20Sopenharmony_ci			dev_spec |= 0x80;
23568c2ecf20Sopenharmony_ci	} else
23578c2ecf20Sopenharmony_ci		dev_spec = 0x0;
23588c2ecf20Sopenharmony_ci	if (msense_6) {
23598c2ecf20Sopenharmony_ci		arr[2] = dev_spec;
23608c2ecf20Sopenharmony_ci		arr[3] = bd_len;
23618c2ecf20Sopenharmony_ci		offset = 4;
23628c2ecf20Sopenharmony_ci	} else {
23638c2ecf20Sopenharmony_ci		arr[3] = dev_spec;
23648c2ecf20Sopenharmony_ci		if (16 == bd_len)
23658c2ecf20Sopenharmony_ci			arr[4] = 0x1;	/* set LONGLBA bit */
23668c2ecf20Sopenharmony_ci		arr[7] = bd_len;	/* assume 255 or less */
23678c2ecf20Sopenharmony_ci		offset = 8;
23688c2ecf20Sopenharmony_ci	}
23698c2ecf20Sopenharmony_ci	ap = arr + offset;
23708c2ecf20Sopenharmony_ci	if ((bd_len > 0) && (!sdebug_capacity))
23718c2ecf20Sopenharmony_ci		sdebug_capacity = get_sdebug_capacity();
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci	if (8 == bd_len) {
23748c2ecf20Sopenharmony_ci		if (sdebug_capacity > 0xfffffffe)
23758c2ecf20Sopenharmony_ci			put_unaligned_be32(0xffffffff, ap + 0);
23768c2ecf20Sopenharmony_ci		else
23778c2ecf20Sopenharmony_ci			put_unaligned_be32(sdebug_capacity, ap + 0);
23788c2ecf20Sopenharmony_ci		put_unaligned_be16(sdebug_sector_size, ap + 6);
23798c2ecf20Sopenharmony_ci		offset += bd_len;
23808c2ecf20Sopenharmony_ci		ap = arr + offset;
23818c2ecf20Sopenharmony_ci	} else if (16 == bd_len) {
23828c2ecf20Sopenharmony_ci		put_unaligned_be64((u64)sdebug_capacity, ap + 0);
23838c2ecf20Sopenharmony_ci		put_unaligned_be32(sdebug_sector_size, ap + 12);
23848c2ecf20Sopenharmony_ci		offset += bd_len;
23858c2ecf20Sopenharmony_ci		ap = arr + offset;
23868c2ecf20Sopenharmony_ci	}
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_ci	if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
23898c2ecf20Sopenharmony_ci		/* TODO: Control Extension page */
23908c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
23918c2ecf20Sopenharmony_ci		return check_condition_result;
23928c2ecf20Sopenharmony_ci	}
23938c2ecf20Sopenharmony_ci	bad_pcode = false;
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	switch (pcode) {
23968c2ecf20Sopenharmony_ci	case 0x1:	/* Read-Write error recovery page, direct access */
23978c2ecf20Sopenharmony_ci		len = resp_err_recov_pg(ap, pcontrol, target);
23988c2ecf20Sopenharmony_ci		offset += len;
23998c2ecf20Sopenharmony_ci		break;
24008c2ecf20Sopenharmony_ci	case 0x2:	/* Disconnect-Reconnect page, all devices */
24018c2ecf20Sopenharmony_ci		len = resp_disconnect_pg(ap, pcontrol, target);
24028c2ecf20Sopenharmony_ci		offset += len;
24038c2ecf20Sopenharmony_ci		break;
24048c2ecf20Sopenharmony_ci	case 0x3:       /* Format device page, direct access */
24058c2ecf20Sopenharmony_ci		if (is_disk) {
24068c2ecf20Sopenharmony_ci			len = resp_format_pg(ap, pcontrol, target);
24078c2ecf20Sopenharmony_ci			offset += len;
24088c2ecf20Sopenharmony_ci		} else
24098c2ecf20Sopenharmony_ci			bad_pcode = true;
24108c2ecf20Sopenharmony_ci		break;
24118c2ecf20Sopenharmony_ci	case 0x8:	/* Caching page, direct access */
24128c2ecf20Sopenharmony_ci		if (is_disk || is_zbc) {
24138c2ecf20Sopenharmony_ci			len = resp_caching_pg(ap, pcontrol, target);
24148c2ecf20Sopenharmony_ci			offset += len;
24158c2ecf20Sopenharmony_ci		} else
24168c2ecf20Sopenharmony_ci			bad_pcode = true;
24178c2ecf20Sopenharmony_ci		break;
24188c2ecf20Sopenharmony_ci	case 0xa:	/* Control Mode page, all devices */
24198c2ecf20Sopenharmony_ci		len = resp_ctrl_m_pg(ap, pcontrol, target);
24208c2ecf20Sopenharmony_ci		offset += len;
24218c2ecf20Sopenharmony_ci		break;
24228c2ecf20Sopenharmony_ci	case 0x19:	/* if spc==1 then sas phy, control+discover */
24238c2ecf20Sopenharmony_ci		if ((subpcode > 0x2) && (subpcode < 0xff)) {
24248c2ecf20Sopenharmony_ci			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
24258c2ecf20Sopenharmony_ci			return check_condition_result;
24268c2ecf20Sopenharmony_ci		}
24278c2ecf20Sopenharmony_ci		len = 0;
24288c2ecf20Sopenharmony_ci		if ((0x0 == subpcode) || (0xff == subpcode))
24298c2ecf20Sopenharmony_ci			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
24308c2ecf20Sopenharmony_ci		if ((0x1 == subpcode) || (0xff == subpcode))
24318c2ecf20Sopenharmony_ci			len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
24328c2ecf20Sopenharmony_ci						  target_dev_id);
24338c2ecf20Sopenharmony_ci		if ((0x2 == subpcode) || (0xff == subpcode))
24348c2ecf20Sopenharmony_ci			len += resp_sas_sha_m_spg(ap + len, pcontrol);
24358c2ecf20Sopenharmony_ci		offset += len;
24368c2ecf20Sopenharmony_ci		break;
24378c2ecf20Sopenharmony_ci	case 0x1c:	/* Informational Exceptions Mode page, all devices */
24388c2ecf20Sopenharmony_ci		len = resp_iec_m_pg(ap, pcontrol, target);
24398c2ecf20Sopenharmony_ci		offset += len;
24408c2ecf20Sopenharmony_ci		break;
24418c2ecf20Sopenharmony_ci	case 0x3f:	/* Read all Mode pages */
24428c2ecf20Sopenharmony_ci		if ((0 == subpcode) || (0xff == subpcode)) {
24438c2ecf20Sopenharmony_ci			len = resp_err_recov_pg(ap, pcontrol, target);
24448c2ecf20Sopenharmony_ci			len += resp_disconnect_pg(ap + len, pcontrol, target);
24458c2ecf20Sopenharmony_ci			if (is_disk) {
24468c2ecf20Sopenharmony_ci				len += resp_format_pg(ap + len, pcontrol,
24478c2ecf20Sopenharmony_ci						      target);
24488c2ecf20Sopenharmony_ci				len += resp_caching_pg(ap + len, pcontrol,
24498c2ecf20Sopenharmony_ci						       target);
24508c2ecf20Sopenharmony_ci			} else if (is_zbc) {
24518c2ecf20Sopenharmony_ci				len += resp_caching_pg(ap + len, pcontrol,
24528c2ecf20Sopenharmony_ci						       target);
24538c2ecf20Sopenharmony_ci			}
24548c2ecf20Sopenharmony_ci			len += resp_ctrl_m_pg(ap + len, pcontrol, target);
24558c2ecf20Sopenharmony_ci			len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
24568c2ecf20Sopenharmony_ci			if (0xff == subpcode) {
24578c2ecf20Sopenharmony_ci				len += resp_sas_pcd_m_spg(ap + len, pcontrol,
24588c2ecf20Sopenharmony_ci						  target, target_dev_id);
24598c2ecf20Sopenharmony_ci				len += resp_sas_sha_m_spg(ap + len, pcontrol);
24608c2ecf20Sopenharmony_ci			}
24618c2ecf20Sopenharmony_ci			len += resp_iec_m_pg(ap + len, pcontrol, target);
24628c2ecf20Sopenharmony_ci			offset += len;
24638c2ecf20Sopenharmony_ci		} else {
24648c2ecf20Sopenharmony_ci			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
24658c2ecf20Sopenharmony_ci			return check_condition_result;
24668c2ecf20Sopenharmony_ci		}
24678c2ecf20Sopenharmony_ci		break;
24688c2ecf20Sopenharmony_ci	default:
24698c2ecf20Sopenharmony_ci		bad_pcode = true;
24708c2ecf20Sopenharmony_ci		break;
24718c2ecf20Sopenharmony_ci	}
24728c2ecf20Sopenharmony_ci	if (bad_pcode) {
24738c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
24748c2ecf20Sopenharmony_ci		return check_condition_result;
24758c2ecf20Sopenharmony_ci	}
24768c2ecf20Sopenharmony_ci	if (msense_6)
24778c2ecf20Sopenharmony_ci		arr[0] = offset - 1;
24788c2ecf20Sopenharmony_ci	else
24798c2ecf20Sopenharmony_ci		put_unaligned_be16((offset - 2), arr + 0);
24808c2ecf20Sopenharmony_ci	return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset));
24818c2ecf20Sopenharmony_ci}
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci#define SDEBUG_MAX_MSELECT_SZ 512
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_cistatic int resp_mode_select(struct scsi_cmnd *scp,
24868c2ecf20Sopenharmony_ci			    struct sdebug_dev_info *devip)
24878c2ecf20Sopenharmony_ci{
24888c2ecf20Sopenharmony_ci	int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
24898c2ecf20Sopenharmony_ci	int param_len, res, mpage;
24908c2ecf20Sopenharmony_ci	unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
24918c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
24928c2ecf20Sopenharmony_ci	int mselect6 = (MODE_SELECT == cmd[0]);
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	memset(arr, 0, sizeof(arr));
24958c2ecf20Sopenharmony_ci	pf = cmd[1] & 0x10;
24968c2ecf20Sopenharmony_ci	sp = cmd[1] & 0x1;
24978c2ecf20Sopenharmony_ci	param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
24988c2ecf20Sopenharmony_ci	if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
24998c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
25008c2ecf20Sopenharmony_ci		return check_condition_result;
25018c2ecf20Sopenharmony_ci	}
25028c2ecf20Sopenharmony_ci	res = fetch_to_dev_buffer(scp, arr, param_len);
25038c2ecf20Sopenharmony_ci	if (-1 == res)
25048c2ecf20Sopenharmony_ci		return DID_ERROR << 16;
25058c2ecf20Sopenharmony_ci	else if (sdebug_verbose && (res < param_len))
25068c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, scp->device,
25078c2ecf20Sopenharmony_ci			    "%s: cdb indicated=%d, IO sent=%d bytes\n",
25088c2ecf20Sopenharmony_ci			    __func__, param_len, res);
25098c2ecf20Sopenharmony_ci	md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
25108c2ecf20Sopenharmony_ci	bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
25118c2ecf20Sopenharmony_ci	off = bd_len + (mselect6 ? 4 : 8);
25128c2ecf20Sopenharmony_ci	if (md_len > 2 || off >= res) {
25138c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
25148c2ecf20Sopenharmony_ci		return check_condition_result;
25158c2ecf20Sopenharmony_ci	}
25168c2ecf20Sopenharmony_ci	mpage = arr[off] & 0x3f;
25178c2ecf20Sopenharmony_ci	ps = !!(arr[off] & 0x80);
25188c2ecf20Sopenharmony_ci	if (ps) {
25198c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
25208c2ecf20Sopenharmony_ci		return check_condition_result;
25218c2ecf20Sopenharmony_ci	}
25228c2ecf20Sopenharmony_ci	spf = !!(arr[off] & 0x40);
25238c2ecf20Sopenharmony_ci	pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
25248c2ecf20Sopenharmony_ci		       (arr[off + 1] + 2);
25258c2ecf20Sopenharmony_ci	if ((pg_len + off) > param_len) {
25268c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST,
25278c2ecf20Sopenharmony_ci				PARAMETER_LIST_LENGTH_ERR, 0);
25288c2ecf20Sopenharmony_ci		return check_condition_result;
25298c2ecf20Sopenharmony_ci	}
25308c2ecf20Sopenharmony_ci	switch (mpage) {
25318c2ecf20Sopenharmony_ci	case 0x8:      /* Caching Mode page */
25328c2ecf20Sopenharmony_ci		if (caching_pg[1] == arr[off + 1]) {
25338c2ecf20Sopenharmony_ci			memcpy(caching_pg + 2, arr + off + 2,
25348c2ecf20Sopenharmony_ci			       sizeof(caching_pg) - 2);
25358c2ecf20Sopenharmony_ci			goto set_mode_changed_ua;
25368c2ecf20Sopenharmony_ci		}
25378c2ecf20Sopenharmony_ci		break;
25388c2ecf20Sopenharmony_ci	case 0xa:      /* Control Mode page */
25398c2ecf20Sopenharmony_ci		if (ctrl_m_pg[1] == arr[off + 1]) {
25408c2ecf20Sopenharmony_ci			memcpy(ctrl_m_pg + 2, arr + off + 2,
25418c2ecf20Sopenharmony_ci			       sizeof(ctrl_m_pg) - 2);
25428c2ecf20Sopenharmony_ci			if (ctrl_m_pg[4] & 0x8)
25438c2ecf20Sopenharmony_ci				sdebug_wp = true;
25448c2ecf20Sopenharmony_ci			else
25458c2ecf20Sopenharmony_ci				sdebug_wp = false;
25468c2ecf20Sopenharmony_ci			sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
25478c2ecf20Sopenharmony_ci			goto set_mode_changed_ua;
25488c2ecf20Sopenharmony_ci		}
25498c2ecf20Sopenharmony_ci		break;
25508c2ecf20Sopenharmony_ci	case 0x1c:      /* Informational Exceptions Mode page */
25518c2ecf20Sopenharmony_ci		if (iec_m_pg[1] == arr[off + 1]) {
25528c2ecf20Sopenharmony_ci			memcpy(iec_m_pg + 2, arr + off + 2,
25538c2ecf20Sopenharmony_ci			       sizeof(iec_m_pg) - 2);
25548c2ecf20Sopenharmony_ci			goto set_mode_changed_ua;
25558c2ecf20Sopenharmony_ci		}
25568c2ecf20Sopenharmony_ci		break;
25578c2ecf20Sopenharmony_ci	default:
25588c2ecf20Sopenharmony_ci		break;
25598c2ecf20Sopenharmony_ci	}
25608c2ecf20Sopenharmony_ci	mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
25618c2ecf20Sopenharmony_ci	return check_condition_result;
25628c2ecf20Sopenharmony_ciset_mode_changed_ua:
25638c2ecf20Sopenharmony_ci	set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
25648c2ecf20Sopenharmony_ci	return 0;
25658c2ecf20Sopenharmony_ci}
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_cistatic int resp_temp_l_pg(unsigned char *arr)
25688c2ecf20Sopenharmony_ci{
25698c2ecf20Sopenharmony_ci	unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
25708c2ecf20Sopenharmony_ci				     0x0, 0x1, 0x3, 0x2, 0x0, 65,
25718c2ecf20Sopenharmony_ci		};
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
25748c2ecf20Sopenharmony_ci	return sizeof(temp_l_pg);
25758c2ecf20Sopenharmony_ci}
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_cistatic int resp_ie_l_pg(unsigned char *arr)
25788c2ecf20Sopenharmony_ci{
25798c2ecf20Sopenharmony_ci	unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
25808c2ecf20Sopenharmony_ci		};
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci	memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
25838c2ecf20Sopenharmony_ci	if (iec_m_pg[2] & 0x4) {	/* TEST bit set */
25848c2ecf20Sopenharmony_ci		arr[4] = THRESHOLD_EXCEEDED;
25858c2ecf20Sopenharmony_ci		arr[5] = 0xff;
25868c2ecf20Sopenharmony_ci	}
25878c2ecf20Sopenharmony_ci	return sizeof(ie_l_pg);
25888c2ecf20Sopenharmony_ci}
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci#define SDEBUG_MAX_LSENSE_SZ 512
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_cistatic int resp_log_sense(struct scsi_cmnd *scp,
25938c2ecf20Sopenharmony_ci			  struct sdebug_dev_info *devip)
25948c2ecf20Sopenharmony_ci{
25958c2ecf20Sopenharmony_ci	int ppc, sp, pcode, subpcode;
25968c2ecf20Sopenharmony_ci	u32 alloc_len, len, n;
25978c2ecf20Sopenharmony_ci	unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
25988c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci	memset(arr, 0, sizeof(arr));
26018c2ecf20Sopenharmony_ci	ppc = cmd[1] & 0x2;
26028c2ecf20Sopenharmony_ci	sp = cmd[1] & 0x1;
26038c2ecf20Sopenharmony_ci	if (ppc || sp) {
26048c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
26058c2ecf20Sopenharmony_ci		return check_condition_result;
26068c2ecf20Sopenharmony_ci	}
26078c2ecf20Sopenharmony_ci	pcode = cmd[2] & 0x3f;
26088c2ecf20Sopenharmony_ci	subpcode = cmd[3] & 0xff;
26098c2ecf20Sopenharmony_ci	alloc_len = get_unaligned_be16(cmd + 7);
26108c2ecf20Sopenharmony_ci	arr[0] = pcode;
26118c2ecf20Sopenharmony_ci	if (0 == subpcode) {
26128c2ecf20Sopenharmony_ci		switch (pcode) {
26138c2ecf20Sopenharmony_ci		case 0x0:	/* Supported log pages log page */
26148c2ecf20Sopenharmony_ci			n = 4;
26158c2ecf20Sopenharmony_ci			arr[n++] = 0x0;		/* this page */
26168c2ecf20Sopenharmony_ci			arr[n++] = 0xd;		/* Temperature */
26178c2ecf20Sopenharmony_ci			arr[n++] = 0x2f;	/* Informational exceptions */
26188c2ecf20Sopenharmony_ci			arr[3] = n - 4;
26198c2ecf20Sopenharmony_ci			break;
26208c2ecf20Sopenharmony_ci		case 0xd:	/* Temperature log page */
26218c2ecf20Sopenharmony_ci			arr[3] = resp_temp_l_pg(arr + 4);
26228c2ecf20Sopenharmony_ci			break;
26238c2ecf20Sopenharmony_ci		case 0x2f:	/* Informational exceptions log page */
26248c2ecf20Sopenharmony_ci			arr[3] = resp_ie_l_pg(arr + 4);
26258c2ecf20Sopenharmony_ci			break;
26268c2ecf20Sopenharmony_ci		default:
26278c2ecf20Sopenharmony_ci			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
26288c2ecf20Sopenharmony_ci			return check_condition_result;
26298c2ecf20Sopenharmony_ci		}
26308c2ecf20Sopenharmony_ci	} else if (0xff == subpcode) {
26318c2ecf20Sopenharmony_ci		arr[0] |= 0x40;
26328c2ecf20Sopenharmony_ci		arr[1] = subpcode;
26338c2ecf20Sopenharmony_ci		switch (pcode) {
26348c2ecf20Sopenharmony_ci		case 0x0:	/* Supported log pages and subpages log page */
26358c2ecf20Sopenharmony_ci			n = 4;
26368c2ecf20Sopenharmony_ci			arr[n++] = 0x0;
26378c2ecf20Sopenharmony_ci			arr[n++] = 0x0;		/* 0,0 page */
26388c2ecf20Sopenharmony_ci			arr[n++] = 0x0;
26398c2ecf20Sopenharmony_ci			arr[n++] = 0xff;	/* this page */
26408c2ecf20Sopenharmony_ci			arr[n++] = 0xd;
26418c2ecf20Sopenharmony_ci			arr[n++] = 0x0;		/* Temperature */
26428c2ecf20Sopenharmony_ci			arr[n++] = 0x2f;
26438c2ecf20Sopenharmony_ci			arr[n++] = 0x0;	/* Informational exceptions */
26448c2ecf20Sopenharmony_ci			arr[3] = n - 4;
26458c2ecf20Sopenharmony_ci			break;
26468c2ecf20Sopenharmony_ci		case 0xd:	/* Temperature subpages */
26478c2ecf20Sopenharmony_ci			n = 4;
26488c2ecf20Sopenharmony_ci			arr[n++] = 0xd;
26498c2ecf20Sopenharmony_ci			arr[n++] = 0x0;		/* Temperature */
26508c2ecf20Sopenharmony_ci			arr[3] = n - 4;
26518c2ecf20Sopenharmony_ci			break;
26528c2ecf20Sopenharmony_ci		case 0x2f:	/* Informational exceptions subpages */
26538c2ecf20Sopenharmony_ci			n = 4;
26548c2ecf20Sopenharmony_ci			arr[n++] = 0x2f;
26558c2ecf20Sopenharmony_ci			arr[n++] = 0x0;		/* Informational exceptions */
26568c2ecf20Sopenharmony_ci			arr[3] = n - 4;
26578c2ecf20Sopenharmony_ci			break;
26588c2ecf20Sopenharmony_ci		default:
26598c2ecf20Sopenharmony_ci			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
26608c2ecf20Sopenharmony_ci			return check_condition_result;
26618c2ecf20Sopenharmony_ci		}
26628c2ecf20Sopenharmony_ci	} else {
26638c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
26648c2ecf20Sopenharmony_ci		return check_condition_result;
26658c2ecf20Sopenharmony_ci	}
26668c2ecf20Sopenharmony_ci	len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len);
26678c2ecf20Sopenharmony_ci	return fill_from_dev_buffer(scp, arr,
26688c2ecf20Sopenharmony_ci		    min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ));
26698c2ecf20Sopenharmony_ci}
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_cistatic inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
26728c2ecf20Sopenharmony_ci{
26738c2ecf20Sopenharmony_ci	return devip->nr_zones != 0;
26748c2ecf20Sopenharmony_ci}
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_cistatic struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
26778c2ecf20Sopenharmony_ci					unsigned long long lba)
26788c2ecf20Sopenharmony_ci{
26798c2ecf20Sopenharmony_ci	return &devip->zstate[lba >> devip->zsize_shift];
26808c2ecf20Sopenharmony_ci}
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_cistatic inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
26838c2ecf20Sopenharmony_ci{
26848c2ecf20Sopenharmony_ci	return zsp->z_type == ZBC_ZONE_TYPE_CNV;
26858c2ecf20Sopenharmony_ci}
26868c2ecf20Sopenharmony_ci
26878c2ecf20Sopenharmony_cistatic void zbc_close_zone(struct sdebug_dev_info *devip,
26888c2ecf20Sopenharmony_ci			   struct sdeb_zone_state *zsp)
26898c2ecf20Sopenharmony_ci{
26908c2ecf20Sopenharmony_ci	enum sdebug_z_cond zc;
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp))
26938c2ecf20Sopenharmony_ci		return;
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci	zc = zsp->z_cond;
26968c2ecf20Sopenharmony_ci	if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN))
26978c2ecf20Sopenharmony_ci		return;
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	if (zc == ZC2_IMPLICIT_OPEN)
27008c2ecf20Sopenharmony_ci		devip->nr_imp_open--;
27018c2ecf20Sopenharmony_ci	else
27028c2ecf20Sopenharmony_ci		devip->nr_exp_open--;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	if (zsp->z_wp == zsp->z_start) {
27058c2ecf20Sopenharmony_ci		zsp->z_cond = ZC1_EMPTY;
27068c2ecf20Sopenharmony_ci	} else {
27078c2ecf20Sopenharmony_ci		zsp->z_cond = ZC4_CLOSED;
27088c2ecf20Sopenharmony_ci		devip->nr_closed++;
27098c2ecf20Sopenharmony_ci	}
27108c2ecf20Sopenharmony_ci}
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_cistatic void zbc_close_imp_open_zone(struct sdebug_dev_info *devip)
27138c2ecf20Sopenharmony_ci{
27148c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp = &devip->zstate[0];
27158c2ecf20Sopenharmony_ci	unsigned int i;
27168c2ecf20Sopenharmony_ci
27178c2ecf20Sopenharmony_ci	for (i = 0; i < devip->nr_zones; i++, zsp++) {
27188c2ecf20Sopenharmony_ci		if (zsp->z_cond == ZC2_IMPLICIT_OPEN) {
27198c2ecf20Sopenharmony_ci			zbc_close_zone(devip, zsp);
27208c2ecf20Sopenharmony_ci			return;
27218c2ecf20Sopenharmony_ci		}
27228c2ecf20Sopenharmony_ci	}
27238c2ecf20Sopenharmony_ci}
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_cistatic void zbc_open_zone(struct sdebug_dev_info *devip,
27268c2ecf20Sopenharmony_ci			  struct sdeb_zone_state *zsp, bool explicit)
27278c2ecf20Sopenharmony_ci{
27288c2ecf20Sopenharmony_ci	enum sdebug_z_cond zc;
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp))
27318c2ecf20Sopenharmony_ci		return;
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	zc = zsp->z_cond;
27348c2ecf20Sopenharmony_ci	if ((explicit && zc == ZC3_EXPLICIT_OPEN) ||
27358c2ecf20Sopenharmony_ci	    (!explicit && zc == ZC2_IMPLICIT_OPEN))
27368c2ecf20Sopenharmony_ci		return;
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci	/* Close an implicit open zone if necessary */
27398c2ecf20Sopenharmony_ci	if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN)
27408c2ecf20Sopenharmony_ci		zbc_close_zone(devip, zsp);
27418c2ecf20Sopenharmony_ci	else if (devip->max_open &&
27428c2ecf20Sopenharmony_ci		 devip->nr_imp_open + devip->nr_exp_open >= devip->max_open)
27438c2ecf20Sopenharmony_ci		zbc_close_imp_open_zone(devip);
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ci	if (zsp->z_cond == ZC4_CLOSED)
27468c2ecf20Sopenharmony_ci		devip->nr_closed--;
27478c2ecf20Sopenharmony_ci	if (explicit) {
27488c2ecf20Sopenharmony_ci		zsp->z_cond = ZC3_EXPLICIT_OPEN;
27498c2ecf20Sopenharmony_ci		devip->nr_exp_open++;
27508c2ecf20Sopenharmony_ci	} else {
27518c2ecf20Sopenharmony_ci		zsp->z_cond = ZC2_IMPLICIT_OPEN;
27528c2ecf20Sopenharmony_ci		devip->nr_imp_open++;
27538c2ecf20Sopenharmony_ci	}
27548c2ecf20Sopenharmony_ci}
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_cistatic inline void zbc_set_zone_full(struct sdebug_dev_info *devip,
27578c2ecf20Sopenharmony_ci				     struct sdeb_zone_state *zsp)
27588c2ecf20Sopenharmony_ci{
27598c2ecf20Sopenharmony_ci	switch (zsp->z_cond) {
27608c2ecf20Sopenharmony_ci	case ZC2_IMPLICIT_OPEN:
27618c2ecf20Sopenharmony_ci		devip->nr_imp_open--;
27628c2ecf20Sopenharmony_ci		break;
27638c2ecf20Sopenharmony_ci	case ZC3_EXPLICIT_OPEN:
27648c2ecf20Sopenharmony_ci		devip->nr_exp_open--;
27658c2ecf20Sopenharmony_ci		break;
27668c2ecf20Sopenharmony_ci	default:
27678c2ecf20Sopenharmony_ci		WARN_ONCE(true, "Invalid zone %llu condition %x\n",
27688c2ecf20Sopenharmony_ci			  zsp->z_start, zsp->z_cond);
27698c2ecf20Sopenharmony_ci		break;
27708c2ecf20Sopenharmony_ci	}
27718c2ecf20Sopenharmony_ci	zsp->z_cond = ZC5_FULL;
27728c2ecf20Sopenharmony_ci}
27738c2ecf20Sopenharmony_ci
27748c2ecf20Sopenharmony_cistatic void zbc_inc_wp(struct sdebug_dev_info *devip,
27758c2ecf20Sopenharmony_ci		       unsigned long long lba, unsigned int num)
27768c2ecf20Sopenharmony_ci{
27778c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
27788c2ecf20Sopenharmony_ci	unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
27798c2ecf20Sopenharmony_ci
27808c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp))
27818c2ecf20Sopenharmony_ci		return;
27828c2ecf20Sopenharmony_ci
27838c2ecf20Sopenharmony_ci	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
27848c2ecf20Sopenharmony_ci		zsp->z_wp += num;
27858c2ecf20Sopenharmony_ci		if (zsp->z_wp >= zend)
27868c2ecf20Sopenharmony_ci			zbc_set_zone_full(devip, zsp);
27878c2ecf20Sopenharmony_ci		return;
27888c2ecf20Sopenharmony_ci	}
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_ci	while (num) {
27918c2ecf20Sopenharmony_ci		if (lba != zsp->z_wp)
27928c2ecf20Sopenharmony_ci			zsp->z_non_seq_resource = true;
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci		end = lba + num;
27958c2ecf20Sopenharmony_ci		if (end >= zend) {
27968c2ecf20Sopenharmony_ci			n = zend - lba;
27978c2ecf20Sopenharmony_ci			zsp->z_wp = zend;
27988c2ecf20Sopenharmony_ci		} else if (end > zsp->z_wp) {
27998c2ecf20Sopenharmony_ci			n = num;
28008c2ecf20Sopenharmony_ci			zsp->z_wp = end;
28018c2ecf20Sopenharmony_ci		} else {
28028c2ecf20Sopenharmony_ci			n = num;
28038c2ecf20Sopenharmony_ci		}
28048c2ecf20Sopenharmony_ci		if (zsp->z_wp >= zend)
28058c2ecf20Sopenharmony_ci			zbc_set_zone_full(devip, zsp);
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci		num -= n;
28088c2ecf20Sopenharmony_ci		lba += n;
28098c2ecf20Sopenharmony_ci		if (num) {
28108c2ecf20Sopenharmony_ci			zsp++;
28118c2ecf20Sopenharmony_ci			zend = zsp->z_start + zsp->z_size;
28128c2ecf20Sopenharmony_ci		}
28138c2ecf20Sopenharmony_ci	}
28148c2ecf20Sopenharmony_ci}
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_cistatic int check_zbc_access_params(struct scsi_cmnd *scp,
28178c2ecf20Sopenharmony_ci			unsigned long long lba, unsigned int num, bool write)
28188c2ecf20Sopenharmony_ci{
28198c2ecf20Sopenharmony_ci	struct scsi_device *sdp = scp->device;
28208c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
28218c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
28228c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1);
28238c2ecf20Sopenharmony_ci
28248c2ecf20Sopenharmony_ci	if (!write) {
28258c2ecf20Sopenharmony_ci		if (devip->zmodel == BLK_ZONED_HA)
28268c2ecf20Sopenharmony_ci			return 0;
28278c2ecf20Sopenharmony_ci		/* For host-managed, reads cannot cross zone types boundaries */
28288c2ecf20Sopenharmony_ci		if (zsp_end != zsp &&
28298c2ecf20Sopenharmony_ci		    zbc_zone_is_conv(zsp) &&
28308c2ecf20Sopenharmony_ci		    !zbc_zone_is_conv(zsp_end)) {
28318c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST,
28328c2ecf20Sopenharmony_ci					LBA_OUT_OF_RANGE,
28338c2ecf20Sopenharmony_ci					READ_INVDATA_ASCQ);
28348c2ecf20Sopenharmony_ci			return check_condition_result;
28358c2ecf20Sopenharmony_ci		}
28368c2ecf20Sopenharmony_ci		return 0;
28378c2ecf20Sopenharmony_ci	}
28388c2ecf20Sopenharmony_ci
28398c2ecf20Sopenharmony_ci	/* No restrictions for writes within conventional zones */
28408c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp)) {
28418c2ecf20Sopenharmony_ci		if (!zbc_zone_is_conv(zsp_end)) {
28428c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST,
28438c2ecf20Sopenharmony_ci					LBA_OUT_OF_RANGE,
28448c2ecf20Sopenharmony_ci					WRITE_BOUNDARY_ASCQ);
28458c2ecf20Sopenharmony_ci			return check_condition_result;
28468c2ecf20Sopenharmony_ci		}
28478c2ecf20Sopenharmony_ci		return 0;
28488c2ecf20Sopenharmony_ci	}
28498c2ecf20Sopenharmony_ci
28508c2ecf20Sopenharmony_ci	if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
28518c2ecf20Sopenharmony_ci		/* Writes cannot cross sequential zone boundaries */
28528c2ecf20Sopenharmony_ci		if (zsp_end != zsp) {
28538c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST,
28548c2ecf20Sopenharmony_ci					LBA_OUT_OF_RANGE,
28558c2ecf20Sopenharmony_ci					WRITE_BOUNDARY_ASCQ);
28568c2ecf20Sopenharmony_ci			return check_condition_result;
28578c2ecf20Sopenharmony_ci		}
28588c2ecf20Sopenharmony_ci		/* Cannot write full zones */
28598c2ecf20Sopenharmony_ci		if (zsp->z_cond == ZC5_FULL) {
28608c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST,
28618c2ecf20Sopenharmony_ci					INVALID_FIELD_IN_CDB, 0);
28628c2ecf20Sopenharmony_ci			return check_condition_result;
28638c2ecf20Sopenharmony_ci		}
28648c2ecf20Sopenharmony_ci		/* Writes must be aligned to the zone WP */
28658c2ecf20Sopenharmony_ci		if (lba != zsp->z_wp) {
28668c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST,
28678c2ecf20Sopenharmony_ci					LBA_OUT_OF_RANGE,
28688c2ecf20Sopenharmony_ci					UNALIGNED_WRITE_ASCQ);
28698c2ecf20Sopenharmony_ci			return check_condition_result;
28708c2ecf20Sopenharmony_ci		}
28718c2ecf20Sopenharmony_ci	}
28728c2ecf20Sopenharmony_ci
28738c2ecf20Sopenharmony_ci	/* Handle implicit open of closed and empty zones */
28748c2ecf20Sopenharmony_ci	if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) {
28758c2ecf20Sopenharmony_ci		if (devip->max_open &&
28768c2ecf20Sopenharmony_ci		    devip->nr_exp_open >= devip->max_open) {
28778c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, DATA_PROTECT,
28788c2ecf20Sopenharmony_ci					INSUFF_RES_ASC,
28798c2ecf20Sopenharmony_ci					INSUFF_ZONE_ASCQ);
28808c2ecf20Sopenharmony_ci			return check_condition_result;
28818c2ecf20Sopenharmony_ci		}
28828c2ecf20Sopenharmony_ci		zbc_open_zone(devip, zsp, false);
28838c2ecf20Sopenharmony_ci	}
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci	return 0;
28868c2ecf20Sopenharmony_ci}
28878c2ecf20Sopenharmony_ci
28888c2ecf20Sopenharmony_cistatic inline int check_device_access_params
28898c2ecf20Sopenharmony_ci			(struct scsi_cmnd *scp, unsigned long long lba,
28908c2ecf20Sopenharmony_ci			 unsigned int num, bool write)
28918c2ecf20Sopenharmony_ci{
28928c2ecf20Sopenharmony_ci	struct scsi_device *sdp = scp->device;
28938c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	if (lba + num > sdebug_capacity) {
28968c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
28978c2ecf20Sopenharmony_ci		return check_condition_result;
28988c2ecf20Sopenharmony_ci	}
28998c2ecf20Sopenharmony_ci	/* transfer length excessive (tie in to block limits VPD page) */
29008c2ecf20Sopenharmony_ci	if (num > sdebug_store_sectors) {
29018c2ecf20Sopenharmony_ci		/* needs work to find which cdb byte 'num' comes from */
29028c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
29038c2ecf20Sopenharmony_ci		return check_condition_result;
29048c2ecf20Sopenharmony_ci	}
29058c2ecf20Sopenharmony_ci	if (write && unlikely(sdebug_wp)) {
29068c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
29078c2ecf20Sopenharmony_ci		return check_condition_result;
29088c2ecf20Sopenharmony_ci	}
29098c2ecf20Sopenharmony_ci	if (sdebug_dev_is_zoned(devip))
29108c2ecf20Sopenharmony_ci		return check_zbc_access_params(scp, lba, num, write);
29118c2ecf20Sopenharmony_ci
29128c2ecf20Sopenharmony_ci	return 0;
29138c2ecf20Sopenharmony_ci}
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci/*
29168c2ecf20Sopenharmony_ci * Note: if BUG_ON() fires it usually indicates a problem with the parser
29178c2ecf20Sopenharmony_ci * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions
29188c2ecf20Sopenharmony_ci * that access any of the "stores" in struct sdeb_store_info should call this
29198c2ecf20Sopenharmony_ci * function with bug_if_fake_rw set to true.
29208c2ecf20Sopenharmony_ci */
29218c2ecf20Sopenharmony_cistatic inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip,
29228c2ecf20Sopenharmony_ci						bool bug_if_fake_rw)
29238c2ecf20Sopenharmony_ci{
29248c2ecf20Sopenharmony_ci	if (sdebug_fake_rw) {
29258c2ecf20Sopenharmony_ci		BUG_ON(bug_if_fake_rw);	/* See note above */
29268c2ecf20Sopenharmony_ci		return NULL;
29278c2ecf20Sopenharmony_ci	}
29288c2ecf20Sopenharmony_ci	return xa_load(per_store_ap, devip->sdbg_host->si_idx);
29298c2ecf20Sopenharmony_ci}
29308c2ecf20Sopenharmony_ci
29318c2ecf20Sopenharmony_ci/* Returns number of bytes copied or -1 if error. */
29328c2ecf20Sopenharmony_cistatic int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp,
29338c2ecf20Sopenharmony_ci			    u32 sg_skip, u64 lba, u32 num, bool do_write)
29348c2ecf20Sopenharmony_ci{
29358c2ecf20Sopenharmony_ci	int ret;
29368c2ecf20Sopenharmony_ci	u64 block, rest = 0;
29378c2ecf20Sopenharmony_ci	enum dma_data_direction dir;
29388c2ecf20Sopenharmony_ci	struct scsi_data_buffer *sdb = &scp->sdb;
29398c2ecf20Sopenharmony_ci	u8 *fsp;
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ci	if (do_write) {
29428c2ecf20Sopenharmony_ci		dir = DMA_TO_DEVICE;
29438c2ecf20Sopenharmony_ci		write_since_sync = true;
29448c2ecf20Sopenharmony_ci	} else {
29458c2ecf20Sopenharmony_ci		dir = DMA_FROM_DEVICE;
29468c2ecf20Sopenharmony_ci	}
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_ci	if (!sdb->length || !sip)
29498c2ecf20Sopenharmony_ci		return 0;
29508c2ecf20Sopenharmony_ci	if (scp->sc_data_direction != dir)
29518c2ecf20Sopenharmony_ci		return -1;
29528c2ecf20Sopenharmony_ci	fsp = sip->storep;
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci	block = do_div(lba, sdebug_store_sectors);
29558c2ecf20Sopenharmony_ci	if (block + num > sdebug_store_sectors)
29568c2ecf20Sopenharmony_ci		rest = block + num - sdebug_store_sectors;
29578c2ecf20Sopenharmony_ci
29588c2ecf20Sopenharmony_ci	ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
29598c2ecf20Sopenharmony_ci		   fsp + (block * sdebug_sector_size),
29608c2ecf20Sopenharmony_ci		   (num - rest) * sdebug_sector_size, sg_skip, do_write);
29618c2ecf20Sopenharmony_ci	if (ret != (num - rest) * sdebug_sector_size)
29628c2ecf20Sopenharmony_ci		return ret;
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	if (rest) {
29658c2ecf20Sopenharmony_ci		ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
29668c2ecf20Sopenharmony_ci			    fsp, rest * sdebug_sector_size,
29678c2ecf20Sopenharmony_ci			    sg_skip + ((num - rest) * sdebug_sector_size),
29688c2ecf20Sopenharmony_ci			    do_write);
29698c2ecf20Sopenharmony_ci	}
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	return ret;
29728c2ecf20Sopenharmony_ci}
29738c2ecf20Sopenharmony_ci
29748c2ecf20Sopenharmony_ci/* Returns number of bytes copied or -1 if error. */
29758c2ecf20Sopenharmony_cistatic int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp)
29768c2ecf20Sopenharmony_ci{
29778c2ecf20Sopenharmony_ci	struct scsi_data_buffer *sdb = &scp->sdb;
29788c2ecf20Sopenharmony_ci
29798c2ecf20Sopenharmony_ci	if (!sdb->length)
29808c2ecf20Sopenharmony_ci		return 0;
29818c2ecf20Sopenharmony_ci	if (scp->sc_data_direction != DMA_TO_DEVICE)
29828c2ecf20Sopenharmony_ci		return -1;
29838c2ecf20Sopenharmony_ci	return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp,
29848c2ecf20Sopenharmony_ci			      num * sdebug_sector_size, 0, true);
29858c2ecf20Sopenharmony_ci}
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci/* If sip->storep+lba compares equal to arr(num), then copy top half of
29888c2ecf20Sopenharmony_ci * arr into sip->storep+lba and return true. If comparison fails then
29898c2ecf20Sopenharmony_ci * return false. */
29908c2ecf20Sopenharmony_cistatic bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num,
29918c2ecf20Sopenharmony_ci			      const u8 *arr, bool compare_only)
29928c2ecf20Sopenharmony_ci{
29938c2ecf20Sopenharmony_ci	bool res;
29948c2ecf20Sopenharmony_ci	u64 block, rest = 0;
29958c2ecf20Sopenharmony_ci	u32 store_blks = sdebug_store_sectors;
29968c2ecf20Sopenharmony_ci	u32 lb_size = sdebug_sector_size;
29978c2ecf20Sopenharmony_ci	u8 *fsp = sip->storep;
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	block = do_div(lba, store_blks);
30008c2ecf20Sopenharmony_ci	if (block + num > store_blks)
30018c2ecf20Sopenharmony_ci		rest = block + num - store_blks;
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci	res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size);
30048c2ecf20Sopenharmony_ci	if (!res)
30058c2ecf20Sopenharmony_ci		return res;
30068c2ecf20Sopenharmony_ci	if (rest)
30078c2ecf20Sopenharmony_ci		res = memcmp(fsp, arr + ((num - rest) * lb_size),
30088c2ecf20Sopenharmony_ci			     rest * lb_size);
30098c2ecf20Sopenharmony_ci	if (!res)
30108c2ecf20Sopenharmony_ci		return res;
30118c2ecf20Sopenharmony_ci	if (compare_only)
30128c2ecf20Sopenharmony_ci		return true;
30138c2ecf20Sopenharmony_ci	arr += num * lb_size;
30148c2ecf20Sopenharmony_ci	memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size);
30158c2ecf20Sopenharmony_ci	if (rest)
30168c2ecf20Sopenharmony_ci		memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size);
30178c2ecf20Sopenharmony_ci	return res;
30188c2ecf20Sopenharmony_ci}
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_cistatic __be16 dif_compute_csum(const void *buf, int len)
30218c2ecf20Sopenharmony_ci{
30228c2ecf20Sopenharmony_ci	__be16 csum;
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_ci	if (sdebug_guard)
30258c2ecf20Sopenharmony_ci		csum = (__force __be16)ip_compute_csum(buf, len);
30268c2ecf20Sopenharmony_ci	else
30278c2ecf20Sopenharmony_ci		csum = cpu_to_be16(crc_t10dif(buf, len));
30288c2ecf20Sopenharmony_ci
30298c2ecf20Sopenharmony_ci	return csum;
30308c2ecf20Sopenharmony_ci}
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_cistatic int dif_verify(struct t10_pi_tuple *sdt, const void *data,
30338c2ecf20Sopenharmony_ci		      sector_t sector, u32 ei_lba)
30348c2ecf20Sopenharmony_ci{
30358c2ecf20Sopenharmony_ci	__be16 csum = dif_compute_csum(data, sdebug_sector_size);
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	if (sdt->guard_tag != csum) {
30388c2ecf20Sopenharmony_ci		pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
30398c2ecf20Sopenharmony_ci			(unsigned long)sector,
30408c2ecf20Sopenharmony_ci			be16_to_cpu(sdt->guard_tag),
30418c2ecf20Sopenharmony_ci			be16_to_cpu(csum));
30428c2ecf20Sopenharmony_ci		return 0x01;
30438c2ecf20Sopenharmony_ci	}
30448c2ecf20Sopenharmony_ci	if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
30458c2ecf20Sopenharmony_ci	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
30468c2ecf20Sopenharmony_ci		pr_err("REF check failed on sector %lu\n",
30478c2ecf20Sopenharmony_ci			(unsigned long)sector);
30488c2ecf20Sopenharmony_ci		return 0x03;
30498c2ecf20Sopenharmony_ci	}
30508c2ecf20Sopenharmony_ci	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
30518c2ecf20Sopenharmony_ci	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
30528c2ecf20Sopenharmony_ci		pr_err("REF check failed on sector %lu\n",
30538c2ecf20Sopenharmony_ci			(unsigned long)sector);
30548c2ecf20Sopenharmony_ci		return 0x03;
30558c2ecf20Sopenharmony_ci	}
30568c2ecf20Sopenharmony_ci	return 0;
30578c2ecf20Sopenharmony_ci}
30588c2ecf20Sopenharmony_ci
30598c2ecf20Sopenharmony_cistatic void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector,
30608c2ecf20Sopenharmony_ci			  unsigned int sectors, bool read)
30618c2ecf20Sopenharmony_ci{
30628c2ecf20Sopenharmony_ci	size_t resid;
30638c2ecf20Sopenharmony_ci	void *paddr;
30648c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
30658c2ecf20Sopenharmony_ci						scp->device->hostdata, true);
30668c2ecf20Sopenharmony_ci	struct t10_pi_tuple *dif_storep = sip->dif_storep;
30678c2ecf20Sopenharmony_ci	const void *dif_store_end = dif_storep + sdebug_store_sectors;
30688c2ecf20Sopenharmony_ci	struct sg_mapping_iter miter;
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	/* Bytes of protection data to copy into sgl */
30718c2ecf20Sopenharmony_ci	resid = sectors * sizeof(*dif_storep);
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	sg_miter_start(&miter, scsi_prot_sglist(scp),
30748c2ecf20Sopenharmony_ci		       scsi_prot_sg_count(scp), SG_MITER_ATOMIC |
30758c2ecf20Sopenharmony_ci		       (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci	while (sg_miter_next(&miter) && resid > 0) {
30788c2ecf20Sopenharmony_ci		size_t len = min_t(size_t, miter.length, resid);
30798c2ecf20Sopenharmony_ci		void *start = dif_store(sip, sector);
30808c2ecf20Sopenharmony_ci		size_t rest = 0;
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_ci		if (dif_store_end < start + len)
30838c2ecf20Sopenharmony_ci			rest = start + len - dif_store_end;
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ci		paddr = miter.addr;
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci		if (read)
30888c2ecf20Sopenharmony_ci			memcpy(paddr, start, len - rest);
30898c2ecf20Sopenharmony_ci		else
30908c2ecf20Sopenharmony_ci			memcpy(start, paddr, len - rest);
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci		if (rest) {
30938c2ecf20Sopenharmony_ci			if (read)
30948c2ecf20Sopenharmony_ci				memcpy(paddr + len - rest, dif_storep, rest);
30958c2ecf20Sopenharmony_ci			else
30968c2ecf20Sopenharmony_ci				memcpy(dif_storep, paddr + len - rest, rest);
30978c2ecf20Sopenharmony_ci		}
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci		sector += len / sizeof(*dif_storep);
31008c2ecf20Sopenharmony_ci		resid -= len;
31018c2ecf20Sopenharmony_ci	}
31028c2ecf20Sopenharmony_ci	sg_miter_stop(&miter);
31038c2ecf20Sopenharmony_ci}
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_cistatic int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
31068c2ecf20Sopenharmony_ci			    unsigned int sectors, u32 ei_lba)
31078c2ecf20Sopenharmony_ci{
31088c2ecf20Sopenharmony_ci	unsigned int i;
31098c2ecf20Sopenharmony_ci	sector_t sector;
31108c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
31118c2ecf20Sopenharmony_ci						scp->device->hostdata, true);
31128c2ecf20Sopenharmony_ci	struct t10_pi_tuple *sdt;
31138c2ecf20Sopenharmony_ci
31148c2ecf20Sopenharmony_ci	for (i = 0; i < sectors; i++, ei_lba++) {
31158c2ecf20Sopenharmony_ci		int ret;
31168c2ecf20Sopenharmony_ci
31178c2ecf20Sopenharmony_ci		sector = start_sec + i;
31188c2ecf20Sopenharmony_ci		sdt = dif_store(sip, sector);
31198c2ecf20Sopenharmony_ci
31208c2ecf20Sopenharmony_ci		if (sdt->app_tag == cpu_to_be16(0xffff))
31218c2ecf20Sopenharmony_ci			continue;
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci		ret = dif_verify(sdt, lba2fake_store(sip, sector), sector,
31248c2ecf20Sopenharmony_ci				 ei_lba);
31258c2ecf20Sopenharmony_ci		if (ret) {
31268c2ecf20Sopenharmony_ci			dif_errors++;
31278c2ecf20Sopenharmony_ci			return ret;
31288c2ecf20Sopenharmony_ci		}
31298c2ecf20Sopenharmony_ci	}
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci	dif_copy_prot(scp, start_sec, sectors, true);
31328c2ecf20Sopenharmony_ci	dix_reads++;
31338c2ecf20Sopenharmony_ci
31348c2ecf20Sopenharmony_ci	return 0;
31358c2ecf20Sopenharmony_ci}
31368c2ecf20Sopenharmony_ci
31378c2ecf20Sopenharmony_cistatic int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
31388c2ecf20Sopenharmony_ci{
31398c2ecf20Sopenharmony_ci	bool check_prot;
31408c2ecf20Sopenharmony_ci	u32 num;
31418c2ecf20Sopenharmony_ci	u32 ei_lba;
31428c2ecf20Sopenharmony_ci	int ret;
31438c2ecf20Sopenharmony_ci	u64 lba;
31448c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, true);
31458c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
31468c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci	switch (cmd[0]) {
31498c2ecf20Sopenharmony_ci	case READ_16:
31508c2ecf20Sopenharmony_ci		ei_lba = 0;
31518c2ecf20Sopenharmony_ci		lba = get_unaligned_be64(cmd + 2);
31528c2ecf20Sopenharmony_ci		num = get_unaligned_be32(cmd + 10);
31538c2ecf20Sopenharmony_ci		check_prot = true;
31548c2ecf20Sopenharmony_ci		break;
31558c2ecf20Sopenharmony_ci	case READ_10:
31568c2ecf20Sopenharmony_ci		ei_lba = 0;
31578c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
31588c2ecf20Sopenharmony_ci		num = get_unaligned_be16(cmd + 7);
31598c2ecf20Sopenharmony_ci		check_prot = true;
31608c2ecf20Sopenharmony_ci		break;
31618c2ecf20Sopenharmony_ci	case READ_6:
31628c2ecf20Sopenharmony_ci		ei_lba = 0;
31638c2ecf20Sopenharmony_ci		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
31648c2ecf20Sopenharmony_ci		      (u32)(cmd[1] & 0x1f) << 16;
31658c2ecf20Sopenharmony_ci		num = (0 == cmd[4]) ? 256 : cmd[4];
31668c2ecf20Sopenharmony_ci		check_prot = true;
31678c2ecf20Sopenharmony_ci		break;
31688c2ecf20Sopenharmony_ci	case READ_12:
31698c2ecf20Sopenharmony_ci		ei_lba = 0;
31708c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
31718c2ecf20Sopenharmony_ci		num = get_unaligned_be32(cmd + 6);
31728c2ecf20Sopenharmony_ci		check_prot = true;
31738c2ecf20Sopenharmony_ci		break;
31748c2ecf20Sopenharmony_ci	case XDWRITEREAD_10:
31758c2ecf20Sopenharmony_ci		ei_lba = 0;
31768c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
31778c2ecf20Sopenharmony_ci		num = get_unaligned_be16(cmd + 7);
31788c2ecf20Sopenharmony_ci		check_prot = false;
31798c2ecf20Sopenharmony_ci		break;
31808c2ecf20Sopenharmony_ci	default:	/* assume READ(32) */
31818c2ecf20Sopenharmony_ci		lba = get_unaligned_be64(cmd + 12);
31828c2ecf20Sopenharmony_ci		ei_lba = get_unaligned_be32(cmd + 20);
31838c2ecf20Sopenharmony_ci		num = get_unaligned_be32(cmd + 28);
31848c2ecf20Sopenharmony_ci		check_prot = false;
31858c2ecf20Sopenharmony_ci		break;
31868c2ecf20Sopenharmony_ci	}
31878c2ecf20Sopenharmony_ci	if (unlikely(have_dif_prot && check_prot)) {
31888c2ecf20Sopenharmony_ci		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
31898c2ecf20Sopenharmony_ci		    (cmd[1] & 0xe0)) {
31908c2ecf20Sopenharmony_ci			mk_sense_invalid_opcode(scp);
31918c2ecf20Sopenharmony_ci			return check_condition_result;
31928c2ecf20Sopenharmony_ci		}
31938c2ecf20Sopenharmony_ci		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
31948c2ecf20Sopenharmony_ci		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
31958c2ecf20Sopenharmony_ci		    (cmd[1] & 0xe0) == 0)
31968c2ecf20Sopenharmony_ci			sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
31978c2ecf20Sopenharmony_ci				    "to DIF device\n");
31988c2ecf20Sopenharmony_ci	}
31998c2ecf20Sopenharmony_ci	if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) &&
32008c2ecf20Sopenharmony_ci		     atomic_read(&sdeb_inject_pending))) {
32018c2ecf20Sopenharmony_ci		num /= 2;
32028c2ecf20Sopenharmony_ci		atomic_set(&sdeb_inject_pending, 0);
32038c2ecf20Sopenharmony_ci	}
32048c2ecf20Sopenharmony_ci
32058c2ecf20Sopenharmony_ci	ret = check_device_access_params(scp, lba, num, false);
32068c2ecf20Sopenharmony_ci	if (ret)
32078c2ecf20Sopenharmony_ci		return ret;
32088c2ecf20Sopenharmony_ci	if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
32098c2ecf20Sopenharmony_ci		     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
32108c2ecf20Sopenharmony_ci		     ((lba + num) > sdebug_medium_error_start))) {
32118c2ecf20Sopenharmony_ci		/* claim unrecoverable read error */
32128c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
32138c2ecf20Sopenharmony_ci		/* set info field and valid bit for fixed descriptor */
32148c2ecf20Sopenharmony_ci		if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
32158c2ecf20Sopenharmony_ci			scp->sense_buffer[0] |= 0x80;	/* Valid bit */
32168c2ecf20Sopenharmony_ci			ret = (lba < OPT_MEDIUM_ERR_ADDR)
32178c2ecf20Sopenharmony_ci			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;
32188c2ecf20Sopenharmony_ci			put_unaligned_be32(ret, scp->sense_buffer + 3);
32198c2ecf20Sopenharmony_ci		}
32208c2ecf20Sopenharmony_ci		scsi_set_resid(scp, scsi_bufflen(scp));
32218c2ecf20Sopenharmony_ci		return check_condition_result;
32228c2ecf20Sopenharmony_ci	}
32238c2ecf20Sopenharmony_ci
32248c2ecf20Sopenharmony_ci	read_lock(macc_lckp);
32258c2ecf20Sopenharmony_ci
32268c2ecf20Sopenharmony_ci	/* DIX + T10 DIF */
32278c2ecf20Sopenharmony_ci	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
32288c2ecf20Sopenharmony_ci		int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
32298c2ecf20Sopenharmony_ci
32308c2ecf20Sopenharmony_ci		if (prot_ret) {
32318c2ecf20Sopenharmony_ci			read_unlock(macc_lckp);
32328c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
32338c2ecf20Sopenharmony_ci			return illegal_condition_result;
32348c2ecf20Sopenharmony_ci		}
32358c2ecf20Sopenharmony_ci	}
32368c2ecf20Sopenharmony_ci
32378c2ecf20Sopenharmony_ci	ret = do_device_access(sip, scp, 0, lba, num, false);
32388c2ecf20Sopenharmony_ci	read_unlock(macc_lckp);
32398c2ecf20Sopenharmony_ci	if (unlikely(ret == -1))
32408c2ecf20Sopenharmony_ci		return DID_ERROR << 16;
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci	scsi_set_resid(scp, scsi_bufflen(scp) - ret);
32438c2ecf20Sopenharmony_ci
32448c2ecf20Sopenharmony_ci	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
32458c2ecf20Sopenharmony_ci		     atomic_read(&sdeb_inject_pending))) {
32468c2ecf20Sopenharmony_ci		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
32478c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
32488c2ecf20Sopenharmony_ci			atomic_set(&sdeb_inject_pending, 0);
32498c2ecf20Sopenharmony_ci			return check_condition_result;
32508c2ecf20Sopenharmony_ci		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
32518c2ecf20Sopenharmony_ci			/* Logical block guard check failed */
32528c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
32538c2ecf20Sopenharmony_ci			atomic_set(&sdeb_inject_pending, 0);
32548c2ecf20Sopenharmony_ci			return illegal_condition_result;
32558c2ecf20Sopenharmony_ci		} else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) {
32568c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
32578c2ecf20Sopenharmony_ci			atomic_set(&sdeb_inject_pending, 0);
32588c2ecf20Sopenharmony_ci			return illegal_condition_result;
32598c2ecf20Sopenharmony_ci		}
32608c2ecf20Sopenharmony_ci	}
32618c2ecf20Sopenharmony_ci	return 0;
32628c2ecf20Sopenharmony_ci}
32638c2ecf20Sopenharmony_ci
32648c2ecf20Sopenharmony_cistatic void dump_sector(unsigned char *buf, int len)
32658c2ecf20Sopenharmony_ci{
32668c2ecf20Sopenharmony_ci	int i, j, n;
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	pr_err(">>> Sector Dump <<<\n");
32698c2ecf20Sopenharmony_ci	for (i = 0 ; i < len ; i += 16) {
32708c2ecf20Sopenharmony_ci		char b[128];
32718c2ecf20Sopenharmony_ci
32728c2ecf20Sopenharmony_ci		for (j = 0, n = 0; j < 16; j++) {
32738c2ecf20Sopenharmony_ci			unsigned char c = buf[i+j];
32748c2ecf20Sopenharmony_ci
32758c2ecf20Sopenharmony_ci			if (c >= 0x20 && c < 0x7e)
32768c2ecf20Sopenharmony_ci				n += scnprintf(b + n, sizeof(b) - n,
32778c2ecf20Sopenharmony_ci					       " %c ", buf[i+j]);
32788c2ecf20Sopenharmony_ci			else
32798c2ecf20Sopenharmony_ci				n += scnprintf(b + n, sizeof(b) - n,
32808c2ecf20Sopenharmony_ci					       "%02x ", buf[i+j]);
32818c2ecf20Sopenharmony_ci		}
32828c2ecf20Sopenharmony_ci		pr_err("%04d: %s\n", i, b);
32838c2ecf20Sopenharmony_ci	}
32848c2ecf20Sopenharmony_ci}
32858c2ecf20Sopenharmony_ci
32868c2ecf20Sopenharmony_cistatic int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
32878c2ecf20Sopenharmony_ci			     unsigned int sectors, u32 ei_lba)
32888c2ecf20Sopenharmony_ci{
32898c2ecf20Sopenharmony_ci	int ret;
32908c2ecf20Sopenharmony_ci	struct t10_pi_tuple *sdt;
32918c2ecf20Sopenharmony_ci	void *daddr;
32928c2ecf20Sopenharmony_ci	sector_t sector = start_sec;
32938c2ecf20Sopenharmony_ci	int ppage_offset;
32948c2ecf20Sopenharmony_ci	int dpage_offset;
32958c2ecf20Sopenharmony_ci	struct sg_mapping_iter diter;
32968c2ecf20Sopenharmony_ci	struct sg_mapping_iter piter;
32978c2ecf20Sopenharmony_ci
32988c2ecf20Sopenharmony_ci	BUG_ON(scsi_sg_count(SCpnt) == 0);
32998c2ecf20Sopenharmony_ci	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
33008c2ecf20Sopenharmony_ci
33018c2ecf20Sopenharmony_ci	sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
33028c2ecf20Sopenharmony_ci			scsi_prot_sg_count(SCpnt),
33038c2ecf20Sopenharmony_ci			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
33048c2ecf20Sopenharmony_ci	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
33058c2ecf20Sopenharmony_ci			SG_MITER_ATOMIC | SG_MITER_FROM_SG);
33068c2ecf20Sopenharmony_ci
33078c2ecf20Sopenharmony_ci	/* For each protection page */
33088c2ecf20Sopenharmony_ci	while (sg_miter_next(&piter)) {
33098c2ecf20Sopenharmony_ci		dpage_offset = 0;
33108c2ecf20Sopenharmony_ci		if (WARN_ON(!sg_miter_next(&diter))) {
33118c2ecf20Sopenharmony_ci			ret = 0x01;
33128c2ecf20Sopenharmony_ci			goto out;
33138c2ecf20Sopenharmony_ci		}
33148c2ecf20Sopenharmony_ci
33158c2ecf20Sopenharmony_ci		for (ppage_offset = 0; ppage_offset < piter.length;
33168c2ecf20Sopenharmony_ci		     ppage_offset += sizeof(struct t10_pi_tuple)) {
33178c2ecf20Sopenharmony_ci			/* If we're at the end of the current
33188c2ecf20Sopenharmony_ci			 * data page advance to the next one
33198c2ecf20Sopenharmony_ci			 */
33208c2ecf20Sopenharmony_ci			if (dpage_offset >= diter.length) {
33218c2ecf20Sopenharmony_ci				if (WARN_ON(!sg_miter_next(&diter))) {
33228c2ecf20Sopenharmony_ci					ret = 0x01;
33238c2ecf20Sopenharmony_ci					goto out;
33248c2ecf20Sopenharmony_ci				}
33258c2ecf20Sopenharmony_ci				dpage_offset = 0;
33268c2ecf20Sopenharmony_ci			}
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci			sdt = piter.addr + ppage_offset;
33298c2ecf20Sopenharmony_ci			daddr = diter.addr + dpage_offset;
33308c2ecf20Sopenharmony_ci
33318c2ecf20Sopenharmony_ci			ret = dif_verify(sdt, daddr, sector, ei_lba);
33328c2ecf20Sopenharmony_ci			if (ret) {
33338c2ecf20Sopenharmony_ci				dump_sector(daddr, sdebug_sector_size);
33348c2ecf20Sopenharmony_ci				goto out;
33358c2ecf20Sopenharmony_ci			}
33368c2ecf20Sopenharmony_ci
33378c2ecf20Sopenharmony_ci			sector++;
33388c2ecf20Sopenharmony_ci			ei_lba++;
33398c2ecf20Sopenharmony_ci			dpage_offset += sdebug_sector_size;
33408c2ecf20Sopenharmony_ci		}
33418c2ecf20Sopenharmony_ci		diter.consumed = dpage_offset;
33428c2ecf20Sopenharmony_ci		sg_miter_stop(&diter);
33438c2ecf20Sopenharmony_ci	}
33448c2ecf20Sopenharmony_ci	sg_miter_stop(&piter);
33458c2ecf20Sopenharmony_ci
33468c2ecf20Sopenharmony_ci	dif_copy_prot(SCpnt, start_sec, sectors, false);
33478c2ecf20Sopenharmony_ci	dix_writes++;
33488c2ecf20Sopenharmony_ci
33498c2ecf20Sopenharmony_ci	return 0;
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ciout:
33528c2ecf20Sopenharmony_ci	dif_errors++;
33538c2ecf20Sopenharmony_ci	sg_miter_stop(&diter);
33548c2ecf20Sopenharmony_ci	sg_miter_stop(&piter);
33558c2ecf20Sopenharmony_ci	return ret;
33568c2ecf20Sopenharmony_ci}
33578c2ecf20Sopenharmony_ci
33588c2ecf20Sopenharmony_cistatic unsigned long lba_to_map_index(sector_t lba)
33598c2ecf20Sopenharmony_ci{
33608c2ecf20Sopenharmony_ci	if (sdebug_unmap_alignment)
33618c2ecf20Sopenharmony_ci		lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
33628c2ecf20Sopenharmony_ci	sector_div(lba, sdebug_unmap_granularity);
33638c2ecf20Sopenharmony_ci	return lba;
33648c2ecf20Sopenharmony_ci}
33658c2ecf20Sopenharmony_ci
33668c2ecf20Sopenharmony_cistatic sector_t map_index_to_lba(unsigned long index)
33678c2ecf20Sopenharmony_ci{
33688c2ecf20Sopenharmony_ci	sector_t lba = index * sdebug_unmap_granularity;
33698c2ecf20Sopenharmony_ci
33708c2ecf20Sopenharmony_ci	if (sdebug_unmap_alignment)
33718c2ecf20Sopenharmony_ci		lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
33728c2ecf20Sopenharmony_ci	return lba;
33738c2ecf20Sopenharmony_ci}
33748c2ecf20Sopenharmony_ci
33758c2ecf20Sopenharmony_cistatic unsigned int map_state(struct sdeb_store_info *sip, sector_t lba,
33768c2ecf20Sopenharmony_ci			      unsigned int *num)
33778c2ecf20Sopenharmony_ci{
33788c2ecf20Sopenharmony_ci	sector_t end;
33798c2ecf20Sopenharmony_ci	unsigned int mapped;
33808c2ecf20Sopenharmony_ci	unsigned long index;
33818c2ecf20Sopenharmony_ci	unsigned long next;
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_ci	index = lba_to_map_index(lba);
33848c2ecf20Sopenharmony_ci	mapped = test_bit(index, sip->map_storep);
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_ci	if (mapped)
33878c2ecf20Sopenharmony_ci		next = find_next_zero_bit(sip->map_storep, map_size, index);
33888c2ecf20Sopenharmony_ci	else
33898c2ecf20Sopenharmony_ci		next = find_next_bit(sip->map_storep, map_size, index);
33908c2ecf20Sopenharmony_ci
33918c2ecf20Sopenharmony_ci	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));
33928c2ecf20Sopenharmony_ci	*num = end - lba;
33938c2ecf20Sopenharmony_ci	return mapped;
33948c2ecf20Sopenharmony_ci}
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_cistatic void map_region(struct sdeb_store_info *sip, sector_t lba,
33978c2ecf20Sopenharmony_ci		       unsigned int len)
33988c2ecf20Sopenharmony_ci{
33998c2ecf20Sopenharmony_ci	sector_t end = lba + len;
34008c2ecf20Sopenharmony_ci
34018c2ecf20Sopenharmony_ci	while (lba < end) {
34028c2ecf20Sopenharmony_ci		unsigned long index = lba_to_map_index(lba);
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci		if (index < map_size)
34058c2ecf20Sopenharmony_ci			set_bit(index, sip->map_storep);
34068c2ecf20Sopenharmony_ci
34078c2ecf20Sopenharmony_ci		lba = map_index_to_lba(index + 1);
34088c2ecf20Sopenharmony_ci	}
34098c2ecf20Sopenharmony_ci}
34108c2ecf20Sopenharmony_ci
34118c2ecf20Sopenharmony_cistatic void unmap_region(struct sdeb_store_info *sip, sector_t lba,
34128c2ecf20Sopenharmony_ci			 unsigned int len)
34138c2ecf20Sopenharmony_ci{
34148c2ecf20Sopenharmony_ci	sector_t end = lba + len;
34158c2ecf20Sopenharmony_ci	u8 *fsp = sip->storep;
34168c2ecf20Sopenharmony_ci
34178c2ecf20Sopenharmony_ci	while (lba < end) {
34188c2ecf20Sopenharmony_ci		unsigned long index = lba_to_map_index(lba);
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci		if (lba == map_index_to_lba(index) &&
34218c2ecf20Sopenharmony_ci		    lba + sdebug_unmap_granularity <= end &&
34228c2ecf20Sopenharmony_ci		    index < map_size) {
34238c2ecf20Sopenharmony_ci			clear_bit(index, sip->map_storep);
34248c2ecf20Sopenharmony_ci			if (sdebug_lbprz) {  /* for LBPRZ=2 return 0xff_s */
34258c2ecf20Sopenharmony_ci				memset(fsp + lba * sdebug_sector_size,
34268c2ecf20Sopenharmony_ci				       (sdebug_lbprz & 1) ? 0 : 0xff,
34278c2ecf20Sopenharmony_ci				       sdebug_sector_size *
34288c2ecf20Sopenharmony_ci				       sdebug_unmap_granularity);
34298c2ecf20Sopenharmony_ci			}
34308c2ecf20Sopenharmony_ci			if (sip->dif_storep) {
34318c2ecf20Sopenharmony_ci				memset(sip->dif_storep + lba, 0xff,
34328c2ecf20Sopenharmony_ci				       sizeof(*sip->dif_storep) *
34338c2ecf20Sopenharmony_ci				       sdebug_unmap_granularity);
34348c2ecf20Sopenharmony_ci			}
34358c2ecf20Sopenharmony_ci		}
34368c2ecf20Sopenharmony_ci		lba = map_index_to_lba(index + 1);
34378c2ecf20Sopenharmony_ci	}
34388c2ecf20Sopenharmony_ci}
34398c2ecf20Sopenharmony_ci
34408c2ecf20Sopenharmony_cistatic int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
34418c2ecf20Sopenharmony_ci{
34428c2ecf20Sopenharmony_ci	bool check_prot;
34438c2ecf20Sopenharmony_ci	u32 num;
34448c2ecf20Sopenharmony_ci	u32 ei_lba;
34458c2ecf20Sopenharmony_ci	int ret;
34468c2ecf20Sopenharmony_ci	u64 lba;
34478c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, true);
34488c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = &sip->macc_lck;
34498c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_ci	switch (cmd[0]) {
34528c2ecf20Sopenharmony_ci	case WRITE_16:
34538c2ecf20Sopenharmony_ci		ei_lba = 0;
34548c2ecf20Sopenharmony_ci		lba = get_unaligned_be64(cmd + 2);
34558c2ecf20Sopenharmony_ci		num = get_unaligned_be32(cmd + 10);
34568c2ecf20Sopenharmony_ci		check_prot = true;
34578c2ecf20Sopenharmony_ci		break;
34588c2ecf20Sopenharmony_ci	case WRITE_10:
34598c2ecf20Sopenharmony_ci		ei_lba = 0;
34608c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
34618c2ecf20Sopenharmony_ci		num = get_unaligned_be16(cmd + 7);
34628c2ecf20Sopenharmony_ci		check_prot = true;
34638c2ecf20Sopenharmony_ci		break;
34648c2ecf20Sopenharmony_ci	case WRITE_6:
34658c2ecf20Sopenharmony_ci		ei_lba = 0;
34668c2ecf20Sopenharmony_ci		lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
34678c2ecf20Sopenharmony_ci		      (u32)(cmd[1] & 0x1f) << 16;
34688c2ecf20Sopenharmony_ci		num = (0 == cmd[4]) ? 256 : cmd[4];
34698c2ecf20Sopenharmony_ci		check_prot = true;
34708c2ecf20Sopenharmony_ci		break;
34718c2ecf20Sopenharmony_ci	case WRITE_12:
34728c2ecf20Sopenharmony_ci		ei_lba = 0;
34738c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
34748c2ecf20Sopenharmony_ci		num = get_unaligned_be32(cmd + 6);
34758c2ecf20Sopenharmony_ci		check_prot = true;
34768c2ecf20Sopenharmony_ci		break;
34778c2ecf20Sopenharmony_ci	case 0x53:	/* XDWRITEREAD(10) */
34788c2ecf20Sopenharmony_ci		ei_lba = 0;
34798c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
34808c2ecf20Sopenharmony_ci		num = get_unaligned_be16(cmd + 7);
34818c2ecf20Sopenharmony_ci		check_prot = false;
34828c2ecf20Sopenharmony_ci		break;
34838c2ecf20Sopenharmony_ci	default:	/* assume WRITE(32) */
34848c2ecf20Sopenharmony_ci		lba = get_unaligned_be64(cmd + 12);
34858c2ecf20Sopenharmony_ci		ei_lba = get_unaligned_be32(cmd + 20);
34868c2ecf20Sopenharmony_ci		num = get_unaligned_be32(cmd + 28);
34878c2ecf20Sopenharmony_ci		check_prot = false;
34888c2ecf20Sopenharmony_ci		break;
34898c2ecf20Sopenharmony_ci	}
34908c2ecf20Sopenharmony_ci	if (unlikely(have_dif_prot && check_prot)) {
34918c2ecf20Sopenharmony_ci		if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
34928c2ecf20Sopenharmony_ci		    (cmd[1] & 0xe0)) {
34938c2ecf20Sopenharmony_ci			mk_sense_invalid_opcode(scp);
34948c2ecf20Sopenharmony_ci			return check_condition_result;
34958c2ecf20Sopenharmony_ci		}
34968c2ecf20Sopenharmony_ci		if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
34978c2ecf20Sopenharmony_ci		     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
34988c2ecf20Sopenharmony_ci		    (cmd[1] & 0xe0) == 0)
34998c2ecf20Sopenharmony_ci			sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
35008c2ecf20Sopenharmony_ci				    "to DIF device\n");
35018c2ecf20Sopenharmony_ci	}
35028c2ecf20Sopenharmony_ci
35038c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
35048c2ecf20Sopenharmony_ci	ret = check_device_access_params(scp, lba, num, true);
35058c2ecf20Sopenharmony_ci	if (ret) {
35068c2ecf20Sopenharmony_ci		write_unlock(macc_lckp);
35078c2ecf20Sopenharmony_ci		return ret;
35088c2ecf20Sopenharmony_ci	}
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci	/* DIX + T10 DIF */
35118c2ecf20Sopenharmony_ci	if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
35128c2ecf20Sopenharmony_ci		int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
35138c2ecf20Sopenharmony_ci
35148c2ecf20Sopenharmony_ci		if (prot_ret) {
35158c2ecf20Sopenharmony_ci			write_unlock(macc_lckp);
35168c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
35178c2ecf20Sopenharmony_ci			return illegal_condition_result;
35188c2ecf20Sopenharmony_ci		}
35198c2ecf20Sopenharmony_ci	}
35208c2ecf20Sopenharmony_ci
35218c2ecf20Sopenharmony_ci	ret = do_device_access(sip, scp, 0, lba, num, true);
35228c2ecf20Sopenharmony_ci	if (unlikely(scsi_debug_lbp()))
35238c2ecf20Sopenharmony_ci		map_region(sip, lba, num);
35248c2ecf20Sopenharmony_ci	/* If ZBC zone then bump its write pointer */
35258c2ecf20Sopenharmony_ci	if (sdebug_dev_is_zoned(devip))
35268c2ecf20Sopenharmony_ci		zbc_inc_wp(devip, lba, num);
35278c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
35288c2ecf20Sopenharmony_ci	if (unlikely(-1 == ret))
35298c2ecf20Sopenharmony_ci		return DID_ERROR << 16;
35308c2ecf20Sopenharmony_ci	else if (unlikely(sdebug_verbose &&
35318c2ecf20Sopenharmony_ci			  (ret < (num * sdebug_sector_size))))
35328c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, scp->device,
35338c2ecf20Sopenharmony_ci			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
35348c2ecf20Sopenharmony_ci			    my_name, num * sdebug_sector_size, ret);
35358c2ecf20Sopenharmony_ci
35368c2ecf20Sopenharmony_ci	if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
35378c2ecf20Sopenharmony_ci		     atomic_read(&sdeb_inject_pending))) {
35388c2ecf20Sopenharmony_ci		if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
35398c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
35408c2ecf20Sopenharmony_ci			atomic_set(&sdeb_inject_pending, 0);
35418c2ecf20Sopenharmony_ci			return check_condition_result;
35428c2ecf20Sopenharmony_ci		} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
35438c2ecf20Sopenharmony_ci			/* Logical block guard check failed */
35448c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
35458c2ecf20Sopenharmony_ci			atomic_set(&sdeb_inject_pending, 0);
35468c2ecf20Sopenharmony_ci			return illegal_condition_result;
35478c2ecf20Sopenharmony_ci		} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
35488c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
35498c2ecf20Sopenharmony_ci			atomic_set(&sdeb_inject_pending, 0);
35508c2ecf20Sopenharmony_ci			return illegal_condition_result;
35518c2ecf20Sopenharmony_ci		}
35528c2ecf20Sopenharmony_ci	}
35538c2ecf20Sopenharmony_ci	return 0;
35548c2ecf20Sopenharmony_ci}
35558c2ecf20Sopenharmony_ci
35568c2ecf20Sopenharmony_ci/*
35578c2ecf20Sopenharmony_ci * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
35588c2ecf20Sopenharmony_ci * No READ GATHERED yet (requires bidi or long cdb holding gather list).
35598c2ecf20Sopenharmony_ci */
35608c2ecf20Sopenharmony_cistatic int resp_write_scat(struct scsi_cmnd *scp,
35618c2ecf20Sopenharmony_ci			   struct sdebug_dev_info *devip)
35628c2ecf20Sopenharmony_ci{
35638c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
35648c2ecf20Sopenharmony_ci	u8 *lrdp = NULL;
35658c2ecf20Sopenharmony_ci	u8 *up;
35668c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, true);
35678c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = &sip->macc_lck;
35688c2ecf20Sopenharmony_ci	u8 wrprotect;
35698c2ecf20Sopenharmony_ci	u16 lbdof, num_lrd, k;
35708c2ecf20Sopenharmony_ci	u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
35718c2ecf20Sopenharmony_ci	u32 lb_size = sdebug_sector_size;
35728c2ecf20Sopenharmony_ci	u32 ei_lba;
35738c2ecf20Sopenharmony_ci	u64 lba;
35748c2ecf20Sopenharmony_ci	int ret, res;
35758c2ecf20Sopenharmony_ci	bool is_16;
35768c2ecf20Sopenharmony_ci	static const u32 lrd_size = 32; /* + parameter list header size */
35778c2ecf20Sopenharmony_ci
35788c2ecf20Sopenharmony_ci	if (cmd[0] == VARIABLE_LENGTH_CMD) {
35798c2ecf20Sopenharmony_ci		is_16 = false;
35808c2ecf20Sopenharmony_ci		wrprotect = (cmd[10] >> 5) & 0x7;
35818c2ecf20Sopenharmony_ci		lbdof = get_unaligned_be16(cmd + 12);
35828c2ecf20Sopenharmony_ci		num_lrd = get_unaligned_be16(cmd + 16);
35838c2ecf20Sopenharmony_ci		bt_len = get_unaligned_be32(cmd + 28);
35848c2ecf20Sopenharmony_ci	} else {        /* that leaves WRITE SCATTERED(16) */
35858c2ecf20Sopenharmony_ci		is_16 = true;
35868c2ecf20Sopenharmony_ci		wrprotect = (cmd[2] >> 5) & 0x7;
35878c2ecf20Sopenharmony_ci		lbdof = get_unaligned_be16(cmd + 4);
35888c2ecf20Sopenharmony_ci		num_lrd = get_unaligned_be16(cmd + 8);
35898c2ecf20Sopenharmony_ci		bt_len = get_unaligned_be32(cmd + 10);
35908c2ecf20Sopenharmony_ci		if (unlikely(have_dif_prot)) {
35918c2ecf20Sopenharmony_ci			if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
35928c2ecf20Sopenharmony_ci			    wrprotect) {
35938c2ecf20Sopenharmony_ci				mk_sense_invalid_opcode(scp);
35948c2ecf20Sopenharmony_ci				return illegal_condition_result;
35958c2ecf20Sopenharmony_ci			}
35968c2ecf20Sopenharmony_ci			if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
35978c2ecf20Sopenharmony_ci			     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
35988c2ecf20Sopenharmony_ci			     wrprotect == 0)
35998c2ecf20Sopenharmony_ci				sdev_printk(KERN_ERR, scp->device,
36008c2ecf20Sopenharmony_ci					    "Unprotected WR to DIF device\n");
36018c2ecf20Sopenharmony_ci		}
36028c2ecf20Sopenharmony_ci	}
36038c2ecf20Sopenharmony_ci	if ((num_lrd == 0) || (bt_len == 0))
36048c2ecf20Sopenharmony_ci		return 0;       /* T10 says these do-nothings are not errors */
36058c2ecf20Sopenharmony_ci	if (lbdof == 0) {
36068c2ecf20Sopenharmony_ci		if (sdebug_verbose)
36078c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, scp->device,
36088c2ecf20Sopenharmony_ci				"%s: %s: LB Data Offset field bad\n",
36098c2ecf20Sopenharmony_ci				my_name, __func__);
36108c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
36118c2ecf20Sopenharmony_ci		return illegal_condition_result;
36128c2ecf20Sopenharmony_ci	}
36138c2ecf20Sopenharmony_ci	lbdof_blen = lbdof * lb_size;
36148c2ecf20Sopenharmony_ci	if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
36158c2ecf20Sopenharmony_ci		if (sdebug_verbose)
36168c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, scp->device,
36178c2ecf20Sopenharmony_ci				"%s: %s: LBA range descriptors don't fit\n",
36188c2ecf20Sopenharmony_ci				my_name, __func__);
36198c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
36208c2ecf20Sopenharmony_ci		return illegal_condition_result;
36218c2ecf20Sopenharmony_ci	}
36228c2ecf20Sopenharmony_ci	lrdp = kzalloc(lbdof_blen, GFP_ATOMIC | __GFP_NOWARN);
36238c2ecf20Sopenharmony_ci	if (lrdp == NULL)
36248c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
36258c2ecf20Sopenharmony_ci	if (sdebug_verbose)
36268c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, scp->device,
36278c2ecf20Sopenharmony_ci			"%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
36288c2ecf20Sopenharmony_ci			my_name, __func__, lbdof_blen);
36298c2ecf20Sopenharmony_ci	res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
36308c2ecf20Sopenharmony_ci	if (res == -1) {
36318c2ecf20Sopenharmony_ci		ret = DID_ERROR << 16;
36328c2ecf20Sopenharmony_ci		goto err_out;
36338c2ecf20Sopenharmony_ci	}
36348c2ecf20Sopenharmony_ci
36358c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
36368c2ecf20Sopenharmony_ci	sg_off = lbdof_blen;
36378c2ecf20Sopenharmony_ci	/* Spec says Buffer xfer Length field in number of LBs in dout */
36388c2ecf20Sopenharmony_ci	cum_lb = 0;
36398c2ecf20Sopenharmony_ci	for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
36408c2ecf20Sopenharmony_ci		lba = get_unaligned_be64(up + 0);
36418c2ecf20Sopenharmony_ci		num = get_unaligned_be32(up + 8);
36428c2ecf20Sopenharmony_ci		if (sdebug_verbose)
36438c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, scp->device,
36448c2ecf20Sopenharmony_ci				"%s: %s: k=%d  LBA=0x%llx num=%u  sg_off=%u\n",
36458c2ecf20Sopenharmony_ci				my_name, __func__, k, lba, num, sg_off);
36468c2ecf20Sopenharmony_ci		if (num == 0)
36478c2ecf20Sopenharmony_ci			continue;
36488c2ecf20Sopenharmony_ci		ret = check_device_access_params(scp, lba, num, true);
36498c2ecf20Sopenharmony_ci		if (ret)
36508c2ecf20Sopenharmony_ci			goto err_out_unlock;
36518c2ecf20Sopenharmony_ci		num_by = num * lb_size;
36528c2ecf20Sopenharmony_ci		ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
36538c2ecf20Sopenharmony_ci
36548c2ecf20Sopenharmony_ci		if ((cum_lb + num) > bt_len) {
36558c2ecf20Sopenharmony_ci			if (sdebug_verbose)
36568c2ecf20Sopenharmony_ci				sdev_printk(KERN_INFO, scp->device,
36578c2ecf20Sopenharmony_ci				    "%s: %s: sum of blocks > data provided\n",
36588c2ecf20Sopenharmony_ci				    my_name, __func__);
36598c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
36608c2ecf20Sopenharmony_ci					0);
36618c2ecf20Sopenharmony_ci			ret = illegal_condition_result;
36628c2ecf20Sopenharmony_ci			goto err_out_unlock;
36638c2ecf20Sopenharmony_ci		}
36648c2ecf20Sopenharmony_ci
36658c2ecf20Sopenharmony_ci		/* DIX + T10 DIF */
36668c2ecf20Sopenharmony_ci		if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
36678c2ecf20Sopenharmony_ci			int prot_ret = prot_verify_write(scp, lba, num,
36688c2ecf20Sopenharmony_ci							 ei_lba);
36698c2ecf20Sopenharmony_ci
36708c2ecf20Sopenharmony_ci			if (prot_ret) {
36718c2ecf20Sopenharmony_ci				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
36728c2ecf20Sopenharmony_ci						prot_ret);
36738c2ecf20Sopenharmony_ci				ret = illegal_condition_result;
36748c2ecf20Sopenharmony_ci				goto err_out_unlock;
36758c2ecf20Sopenharmony_ci			}
36768c2ecf20Sopenharmony_ci		}
36778c2ecf20Sopenharmony_ci
36788c2ecf20Sopenharmony_ci		ret = do_device_access(sip, scp, sg_off, lba, num, true);
36798c2ecf20Sopenharmony_ci		/* If ZBC zone then bump its write pointer */
36808c2ecf20Sopenharmony_ci		if (sdebug_dev_is_zoned(devip))
36818c2ecf20Sopenharmony_ci			zbc_inc_wp(devip, lba, num);
36828c2ecf20Sopenharmony_ci		if (unlikely(scsi_debug_lbp()))
36838c2ecf20Sopenharmony_ci			map_region(sip, lba, num);
36848c2ecf20Sopenharmony_ci		if (unlikely(-1 == ret)) {
36858c2ecf20Sopenharmony_ci			ret = DID_ERROR << 16;
36868c2ecf20Sopenharmony_ci			goto err_out_unlock;
36878c2ecf20Sopenharmony_ci		} else if (unlikely(sdebug_verbose && (ret < num_by)))
36888c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, scp->device,
36898c2ecf20Sopenharmony_ci			    "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
36908c2ecf20Sopenharmony_ci			    my_name, num_by, ret);
36918c2ecf20Sopenharmony_ci
36928c2ecf20Sopenharmony_ci		if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) &&
36938c2ecf20Sopenharmony_ci			     atomic_read(&sdeb_inject_pending))) {
36948c2ecf20Sopenharmony_ci			if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) {
36958c2ecf20Sopenharmony_ci				mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0);
36968c2ecf20Sopenharmony_ci				atomic_set(&sdeb_inject_pending, 0);
36978c2ecf20Sopenharmony_ci				ret = check_condition_result;
36988c2ecf20Sopenharmony_ci				goto err_out_unlock;
36998c2ecf20Sopenharmony_ci			} else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) {
37008c2ecf20Sopenharmony_ci				/* Logical block guard check failed */
37018c2ecf20Sopenharmony_ci				mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
37028c2ecf20Sopenharmony_ci				atomic_set(&sdeb_inject_pending, 0);
37038c2ecf20Sopenharmony_ci				ret = illegal_condition_result;
37048c2ecf20Sopenharmony_ci				goto err_out_unlock;
37058c2ecf20Sopenharmony_ci			} else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) {
37068c2ecf20Sopenharmony_ci				mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
37078c2ecf20Sopenharmony_ci				atomic_set(&sdeb_inject_pending, 0);
37088c2ecf20Sopenharmony_ci				ret = illegal_condition_result;
37098c2ecf20Sopenharmony_ci				goto err_out_unlock;
37108c2ecf20Sopenharmony_ci			}
37118c2ecf20Sopenharmony_ci		}
37128c2ecf20Sopenharmony_ci		sg_off += num_by;
37138c2ecf20Sopenharmony_ci		cum_lb += num;
37148c2ecf20Sopenharmony_ci	}
37158c2ecf20Sopenharmony_ci	ret = 0;
37168c2ecf20Sopenharmony_cierr_out_unlock:
37178c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
37188c2ecf20Sopenharmony_cierr_out:
37198c2ecf20Sopenharmony_ci	kfree(lrdp);
37208c2ecf20Sopenharmony_ci	return ret;
37218c2ecf20Sopenharmony_ci}
37228c2ecf20Sopenharmony_ci
37238c2ecf20Sopenharmony_cistatic int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
37248c2ecf20Sopenharmony_ci			   u32 ei_lba, bool unmap, bool ndob)
37258c2ecf20Sopenharmony_ci{
37268c2ecf20Sopenharmony_ci	struct scsi_device *sdp = scp->device;
37278c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata;
37288c2ecf20Sopenharmony_ci	unsigned long long i;
37298c2ecf20Sopenharmony_ci	u64 block, lbaa;
37308c2ecf20Sopenharmony_ci	u32 lb_size = sdebug_sector_size;
37318c2ecf20Sopenharmony_ci	int ret;
37328c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
37338c2ecf20Sopenharmony_ci						scp->device->hostdata, true);
37348c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = &sip->macc_lck;
37358c2ecf20Sopenharmony_ci	u8 *fs1p;
37368c2ecf20Sopenharmony_ci	u8 *fsp;
37378c2ecf20Sopenharmony_ci
37388c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
37398c2ecf20Sopenharmony_ci
37408c2ecf20Sopenharmony_ci	ret = check_device_access_params(scp, lba, num, true);
37418c2ecf20Sopenharmony_ci	if (ret) {
37428c2ecf20Sopenharmony_ci		write_unlock(macc_lckp);
37438c2ecf20Sopenharmony_ci		return ret;
37448c2ecf20Sopenharmony_ci	}
37458c2ecf20Sopenharmony_ci
37468c2ecf20Sopenharmony_ci	if (unmap && scsi_debug_lbp()) {
37478c2ecf20Sopenharmony_ci		unmap_region(sip, lba, num);
37488c2ecf20Sopenharmony_ci		goto out;
37498c2ecf20Sopenharmony_ci	}
37508c2ecf20Sopenharmony_ci	lbaa = lba;
37518c2ecf20Sopenharmony_ci	block = do_div(lbaa, sdebug_store_sectors);
37528c2ecf20Sopenharmony_ci	/* if ndob then zero 1 logical block, else fetch 1 logical block */
37538c2ecf20Sopenharmony_ci	fsp = sip->storep;
37548c2ecf20Sopenharmony_ci	fs1p = fsp + (block * lb_size);
37558c2ecf20Sopenharmony_ci	if (ndob) {
37568c2ecf20Sopenharmony_ci		memset(fs1p, 0, lb_size);
37578c2ecf20Sopenharmony_ci		ret = 0;
37588c2ecf20Sopenharmony_ci	} else
37598c2ecf20Sopenharmony_ci		ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
37608c2ecf20Sopenharmony_ci
37618c2ecf20Sopenharmony_ci	if (-1 == ret) {
37628c2ecf20Sopenharmony_ci		write_unlock(&sip->macc_lck);
37638c2ecf20Sopenharmony_ci		return DID_ERROR << 16;
37648c2ecf20Sopenharmony_ci	} else if (sdebug_verbose && !ndob && (ret < lb_size))
37658c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, scp->device,
37668c2ecf20Sopenharmony_ci			    "%s: %s: lb size=%u, IO sent=%d bytes\n",
37678c2ecf20Sopenharmony_ci			    my_name, "write same", lb_size, ret);
37688c2ecf20Sopenharmony_ci
37698c2ecf20Sopenharmony_ci	/* Copy first sector to remaining blocks */
37708c2ecf20Sopenharmony_ci	for (i = 1 ; i < num ; i++) {
37718c2ecf20Sopenharmony_ci		lbaa = lba + i;
37728c2ecf20Sopenharmony_ci		block = do_div(lbaa, sdebug_store_sectors);
37738c2ecf20Sopenharmony_ci		memmove(fsp + (block * lb_size), fs1p, lb_size);
37748c2ecf20Sopenharmony_ci	}
37758c2ecf20Sopenharmony_ci	if (scsi_debug_lbp())
37768c2ecf20Sopenharmony_ci		map_region(sip, lba, num);
37778c2ecf20Sopenharmony_ci	/* If ZBC zone then bump its write pointer */
37788c2ecf20Sopenharmony_ci	if (sdebug_dev_is_zoned(devip))
37798c2ecf20Sopenharmony_ci		zbc_inc_wp(devip, lba, num);
37808c2ecf20Sopenharmony_ciout:
37818c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
37828c2ecf20Sopenharmony_ci
37838c2ecf20Sopenharmony_ci	return 0;
37848c2ecf20Sopenharmony_ci}
37858c2ecf20Sopenharmony_ci
37868c2ecf20Sopenharmony_cistatic int resp_write_same_10(struct scsi_cmnd *scp,
37878c2ecf20Sopenharmony_ci			      struct sdebug_dev_info *devip)
37888c2ecf20Sopenharmony_ci{
37898c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
37908c2ecf20Sopenharmony_ci	u32 lba;
37918c2ecf20Sopenharmony_ci	u16 num;
37928c2ecf20Sopenharmony_ci	u32 ei_lba = 0;
37938c2ecf20Sopenharmony_ci	bool unmap = false;
37948c2ecf20Sopenharmony_ci
37958c2ecf20Sopenharmony_ci	if (cmd[1] & 0x8) {
37968c2ecf20Sopenharmony_ci		if (sdebug_lbpws10 == 0) {
37978c2ecf20Sopenharmony_ci			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
37988c2ecf20Sopenharmony_ci			return check_condition_result;
37998c2ecf20Sopenharmony_ci		} else
38008c2ecf20Sopenharmony_ci			unmap = true;
38018c2ecf20Sopenharmony_ci	}
38028c2ecf20Sopenharmony_ci	lba = get_unaligned_be32(cmd + 2);
38038c2ecf20Sopenharmony_ci	num = get_unaligned_be16(cmd + 7);
38048c2ecf20Sopenharmony_ci	if (num > sdebug_write_same_length) {
38058c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
38068c2ecf20Sopenharmony_ci		return check_condition_result;
38078c2ecf20Sopenharmony_ci	}
38088c2ecf20Sopenharmony_ci	return resp_write_same(scp, lba, num, ei_lba, unmap, false);
38098c2ecf20Sopenharmony_ci}
38108c2ecf20Sopenharmony_ci
38118c2ecf20Sopenharmony_cistatic int resp_write_same_16(struct scsi_cmnd *scp,
38128c2ecf20Sopenharmony_ci			      struct sdebug_dev_info *devip)
38138c2ecf20Sopenharmony_ci{
38148c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
38158c2ecf20Sopenharmony_ci	u64 lba;
38168c2ecf20Sopenharmony_ci	u32 num;
38178c2ecf20Sopenharmony_ci	u32 ei_lba = 0;
38188c2ecf20Sopenharmony_ci	bool unmap = false;
38198c2ecf20Sopenharmony_ci	bool ndob = false;
38208c2ecf20Sopenharmony_ci
38218c2ecf20Sopenharmony_ci	if (cmd[1] & 0x8) {	/* UNMAP */
38228c2ecf20Sopenharmony_ci		if (sdebug_lbpws == 0) {
38238c2ecf20Sopenharmony_ci			mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
38248c2ecf20Sopenharmony_ci			return check_condition_result;
38258c2ecf20Sopenharmony_ci		} else
38268c2ecf20Sopenharmony_ci			unmap = true;
38278c2ecf20Sopenharmony_ci	}
38288c2ecf20Sopenharmony_ci	if (cmd[1] & 0x1)  /* NDOB (no data-out buffer, assumes zeroes) */
38298c2ecf20Sopenharmony_ci		ndob = true;
38308c2ecf20Sopenharmony_ci	lba = get_unaligned_be64(cmd + 2);
38318c2ecf20Sopenharmony_ci	num = get_unaligned_be32(cmd + 10);
38328c2ecf20Sopenharmony_ci	if (num > sdebug_write_same_length) {
38338c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
38348c2ecf20Sopenharmony_ci		return check_condition_result;
38358c2ecf20Sopenharmony_ci	}
38368c2ecf20Sopenharmony_ci	return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
38378c2ecf20Sopenharmony_ci}
38388c2ecf20Sopenharmony_ci
38398c2ecf20Sopenharmony_ci/* Note the mode field is in the same position as the (lower) service action
38408c2ecf20Sopenharmony_ci * field. For the Report supported operation codes command, SPC-4 suggests
38418c2ecf20Sopenharmony_ci * each mode of this command should be reported separately; for future. */
38428c2ecf20Sopenharmony_cistatic int resp_write_buffer(struct scsi_cmnd *scp,
38438c2ecf20Sopenharmony_ci			     struct sdebug_dev_info *devip)
38448c2ecf20Sopenharmony_ci{
38458c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
38468c2ecf20Sopenharmony_ci	struct scsi_device *sdp = scp->device;
38478c2ecf20Sopenharmony_ci	struct sdebug_dev_info *dp;
38488c2ecf20Sopenharmony_ci	u8 mode;
38498c2ecf20Sopenharmony_ci
38508c2ecf20Sopenharmony_ci	mode = cmd[1] & 0x1f;
38518c2ecf20Sopenharmony_ci	switch (mode) {
38528c2ecf20Sopenharmony_ci	case 0x4:	/* download microcode (MC) and activate (ACT) */
38538c2ecf20Sopenharmony_ci		/* set UAs on this device only */
38548c2ecf20Sopenharmony_ci		set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
38558c2ecf20Sopenharmony_ci		set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
38568c2ecf20Sopenharmony_ci		break;
38578c2ecf20Sopenharmony_ci	case 0x5:	/* download MC, save and ACT */
38588c2ecf20Sopenharmony_ci		set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
38598c2ecf20Sopenharmony_ci		break;
38608c2ecf20Sopenharmony_ci	case 0x6:	/* download MC with offsets and ACT */
38618c2ecf20Sopenharmony_ci		/* set UAs on most devices (LUs) in this target */
38628c2ecf20Sopenharmony_ci		list_for_each_entry(dp,
38638c2ecf20Sopenharmony_ci				    &devip->sdbg_host->dev_info_list,
38648c2ecf20Sopenharmony_ci				    dev_list)
38658c2ecf20Sopenharmony_ci			if (dp->target == sdp->id) {
38668c2ecf20Sopenharmony_ci				set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
38678c2ecf20Sopenharmony_ci				if (devip != dp)
38688c2ecf20Sopenharmony_ci					set_bit(SDEBUG_UA_MICROCODE_CHANGED,
38698c2ecf20Sopenharmony_ci						dp->uas_bm);
38708c2ecf20Sopenharmony_ci			}
38718c2ecf20Sopenharmony_ci		break;
38728c2ecf20Sopenharmony_ci	case 0x7:	/* download MC with offsets, save, and ACT */
38738c2ecf20Sopenharmony_ci		/* set UA on all devices (LUs) in this target */
38748c2ecf20Sopenharmony_ci		list_for_each_entry(dp,
38758c2ecf20Sopenharmony_ci				    &devip->sdbg_host->dev_info_list,
38768c2ecf20Sopenharmony_ci				    dev_list)
38778c2ecf20Sopenharmony_ci			if (dp->target == sdp->id)
38788c2ecf20Sopenharmony_ci				set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
38798c2ecf20Sopenharmony_ci					dp->uas_bm);
38808c2ecf20Sopenharmony_ci		break;
38818c2ecf20Sopenharmony_ci	default:
38828c2ecf20Sopenharmony_ci		/* do nothing for this command for other mode values */
38838c2ecf20Sopenharmony_ci		break;
38848c2ecf20Sopenharmony_ci	}
38858c2ecf20Sopenharmony_ci	return 0;
38868c2ecf20Sopenharmony_ci}
38878c2ecf20Sopenharmony_ci
38888c2ecf20Sopenharmony_cistatic int resp_comp_write(struct scsi_cmnd *scp,
38898c2ecf20Sopenharmony_ci			   struct sdebug_dev_info *devip)
38908c2ecf20Sopenharmony_ci{
38918c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
38928c2ecf20Sopenharmony_ci	u8 *arr;
38938c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, true);
38948c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = &sip->macc_lck;
38958c2ecf20Sopenharmony_ci	u64 lba;
38968c2ecf20Sopenharmony_ci	u32 dnum;
38978c2ecf20Sopenharmony_ci	u32 lb_size = sdebug_sector_size;
38988c2ecf20Sopenharmony_ci	u8 num;
38998c2ecf20Sopenharmony_ci	int ret;
39008c2ecf20Sopenharmony_ci	int retval = 0;
39018c2ecf20Sopenharmony_ci
39028c2ecf20Sopenharmony_ci	lba = get_unaligned_be64(cmd + 2);
39038c2ecf20Sopenharmony_ci	num = cmd[13];		/* 1 to a maximum of 255 logical blocks */
39048c2ecf20Sopenharmony_ci	if (0 == num)
39058c2ecf20Sopenharmony_ci		return 0;	/* degenerate case, not an error */
39068c2ecf20Sopenharmony_ci	if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
39078c2ecf20Sopenharmony_ci	    (cmd[1] & 0xe0)) {
39088c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
39098c2ecf20Sopenharmony_ci		return check_condition_result;
39108c2ecf20Sopenharmony_ci	}
39118c2ecf20Sopenharmony_ci	if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
39128c2ecf20Sopenharmony_ci	     sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
39138c2ecf20Sopenharmony_ci	    (cmd[1] & 0xe0) == 0)
39148c2ecf20Sopenharmony_ci		sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
39158c2ecf20Sopenharmony_ci			    "to DIF device\n");
39168c2ecf20Sopenharmony_ci	ret = check_device_access_params(scp, lba, num, false);
39178c2ecf20Sopenharmony_ci	if (ret)
39188c2ecf20Sopenharmony_ci		return ret;
39198c2ecf20Sopenharmony_ci	dnum = 2 * num;
39208c2ecf20Sopenharmony_ci	arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
39218c2ecf20Sopenharmony_ci	if (NULL == arr) {
39228c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
39238c2ecf20Sopenharmony_ci				INSUFF_RES_ASCQ);
39248c2ecf20Sopenharmony_ci		return check_condition_result;
39258c2ecf20Sopenharmony_ci	}
39268c2ecf20Sopenharmony_ci
39278c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
39288c2ecf20Sopenharmony_ci
39298c2ecf20Sopenharmony_ci	ret = do_dout_fetch(scp, dnum, arr);
39308c2ecf20Sopenharmony_ci	if (ret == -1) {
39318c2ecf20Sopenharmony_ci		retval = DID_ERROR << 16;
39328c2ecf20Sopenharmony_ci		goto cleanup;
39338c2ecf20Sopenharmony_ci	} else if (sdebug_verbose && (ret < (dnum * lb_size)))
39348c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
39358c2ecf20Sopenharmony_ci			    "indicated=%u, IO sent=%d bytes\n", my_name,
39368c2ecf20Sopenharmony_ci			    dnum * lb_size, ret);
39378c2ecf20Sopenharmony_ci	if (!comp_write_worker(sip, lba, num, arr, false)) {
39388c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
39398c2ecf20Sopenharmony_ci		retval = check_condition_result;
39408c2ecf20Sopenharmony_ci		goto cleanup;
39418c2ecf20Sopenharmony_ci	}
39428c2ecf20Sopenharmony_ci	if (scsi_debug_lbp())
39438c2ecf20Sopenharmony_ci		map_region(sip, lba, num);
39448c2ecf20Sopenharmony_cicleanup:
39458c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
39468c2ecf20Sopenharmony_ci	kfree(arr);
39478c2ecf20Sopenharmony_ci	return retval;
39488c2ecf20Sopenharmony_ci}
39498c2ecf20Sopenharmony_ci
39508c2ecf20Sopenharmony_cistruct unmap_block_desc {
39518c2ecf20Sopenharmony_ci	__be64	lba;
39528c2ecf20Sopenharmony_ci	__be32	blocks;
39538c2ecf20Sopenharmony_ci	__be32	__reserved;
39548c2ecf20Sopenharmony_ci};
39558c2ecf20Sopenharmony_ci
39568c2ecf20Sopenharmony_cistatic int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
39578c2ecf20Sopenharmony_ci{
39588c2ecf20Sopenharmony_ci	unsigned char *buf;
39598c2ecf20Sopenharmony_ci	struct unmap_block_desc *desc;
39608c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, true);
39618c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = &sip->macc_lck;
39628c2ecf20Sopenharmony_ci	unsigned int i, payload_len, descriptors;
39638c2ecf20Sopenharmony_ci	int ret;
39648c2ecf20Sopenharmony_ci
39658c2ecf20Sopenharmony_ci	if (!scsi_debug_lbp())
39668c2ecf20Sopenharmony_ci		return 0;	/* fib and say its done */
39678c2ecf20Sopenharmony_ci	payload_len = get_unaligned_be16(scp->cmnd + 7);
39688c2ecf20Sopenharmony_ci	BUG_ON(scsi_bufflen(scp) != payload_len);
39698c2ecf20Sopenharmony_ci
39708c2ecf20Sopenharmony_ci	descriptors = (payload_len - 8) / 16;
39718c2ecf20Sopenharmony_ci	if (descriptors > sdebug_unmap_max_desc) {
39728c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
39738c2ecf20Sopenharmony_ci		return check_condition_result;
39748c2ecf20Sopenharmony_ci	}
39758c2ecf20Sopenharmony_ci
39768c2ecf20Sopenharmony_ci	buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
39778c2ecf20Sopenharmony_ci	if (!buf) {
39788c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
39798c2ecf20Sopenharmony_ci				INSUFF_RES_ASCQ);
39808c2ecf20Sopenharmony_ci		return check_condition_result;
39818c2ecf20Sopenharmony_ci	}
39828c2ecf20Sopenharmony_ci
39838c2ecf20Sopenharmony_ci	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_ci	BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
39868c2ecf20Sopenharmony_ci	BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
39878c2ecf20Sopenharmony_ci
39888c2ecf20Sopenharmony_ci	desc = (void *)&buf[8];
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
39918c2ecf20Sopenharmony_ci
39928c2ecf20Sopenharmony_ci	for (i = 0 ; i < descriptors ; i++) {
39938c2ecf20Sopenharmony_ci		unsigned long long lba = get_unaligned_be64(&desc[i].lba);
39948c2ecf20Sopenharmony_ci		unsigned int num = get_unaligned_be32(&desc[i].blocks);
39958c2ecf20Sopenharmony_ci
39968c2ecf20Sopenharmony_ci		ret = check_device_access_params(scp, lba, num, true);
39978c2ecf20Sopenharmony_ci		if (ret)
39988c2ecf20Sopenharmony_ci			goto out;
39998c2ecf20Sopenharmony_ci
40008c2ecf20Sopenharmony_ci		unmap_region(sip, lba, num);
40018c2ecf20Sopenharmony_ci	}
40028c2ecf20Sopenharmony_ci
40038c2ecf20Sopenharmony_ci	ret = 0;
40048c2ecf20Sopenharmony_ci
40058c2ecf20Sopenharmony_ciout:
40068c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
40078c2ecf20Sopenharmony_ci	kfree(buf);
40088c2ecf20Sopenharmony_ci
40098c2ecf20Sopenharmony_ci	return ret;
40108c2ecf20Sopenharmony_ci}
40118c2ecf20Sopenharmony_ci
40128c2ecf20Sopenharmony_ci#define SDEBUG_GET_LBA_STATUS_LEN 32
40138c2ecf20Sopenharmony_ci
40148c2ecf20Sopenharmony_cistatic int resp_get_lba_status(struct scsi_cmnd *scp,
40158c2ecf20Sopenharmony_ci			       struct sdebug_dev_info *devip)
40168c2ecf20Sopenharmony_ci{
40178c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
40188c2ecf20Sopenharmony_ci	u64 lba;
40198c2ecf20Sopenharmony_ci	u32 alloc_len, mapped, num;
40208c2ecf20Sopenharmony_ci	int ret;
40218c2ecf20Sopenharmony_ci	u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
40228c2ecf20Sopenharmony_ci
40238c2ecf20Sopenharmony_ci	lba = get_unaligned_be64(cmd + 2);
40248c2ecf20Sopenharmony_ci	alloc_len = get_unaligned_be32(cmd + 10);
40258c2ecf20Sopenharmony_ci
40268c2ecf20Sopenharmony_ci	if (alloc_len < 24)
40278c2ecf20Sopenharmony_ci		return 0;
40288c2ecf20Sopenharmony_ci
40298c2ecf20Sopenharmony_ci	ret = check_device_access_params(scp, lba, 1, false);
40308c2ecf20Sopenharmony_ci	if (ret)
40318c2ecf20Sopenharmony_ci		return ret;
40328c2ecf20Sopenharmony_ci
40338c2ecf20Sopenharmony_ci	if (scsi_debug_lbp()) {
40348c2ecf20Sopenharmony_ci		struct sdeb_store_info *sip = devip2sip(devip, true);
40358c2ecf20Sopenharmony_ci
40368c2ecf20Sopenharmony_ci		mapped = map_state(sip, lba, &num);
40378c2ecf20Sopenharmony_ci	} else {
40388c2ecf20Sopenharmony_ci		mapped = 1;
40398c2ecf20Sopenharmony_ci		/* following just in case virtual_gb changed */
40408c2ecf20Sopenharmony_ci		sdebug_capacity = get_sdebug_capacity();
40418c2ecf20Sopenharmony_ci		if (sdebug_capacity - lba <= 0xffffffff)
40428c2ecf20Sopenharmony_ci			num = sdebug_capacity - lba;
40438c2ecf20Sopenharmony_ci		else
40448c2ecf20Sopenharmony_ci			num = 0xffffffff;
40458c2ecf20Sopenharmony_ci	}
40468c2ecf20Sopenharmony_ci
40478c2ecf20Sopenharmony_ci	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
40488c2ecf20Sopenharmony_ci	put_unaligned_be32(20, arr);		/* Parameter Data Length */
40498c2ecf20Sopenharmony_ci	put_unaligned_be64(lba, arr + 8);	/* LBA */
40508c2ecf20Sopenharmony_ci	put_unaligned_be32(num, arr + 16);	/* Number of blocks */
40518c2ecf20Sopenharmony_ci	arr[20] = !mapped;		/* prov_stat=0: mapped; 1: dealloc */
40528c2ecf20Sopenharmony_ci
40538c2ecf20Sopenharmony_ci	return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
40548c2ecf20Sopenharmony_ci}
40558c2ecf20Sopenharmony_ci
40568c2ecf20Sopenharmony_cistatic int resp_sync_cache(struct scsi_cmnd *scp,
40578c2ecf20Sopenharmony_ci			   struct sdebug_dev_info *devip)
40588c2ecf20Sopenharmony_ci{
40598c2ecf20Sopenharmony_ci	int res = 0;
40608c2ecf20Sopenharmony_ci	u64 lba;
40618c2ecf20Sopenharmony_ci	u32 num_blocks;
40628c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
40638c2ecf20Sopenharmony_ci
40648c2ecf20Sopenharmony_ci	if (cmd[0] == SYNCHRONIZE_CACHE) {	/* 10 byte cdb */
40658c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
40668c2ecf20Sopenharmony_ci		num_blocks = get_unaligned_be16(cmd + 7);
40678c2ecf20Sopenharmony_ci	} else {				/* SYNCHRONIZE_CACHE(16) */
40688c2ecf20Sopenharmony_ci		lba = get_unaligned_be64(cmd + 2);
40698c2ecf20Sopenharmony_ci		num_blocks = get_unaligned_be32(cmd + 10);
40708c2ecf20Sopenharmony_ci	}
40718c2ecf20Sopenharmony_ci	if (lba + num_blocks > sdebug_capacity) {
40728c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
40738c2ecf20Sopenharmony_ci		return check_condition_result;
40748c2ecf20Sopenharmony_ci	}
40758c2ecf20Sopenharmony_ci	if (!write_since_sync || (cmd[1] & 0x2))
40768c2ecf20Sopenharmony_ci		res = SDEG_RES_IMMED_MASK;
40778c2ecf20Sopenharmony_ci	else		/* delay if write_since_sync and IMMED clear */
40788c2ecf20Sopenharmony_ci		write_since_sync = false;
40798c2ecf20Sopenharmony_ci	return res;
40808c2ecf20Sopenharmony_ci}
40818c2ecf20Sopenharmony_ci
40828c2ecf20Sopenharmony_ci/*
40838c2ecf20Sopenharmony_ci * Assuming the LBA+num_blocks is not out-of-range, this function will return
40848c2ecf20Sopenharmony_ci * CONDITION MET if the specified blocks will/have fitted in the cache, and
40858c2ecf20Sopenharmony_ci * a GOOD status otherwise. Model a disk with a big cache and yield
40868c2ecf20Sopenharmony_ci * CONDITION MET. Actually tries to bring range in main memory into the
40878c2ecf20Sopenharmony_ci * cache associated with the CPU(s).
40888c2ecf20Sopenharmony_ci */
40898c2ecf20Sopenharmony_cistatic int resp_pre_fetch(struct scsi_cmnd *scp,
40908c2ecf20Sopenharmony_ci			  struct sdebug_dev_info *devip)
40918c2ecf20Sopenharmony_ci{
40928c2ecf20Sopenharmony_ci	int res = 0;
40938c2ecf20Sopenharmony_ci	u64 lba;
40948c2ecf20Sopenharmony_ci	u64 block, rest = 0;
40958c2ecf20Sopenharmony_ci	u32 nblks;
40968c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
40978c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, true);
40988c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = &sip->macc_lck;
40998c2ecf20Sopenharmony_ci	u8 *fsp = sip->storep;
41008c2ecf20Sopenharmony_ci
41018c2ecf20Sopenharmony_ci	if (cmd[0] == PRE_FETCH) {	/* 10 byte cdb */
41028c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
41038c2ecf20Sopenharmony_ci		nblks = get_unaligned_be16(cmd + 7);
41048c2ecf20Sopenharmony_ci	} else {			/* PRE-FETCH(16) */
41058c2ecf20Sopenharmony_ci		lba = get_unaligned_be64(cmd + 2);
41068c2ecf20Sopenharmony_ci		nblks = get_unaligned_be32(cmd + 10);
41078c2ecf20Sopenharmony_ci	}
41088c2ecf20Sopenharmony_ci	if (lba + nblks > sdebug_capacity) {
41098c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
41108c2ecf20Sopenharmony_ci		return check_condition_result;
41118c2ecf20Sopenharmony_ci	}
41128c2ecf20Sopenharmony_ci	if (!fsp)
41138c2ecf20Sopenharmony_ci		goto fini;
41148c2ecf20Sopenharmony_ci	/* PRE-FETCH spec says nothing about LBP or PI so skip them */
41158c2ecf20Sopenharmony_ci	block = do_div(lba, sdebug_store_sectors);
41168c2ecf20Sopenharmony_ci	if (block + nblks > sdebug_store_sectors)
41178c2ecf20Sopenharmony_ci		rest = block + nblks - sdebug_store_sectors;
41188c2ecf20Sopenharmony_ci
41198c2ecf20Sopenharmony_ci	/* Try to bring the PRE-FETCH range into CPU's cache */
41208c2ecf20Sopenharmony_ci	read_lock(macc_lckp);
41218c2ecf20Sopenharmony_ci	prefetch_range(fsp + (sdebug_sector_size * block),
41228c2ecf20Sopenharmony_ci		       (nblks - rest) * sdebug_sector_size);
41238c2ecf20Sopenharmony_ci	if (rest)
41248c2ecf20Sopenharmony_ci		prefetch_range(fsp, rest * sdebug_sector_size);
41258c2ecf20Sopenharmony_ci	read_unlock(macc_lckp);
41268c2ecf20Sopenharmony_cifini:
41278c2ecf20Sopenharmony_ci	if (cmd[1] & 0x2)
41288c2ecf20Sopenharmony_ci		res = SDEG_RES_IMMED_MASK;
41298c2ecf20Sopenharmony_ci	return res | condition_met_result;
41308c2ecf20Sopenharmony_ci}
41318c2ecf20Sopenharmony_ci
41328c2ecf20Sopenharmony_ci#define RL_BUCKET_ELEMS 8
41338c2ecf20Sopenharmony_ci
41348c2ecf20Sopenharmony_ci/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
41358c2ecf20Sopenharmony_ci * (W-LUN), the normal Linux scanning logic does not associate it with a
41368c2ecf20Sopenharmony_ci * device (e.g. /dev/sg7). The following magic will make that association:
41378c2ecf20Sopenharmony_ci *   "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
41388c2ecf20Sopenharmony_ci * where <n> is a host number. If there are multiple targets in a host then
41398c2ecf20Sopenharmony_ci * the above will associate a W-LUN to each target. To only get a W-LUN
41408c2ecf20Sopenharmony_ci * for target 2, then use "echo '- 2 49409' > scan" .
41418c2ecf20Sopenharmony_ci */
41428c2ecf20Sopenharmony_cistatic int resp_report_luns(struct scsi_cmnd *scp,
41438c2ecf20Sopenharmony_ci			    struct sdebug_dev_info *devip)
41448c2ecf20Sopenharmony_ci{
41458c2ecf20Sopenharmony_ci	unsigned char *cmd = scp->cmnd;
41468c2ecf20Sopenharmony_ci	unsigned int alloc_len;
41478c2ecf20Sopenharmony_ci	unsigned char select_report;
41488c2ecf20Sopenharmony_ci	u64 lun;
41498c2ecf20Sopenharmony_ci	struct scsi_lun *lun_p;
41508c2ecf20Sopenharmony_ci	u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
41518c2ecf20Sopenharmony_ci	unsigned int lun_cnt;	/* normal LUN count (max: 256) */
41528c2ecf20Sopenharmony_ci	unsigned int wlun_cnt;	/* report luns W-LUN count */
41538c2ecf20Sopenharmony_ci	unsigned int tlun_cnt;	/* total LUN count */
41548c2ecf20Sopenharmony_ci	unsigned int rlen;	/* response length (in bytes) */
41558c2ecf20Sopenharmony_ci	int k, j, n, res;
41568c2ecf20Sopenharmony_ci	unsigned int off_rsp = 0;
41578c2ecf20Sopenharmony_ci	const int sz_lun = sizeof(struct scsi_lun);
41588c2ecf20Sopenharmony_ci
41598c2ecf20Sopenharmony_ci	clear_luns_changed_on_target(devip);
41608c2ecf20Sopenharmony_ci
41618c2ecf20Sopenharmony_ci	select_report = cmd[2];
41628c2ecf20Sopenharmony_ci	alloc_len = get_unaligned_be32(cmd + 6);
41638c2ecf20Sopenharmony_ci
41648c2ecf20Sopenharmony_ci	if (alloc_len < 4) {
41658c2ecf20Sopenharmony_ci		pr_err("alloc len too small %d\n", alloc_len);
41668c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
41678c2ecf20Sopenharmony_ci		return check_condition_result;
41688c2ecf20Sopenharmony_ci	}
41698c2ecf20Sopenharmony_ci
41708c2ecf20Sopenharmony_ci	switch (select_report) {
41718c2ecf20Sopenharmony_ci	case 0:		/* all LUNs apart from W-LUNs */
41728c2ecf20Sopenharmony_ci		lun_cnt = sdebug_max_luns;
41738c2ecf20Sopenharmony_ci		wlun_cnt = 0;
41748c2ecf20Sopenharmony_ci		break;
41758c2ecf20Sopenharmony_ci	case 1:		/* only W-LUNs */
41768c2ecf20Sopenharmony_ci		lun_cnt = 0;
41778c2ecf20Sopenharmony_ci		wlun_cnt = 1;
41788c2ecf20Sopenharmony_ci		break;
41798c2ecf20Sopenharmony_ci	case 2:		/* all LUNs */
41808c2ecf20Sopenharmony_ci		lun_cnt = sdebug_max_luns;
41818c2ecf20Sopenharmony_ci		wlun_cnt = 1;
41828c2ecf20Sopenharmony_ci		break;
41838c2ecf20Sopenharmony_ci	case 0x10:	/* only administrative LUs */
41848c2ecf20Sopenharmony_ci	case 0x11:	/* see SPC-5 */
41858c2ecf20Sopenharmony_ci	case 0x12:	/* only subsiduary LUs owned by referenced LU */
41868c2ecf20Sopenharmony_ci	default:
41878c2ecf20Sopenharmony_ci		pr_debug("select report invalid %d\n", select_report);
41888c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
41898c2ecf20Sopenharmony_ci		return check_condition_result;
41908c2ecf20Sopenharmony_ci	}
41918c2ecf20Sopenharmony_ci
41928c2ecf20Sopenharmony_ci	if (sdebug_no_lun_0 && (lun_cnt > 0))
41938c2ecf20Sopenharmony_ci		--lun_cnt;
41948c2ecf20Sopenharmony_ci
41958c2ecf20Sopenharmony_ci	tlun_cnt = lun_cnt + wlun_cnt;
41968c2ecf20Sopenharmony_ci	rlen = tlun_cnt * sz_lun;	/* excluding 8 byte header */
41978c2ecf20Sopenharmony_ci	scsi_set_resid(scp, scsi_bufflen(scp));
41988c2ecf20Sopenharmony_ci	pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
41998c2ecf20Sopenharmony_ci		 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
42008c2ecf20Sopenharmony_ci
42018c2ecf20Sopenharmony_ci	/* loops rely on sizeof response header same as sizeof lun (both 8) */
42028c2ecf20Sopenharmony_ci	lun = sdebug_no_lun_0 ? 1 : 0;
42038c2ecf20Sopenharmony_ci	for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
42048c2ecf20Sopenharmony_ci		memset(arr, 0, sizeof(arr));
42058c2ecf20Sopenharmony_ci		lun_p = (struct scsi_lun *)&arr[0];
42068c2ecf20Sopenharmony_ci		if (k == 0) {
42078c2ecf20Sopenharmony_ci			put_unaligned_be32(rlen, &arr[0]);
42088c2ecf20Sopenharmony_ci			++lun_p;
42098c2ecf20Sopenharmony_ci			j = 1;
42108c2ecf20Sopenharmony_ci		}
42118c2ecf20Sopenharmony_ci		for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
42128c2ecf20Sopenharmony_ci			if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
42138c2ecf20Sopenharmony_ci				break;
42148c2ecf20Sopenharmony_ci			int_to_scsilun(lun++, lun_p);
42158c2ecf20Sopenharmony_ci			if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT)
42168c2ecf20Sopenharmony_ci				lun_p->scsi_lun[0] |= 0x40;
42178c2ecf20Sopenharmony_ci		}
42188c2ecf20Sopenharmony_ci		if (j < RL_BUCKET_ELEMS)
42198c2ecf20Sopenharmony_ci			break;
42208c2ecf20Sopenharmony_ci		n = j * sz_lun;
42218c2ecf20Sopenharmony_ci		res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
42228c2ecf20Sopenharmony_ci		if (res)
42238c2ecf20Sopenharmony_ci			return res;
42248c2ecf20Sopenharmony_ci		off_rsp += n;
42258c2ecf20Sopenharmony_ci	}
42268c2ecf20Sopenharmony_ci	if (wlun_cnt) {
42278c2ecf20Sopenharmony_ci		int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
42288c2ecf20Sopenharmony_ci		++j;
42298c2ecf20Sopenharmony_ci	}
42308c2ecf20Sopenharmony_ci	if (j > 0)
42318c2ecf20Sopenharmony_ci		res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
42328c2ecf20Sopenharmony_ci	return res;
42338c2ecf20Sopenharmony_ci}
42348c2ecf20Sopenharmony_ci
42358c2ecf20Sopenharmony_cistatic int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
42368c2ecf20Sopenharmony_ci{
42378c2ecf20Sopenharmony_ci	bool is_bytchk3 = false;
42388c2ecf20Sopenharmony_ci	u8 bytchk;
42398c2ecf20Sopenharmony_ci	int ret, j;
42408c2ecf20Sopenharmony_ci	u32 vnum, a_num, off;
42418c2ecf20Sopenharmony_ci	const u32 lb_size = sdebug_sector_size;
42428c2ecf20Sopenharmony_ci	u64 lba;
42438c2ecf20Sopenharmony_ci	u8 *arr;
42448c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
42458c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, true);
42468c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = &sip->macc_lck;
42478c2ecf20Sopenharmony_ci
42488c2ecf20Sopenharmony_ci	bytchk = (cmd[1] >> 1) & 0x3;
42498c2ecf20Sopenharmony_ci	if (bytchk == 0) {
42508c2ecf20Sopenharmony_ci		return 0;	/* always claim internal verify okay */
42518c2ecf20Sopenharmony_ci	} else if (bytchk == 2) {
42528c2ecf20Sopenharmony_ci		mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
42538c2ecf20Sopenharmony_ci		return check_condition_result;
42548c2ecf20Sopenharmony_ci	} else if (bytchk == 3) {
42558c2ecf20Sopenharmony_ci		is_bytchk3 = true;	/* 1 block sent, compared repeatedly */
42568c2ecf20Sopenharmony_ci	}
42578c2ecf20Sopenharmony_ci	switch (cmd[0]) {
42588c2ecf20Sopenharmony_ci	case VERIFY_16:
42598c2ecf20Sopenharmony_ci		lba = get_unaligned_be64(cmd + 2);
42608c2ecf20Sopenharmony_ci		vnum = get_unaligned_be32(cmd + 10);
42618c2ecf20Sopenharmony_ci		break;
42628c2ecf20Sopenharmony_ci	case VERIFY:		/* is VERIFY(10) */
42638c2ecf20Sopenharmony_ci		lba = get_unaligned_be32(cmd + 2);
42648c2ecf20Sopenharmony_ci		vnum = get_unaligned_be16(cmd + 7);
42658c2ecf20Sopenharmony_ci		break;
42668c2ecf20Sopenharmony_ci	default:
42678c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
42688c2ecf20Sopenharmony_ci		return check_condition_result;
42698c2ecf20Sopenharmony_ci	}
42708c2ecf20Sopenharmony_ci	if (vnum == 0)
42718c2ecf20Sopenharmony_ci		return 0;	/* not an error */
42728c2ecf20Sopenharmony_ci	a_num = is_bytchk3 ? 1 : vnum;
42738c2ecf20Sopenharmony_ci	/* Treat following check like one for read (i.e. no write) access */
42748c2ecf20Sopenharmony_ci	ret = check_device_access_params(scp, lba, a_num, false);
42758c2ecf20Sopenharmony_ci	if (ret)
42768c2ecf20Sopenharmony_ci		return ret;
42778c2ecf20Sopenharmony_ci
42788c2ecf20Sopenharmony_ci	arr = kcalloc(lb_size, vnum, GFP_ATOMIC | __GFP_NOWARN);
42798c2ecf20Sopenharmony_ci	if (!arr) {
42808c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
42818c2ecf20Sopenharmony_ci				INSUFF_RES_ASCQ);
42828c2ecf20Sopenharmony_ci		return check_condition_result;
42838c2ecf20Sopenharmony_ci	}
42848c2ecf20Sopenharmony_ci	/* Not changing store, so only need read access */
42858c2ecf20Sopenharmony_ci	read_lock(macc_lckp);
42868c2ecf20Sopenharmony_ci
42878c2ecf20Sopenharmony_ci	ret = do_dout_fetch(scp, a_num, arr);
42888c2ecf20Sopenharmony_ci	if (ret == -1) {
42898c2ecf20Sopenharmony_ci		ret = DID_ERROR << 16;
42908c2ecf20Sopenharmony_ci		goto cleanup;
42918c2ecf20Sopenharmony_ci	} else if (sdebug_verbose && (ret < (a_num * lb_size))) {
42928c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, scp->device,
42938c2ecf20Sopenharmony_ci			    "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
42948c2ecf20Sopenharmony_ci			    my_name, __func__, a_num * lb_size, ret);
42958c2ecf20Sopenharmony_ci	}
42968c2ecf20Sopenharmony_ci	if (is_bytchk3) {
42978c2ecf20Sopenharmony_ci		for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size)
42988c2ecf20Sopenharmony_ci			memcpy(arr + off, arr, lb_size);
42998c2ecf20Sopenharmony_ci	}
43008c2ecf20Sopenharmony_ci	ret = 0;
43018c2ecf20Sopenharmony_ci	if (!comp_write_worker(sip, lba, vnum, arr, true)) {
43028c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
43038c2ecf20Sopenharmony_ci		ret = check_condition_result;
43048c2ecf20Sopenharmony_ci		goto cleanup;
43058c2ecf20Sopenharmony_ci	}
43068c2ecf20Sopenharmony_cicleanup:
43078c2ecf20Sopenharmony_ci	read_unlock(macc_lckp);
43088c2ecf20Sopenharmony_ci	kfree(arr);
43098c2ecf20Sopenharmony_ci	return ret;
43108c2ecf20Sopenharmony_ci}
43118c2ecf20Sopenharmony_ci
43128c2ecf20Sopenharmony_ci#define RZONES_DESC_HD 64
43138c2ecf20Sopenharmony_ci
43148c2ecf20Sopenharmony_ci/* Report zones depending on start LBA nad reporting options */
43158c2ecf20Sopenharmony_cistatic int resp_report_zones(struct scsi_cmnd *scp,
43168c2ecf20Sopenharmony_ci			     struct sdebug_dev_info *devip)
43178c2ecf20Sopenharmony_ci{
43188c2ecf20Sopenharmony_ci	unsigned int i, max_zones, rep_max_zones, nrz = 0;
43198c2ecf20Sopenharmony_ci	int ret = 0;
43208c2ecf20Sopenharmony_ci	u32 alloc_len, rep_opts, rep_len;
43218c2ecf20Sopenharmony_ci	bool partial;
43228c2ecf20Sopenharmony_ci	u64 lba, zs_lba;
43238c2ecf20Sopenharmony_ci	u8 *arr = NULL, *desc;
43248c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
43258c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp;
43268c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, false);
43278c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
43288c2ecf20Sopenharmony_ci
43298c2ecf20Sopenharmony_ci	if (!sdebug_dev_is_zoned(devip)) {
43308c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
43318c2ecf20Sopenharmony_ci		return check_condition_result;
43328c2ecf20Sopenharmony_ci	}
43338c2ecf20Sopenharmony_ci	zs_lba = get_unaligned_be64(cmd + 2);
43348c2ecf20Sopenharmony_ci	alloc_len = get_unaligned_be32(cmd + 10);
43358c2ecf20Sopenharmony_ci	if (alloc_len == 0)
43368c2ecf20Sopenharmony_ci		return 0;	/* not an error */
43378c2ecf20Sopenharmony_ci	rep_opts = cmd[14] & 0x3f;
43388c2ecf20Sopenharmony_ci	partial = cmd[14] & 0x80;
43398c2ecf20Sopenharmony_ci
43408c2ecf20Sopenharmony_ci	if (zs_lba >= sdebug_capacity) {
43418c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
43428c2ecf20Sopenharmony_ci		return check_condition_result;
43438c2ecf20Sopenharmony_ci	}
43448c2ecf20Sopenharmony_ci
43458c2ecf20Sopenharmony_ci	max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
43468c2ecf20Sopenharmony_ci	rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
43478c2ecf20Sopenharmony_ci			    max_zones);
43488c2ecf20Sopenharmony_ci
43498c2ecf20Sopenharmony_ci	arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN);
43508c2ecf20Sopenharmony_ci	if (!arr) {
43518c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
43528c2ecf20Sopenharmony_ci				INSUFF_RES_ASCQ);
43538c2ecf20Sopenharmony_ci		return check_condition_result;
43548c2ecf20Sopenharmony_ci	}
43558c2ecf20Sopenharmony_ci
43568c2ecf20Sopenharmony_ci	read_lock(macc_lckp);
43578c2ecf20Sopenharmony_ci
43588c2ecf20Sopenharmony_ci	desc = arr + 64;
43598c2ecf20Sopenharmony_ci	for (i = 0; i < max_zones; i++) {
43608c2ecf20Sopenharmony_ci		lba = zs_lba + devip->zsize * i;
43618c2ecf20Sopenharmony_ci		if (lba > sdebug_capacity)
43628c2ecf20Sopenharmony_ci			break;
43638c2ecf20Sopenharmony_ci		zsp = zbc_zone(devip, lba);
43648c2ecf20Sopenharmony_ci		switch (rep_opts) {
43658c2ecf20Sopenharmony_ci		case 0x00:
43668c2ecf20Sopenharmony_ci			/* All zones */
43678c2ecf20Sopenharmony_ci			break;
43688c2ecf20Sopenharmony_ci		case 0x01:
43698c2ecf20Sopenharmony_ci			/* Empty zones */
43708c2ecf20Sopenharmony_ci			if (zsp->z_cond != ZC1_EMPTY)
43718c2ecf20Sopenharmony_ci				continue;
43728c2ecf20Sopenharmony_ci			break;
43738c2ecf20Sopenharmony_ci		case 0x02:
43748c2ecf20Sopenharmony_ci			/* Implicit open zones */
43758c2ecf20Sopenharmony_ci			if (zsp->z_cond != ZC2_IMPLICIT_OPEN)
43768c2ecf20Sopenharmony_ci				continue;
43778c2ecf20Sopenharmony_ci			break;
43788c2ecf20Sopenharmony_ci		case 0x03:
43798c2ecf20Sopenharmony_ci			/* Explicit open zones */
43808c2ecf20Sopenharmony_ci			if (zsp->z_cond != ZC3_EXPLICIT_OPEN)
43818c2ecf20Sopenharmony_ci				continue;
43828c2ecf20Sopenharmony_ci			break;
43838c2ecf20Sopenharmony_ci		case 0x04:
43848c2ecf20Sopenharmony_ci			/* Closed zones */
43858c2ecf20Sopenharmony_ci			if (zsp->z_cond != ZC4_CLOSED)
43868c2ecf20Sopenharmony_ci				continue;
43878c2ecf20Sopenharmony_ci			break;
43888c2ecf20Sopenharmony_ci		case 0x05:
43898c2ecf20Sopenharmony_ci			/* Full zones */
43908c2ecf20Sopenharmony_ci			if (zsp->z_cond != ZC5_FULL)
43918c2ecf20Sopenharmony_ci				continue;
43928c2ecf20Sopenharmony_ci			break;
43938c2ecf20Sopenharmony_ci		case 0x06:
43948c2ecf20Sopenharmony_ci		case 0x07:
43958c2ecf20Sopenharmony_ci		case 0x10:
43968c2ecf20Sopenharmony_ci			/*
43978c2ecf20Sopenharmony_ci			 * Read-only, offline, reset WP recommended are
43988c2ecf20Sopenharmony_ci			 * not emulated: no zones to report;
43998c2ecf20Sopenharmony_ci			 */
44008c2ecf20Sopenharmony_ci			continue;
44018c2ecf20Sopenharmony_ci		case 0x11:
44028c2ecf20Sopenharmony_ci			/* non-seq-resource set */
44038c2ecf20Sopenharmony_ci			if (!zsp->z_non_seq_resource)
44048c2ecf20Sopenharmony_ci				continue;
44058c2ecf20Sopenharmony_ci			break;
44068c2ecf20Sopenharmony_ci		case 0x3f:
44078c2ecf20Sopenharmony_ci			/* Not write pointer (conventional) zones */
44088c2ecf20Sopenharmony_ci			if (!zbc_zone_is_conv(zsp))
44098c2ecf20Sopenharmony_ci				continue;
44108c2ecf20Sopenharmony_ci			break;
44118c2ecf20Sopenharmony_ci		default:
44128c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, ILLEGAL_REQUEST,
44138c2ecf20Sopenharmony_ci					INVALID_FIELD_IN_CDB, 0);
44148c2ecf20Sopenharmony_ci			ret = check_condition_result;
44158c2ecf20Sopenharmony_ci			goto fini;
44168c2ecf20Sopenharmony_ci		}
44178c2ecf20Sopenharmony_ci
44188c2ecf20Sopenharmony_ci		if (nrz < rep_max_zones) {
44198c2ecf20Sopenharmony_ci			/* Fill zone descriptor */
44208c2ecf20Sopenharmony_ci			desc[0] = zsp->z_type;
44218c2ecf20Sopenharmony_ci			desc[1] = zsp->z_cond << 4;
44228c2ecf20Sopenharmony_ci			if (zsp->z_non_seq_resource)
44238c2ecf20Sopenharmony_ci				desc[1] |= 1 << 1;
44248c2ecf20Sopenharmony_ci			put_unaligned_be64((u64)zsp->z_size, desc + 8);
44258c2ecf20Sopenharmony_ci			put_unaligned_be64((u64)zsp->z_start, desc + 16);
44268c2ecf20Sopenharmony_ci			put_unaligned_be64((u64)zsp->z_wp, desc + 24);
44278c2ecf20Sopenharmony_ci			desc += 64;
44288c2ecf20Sopenharmony_ci		}
44298c2ecf20Sopenharmony_ci
44308c2ecf20Sopenharmony_ci		if (partial && nrz >= rep_max_zones)
44318c2ecf20Sopenharmony_ci			break;
44328c2ecf20Sopenharmony_ci
44338c2ecf20Sopenharmony_ci		nrz++;
44348c2ecf20Sopenharmony_ci	}
44358c2ecf20Sopenharmony_ci
44368c2ecf20Sopenharmony_ci	/* Report header */
44378c2ecf20Sopenharmony_ci	put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
44388c2ecf20Sopenharmony_ci	put_unaligned_be64(sdebug_capacity - 1, arr + 8);
44398c2ecf20Sopenharmony_ci
44408c2ecf20Sopenharmony_ci	rep_len = (unsigned long)desc - (unsigned long)arr;
44418c2ecf20Sopenharmony_ci	ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
44428c2ecf20Sopenharmony_ci
44438c2ecf20Sopenharmony_cifini:
44448c2ecf20Sopenharmony_ci	read_unlock(macc_lckp);
44458c2ecf20Sopenharmony_ci	kfree(arr);
44468c2ecf20Sopenharmony_ci	return ret;
44478c2ecf20Sopenharmony_ci}
44488c2ecf20Sopenharmony_ci
44498c2ecf20Sopenharmony_ci/* Logic transplanted from tcmu-runner, file_zbc.c */
44508c2ecf20Sopenharmony_cistatic void zbc_open_all(struct sdebug_dev_info *devip)
44518c2ecf20Sopenharmony_ci{
44528c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp = &devip->zstate[0];
44538c2ecf20Sopenharmony_ci	unsigned int i;
44548c2ecf20Sopenharmony_ci
44558c2ecf20Sopenharmony_ci	for (i = 0; i < devip->nr_zones; i++, zsp++) {
44568c2ecf20Sopenharmony_ci		if (zsp->z_cond == ZC4_CLOSED)
44578c2ecf20Sopenharmony_ci			zbc_open_zone(devip, &devip->zstate[i], true);
44588c2ecf20Sopenharmony_ci	}
44598c2ecf20Sopenharmony_ci}
44608c2ecf20Sopenharmony_ci
44618c2ecf20Sopenharmony_cistatic int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
44628c2ecf20Sopenharmony_ci{
44638c2ecf20Sopenharmony_ci	int res = 0;
44648c2ecf20Sopenharmony_ci	u64 z_id;
44658c2ecf20Sopenharmony_ci	enum sdebug_z_cond zc;
44668c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
44678c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp;
44688c2ecf20Sopenharmony_ci	bool all = cmd[14] & 0x01;
44698c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, false);
44708c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
44718c2ecf20Sopenharmony_ci
44728c2ecf20Sopenharmony_ci	if (!sdebug_dev_is_zoned(devip)) {
44738c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
44748c2ecf20Sopenharmony_ci		return check_condition_result;
44758c2ecf20Sopenharmony_ci	}
44768c2ecf20Sopenharmony_ci
44778c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
44788c2ecf20Sopenharmony_ci
44798c2ecf20Sopenharmony_ci	if (all) {
44808c2ecf20Sopenharmony_ci		/* Check if all closed zones can be open */
44818c2ecf20Sopenharmony_ci		if (devip->max_open &&
44828c2ecf20Sopenharmony_ci		    devip->nr_exp_open + devip->nr_closed > devip->max_open) {
44838c2ecf20Sopenharmony_ci			mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
44848c2ecf20Sopenharmony_ci					INSUFF_ZONE_ASCQ);
44858c2ecf20Sopenharmony_ci			res = check_condition_result;
44868c2ecf20Sopenharmony_ci			goto fini;
44878c2ecf20Sopenharmony_ci		}
44888c2ecf20Sopenharmony_ci		/* Open all closed zones */
44898c2ecf20Sopenharmony_ci		zbc_open_all(devip);
44908c2ecf20Sopenharmony_ci		goto fini;
44918c2ecf20Sopenharmony_ci	}
44928c2ecf20Sopenharmony_ci
44938c2ecf20Sopenharmony_ci	/* Open the specified zone */
44948c2ecf20Sopenharmony_ci	z_id = get_unaligned_be64(cmd + 2);
44958c2ecf20Sopenharmony_ci	if (z_id >= sdebug_capacity) {
44968c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
44978c2ecf20Sopenharmony_ci		res = check_condition_result;
44988c2ecf20Sopenharmony_ci		goto fini;
44998c2ecf20Sopenharmony_ci	}
45008c2ecf20Sopenharmony_ci
45018c2ecf20Sopenharmony_ci	zsp = zbc_zone(devip, z_id);
45028c2ecf20Sopenharmony_ci	if (z_id != zsp->z_start) {
45038c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
45048c2ecf20Sopenharmony_ci		res = check_condition_result;
45058c2ecf20Sopenharmony_ci		goto fini;
45068c2ecf20Sopenharmony_ci	}
45078c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp)) {
45088c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
45098c2ecf20Sopenharmony_ci		res = check_condition_result;
45108c2ecf20Sopenharmony_ci		goto fini;
45118c2ecf20Sopenharmony_ci	}
45128c2ecf20Sopenharmony_ci
45138c2ecf20Sopenharmony_ci	zc = zsp->z_cond;
45148c2ecf20Sopenharmony_ci	if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL)
45158c2ecf20Sopenharmony_ci		goto fini;
45168c2ecf20Sopenharmony_ci
45178c2ecf20Sopenharmony_ci	if (devip->max_open && devip->nr_exp_open >= devip->max_open) {
45188c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC,
45198c2ecf20Sopenharmony_ci				INSUFF_ZONE_ASCQ);
45208c2ecf20Sopenharmony_ci		res = check_condition_result;
45218c2ecf20Sopenharmony_ci		goto fini;
45228c2ecf20Sopenharmony_ci	}
45238c2ecf20Sopenharmony_ci
45248c2ecf20Sopenharmony_ci	zbc_open_zone(devip, zsp, true);
45258c2ecf20Sopenharmony_cifini:
45268c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
45278c2ecf20Sopenharmony_ci	return res;
45288c2ecf20Sopenharmony_ci}
45298c2ecf20Sopenharmony_ci
45308c2ecf20Sopenharmony_cistatic void zbc_close_all(struct sdebug_dev_info *devip)
45318c2ecf20Sopenharmony_ci{
45328c2ecf20Sopenharmony_ci	unsigned int i;
45338c2ecf20Sopenharmony_ci
45348c2ecf20Sopenharmony_ci	for (i = 0; i < devip->nr_zones; i++)
45358c2ecf20Sopenharmony_ci		zbc_close_zone(devip, &devip->zstate[i]);
45368c2ecf20Sopenharmony_ci}
45378c2ecf20Sopenharmony_ci
45388c2ecf20Sopenharmony_cistatic int resp_close_zone(struct scsi_cmnd *scp,
45398c2ecf20Sopenharmony_ci			   struct sdebug_dev_info *devip)
45408c2ecf20Sopenharmony_ci{
45418c2ecf20Sopenharmony_ci	int res = 0;
45428c2ecf20Sopenharmony_ci	u64 z_id;
45438c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
45448c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp;
45458c2ecf20Sopenharmony_ci	bool all = cmd[14] & 0x01;
45468c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, false);
45478c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
45488c2ecf20Sopenharmony_ci
45498c2ecf20Sopenharmony_ci	if (!sdebug_dev_is_zoned(devip)) {
45508c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
45518c2ecf20Sopenharmony_ci		return check_condition_result;
45528c2ecf20Sopenharmony_ci	}
45538c2ecf20Sopenharmony_ci
45548c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
45558c2ecf20Sopenharmony_ci
45568c2ecf20Sopenharmony_ci	if (all) {
45578c2ecf20Sopenharmony_ci		zbc_close_all(devip);
45588c2ecf20Sopenharmony_ci		goto fini;
45598c2ecf20Sopenharmony_ci	}
45608c2ecf20Sopenharmony_ci
45618c2ecf20Sopenharmony_ci	/* Close specified zone */
45628c2ecf20Sopenharmony_ci	z_id = get_unaligned_be64(cmd + 2);
45638c2ecf20Sopenharmony_ci	if (z_id >= sdebug_capacity) {
45648c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
45658c2ecf20Sopenharmony_ci		res = check_condition_result;
45668c2ecf20Sopenharmony_ci		goto fini;
45678c2ecf20Sopenharmony_ci	}
45688c2ecf20Sopenharmony_ci
45698c2ecf20Sopenharmony_ci	zsp = zbc_zone(devip, z_id);
45708c2ecf20Sopenharmony_ci	if (z_id != zsp->z_start) {
45718c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
45728c2ecf20Sopenharmony_ci		res = check_condition_result;
45738c2ecf20Sopenharmony_ci		goto fini;
45748c2ecf20Sopenharmony_ci	}
45758c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp)) {
45768c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
45778c2ecf20Sopenharmony_ci		res = check_condition_result;
45788c2ecf20Sopenharmony_ci		goto fini;
45798c2ecf20Sopenharmony_ci	}
45808c2ecf20Sopenharmony_ci
45818c2ecf20Sopenharmony_ci	zbc_close_zone(devip, zsp);
45828c2ecf20Sopenharmony_cifini:
45838c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
45848c2ecf20Sopenharmony_ci	return res;
45858c2ecf20Sopenharmony_ci}
45868c2ecf20Sopenharmony_ci
45878c2ecf20Sopenharmony_cistatic void zbc_finish_zone(struct sdebug_dev_info *devip,
45888c2ecf20Sopenharmony_ci			    struct sdeb_zone_state *zsp, bool empty)
45898c2ecf20Sopenharmony_ci{
45908c2ecf20Sopenharmony_ci	enum sdebug_z_cond zc = zsp->z_cond;
45918c2ecf20Sopenharmony_ci
45928c2ecf20Sopenharmony_ci	if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN ||
45938c2ecf20Sopenharmony_ci	    zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) {
45948c2ecf20Sopenharmony_ci		if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
45958c2ecf20Sopenharmony_ci			zbc_close_zone(devip, zsp);
45968c2ecf20Sopenharmony_ci		if (zsp->z_cond == ZC4_CLOSED)
45978c2ecf20Sopenharmony_ci			devip->nr_closed--;
45988c2ecf20Sopenharmony_ci		zsp->z_wp = zsp->z_start + zsp->z_size;
45998c2ecf20Sopenharmony_ci		zsp->z_cond = ZC5_FULL;
46008c2ecf20Sopenharmony_ci	}
46018c2ecf20Sopenharmony_ci}
46028c2ecf20Sopenharmony_ci
46038c2ecf20Sopenharmony_cistatic void zbc_finish_all(struct sdebug_dev_info *devip)
46048c2ecf20Sopenharmony_ci{
46058c2ecf20Sopenharmony_ci	unsigned int i;
46068c2ecf20Sopenharmony_ci
46078c2ecf20Sopenharmony_ci	for (i = 0; i < devip->nr_zones; i++)
46088c2ecf20Sopenharmony_ci		zbc_finish_zone(devip, &devip->zstate[i], false);
46098c2ecf20Sopenharmony_ci}
46108c2ecf20Sopenharmony_ci
46118c2ecf20Sopenharmony_cistatic int resp_finish_zone(struct scsi_cmnd *scp,
46128c2ecf20Sopenharmony_ci			    struct sdebug_dev_info *devip)
46138c2ecf20Sopenharmony_ci{
46148c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp;
46158c2ecf20Sopenharmony_ci	int res = 0;
46168c2ecf20Sopenharmony_ci	u64 z_id;
46178c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
46188c2ecf20Sopenharmony_ci	bool all = cmd[14] & 0x01;
46198c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, false);
46208c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
46218c2ecf20Sopenharmony_ci
46228c2ecf20Sopenharmony_ci	if (!sdebug_dev_is_zoned(devip)) {
46238c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
46248c2ecf20Sopenharmony_ci		return check_condition_result;
46258c2ecf20Sopenharmony_ci	}
46268c2ecf20Sopenharmony_ci
46278c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
46288c2ecf20Sopenharmony_ci
46298c2ecf20Sopenharmony_ci	if (all) {
46308c2ecf20Sopenharmony_ci		zbc_finish_all(devip);
46318c2ecf20Sopenharmony_ci		goto fini;
46328c2ecf20Sopenharmony_ci	}
46338c2ecf20Sopenharmony_ci
46348c2ecf20Sopenharmony_ci	/* Finish the specified zone */
46358c2ecf20Sopenharmony_ci	z_id = get_unaligned_be64(cmd + 2);
46368c2ecf20Sopenharmony_ci	if (z_id >= sdebug_capacity) {
46378c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
46388c2ecf20Sopenharmony_ci		res = check_condition_result;
46398c2ecf20Sopenharmony_ci		goto fini;
46408c2ecf20Sopenharmony_ci	}
46418c2ecf20Sopenharmony_ci
46428c2ecf20Sopenharmony_ci	zsp = zbc_zone(devip, z_id);
46438c2ecf20Sopenharmony_ci	if (z_id != zsp->z_start) {
46448c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
46458c2ecf20Sopenharmony_ci		res = check_condition_result;
46468c2ecf20Sopenharmony_ci		goto fini;
46478c2ecf20Sopenharmony_ci	}
46488c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp)) {
46498c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
46508c2ecf20Sopenharmony_ci		res = check_condition_result;
46518c2ecf20Sopenharmony_ci		goto fini;
46528c2ecf20Sopenharmony_ci	}
46538c2ecf20Sopenharmony_ci
46548c2ecf20Sopenharmony_ci	zbc_finish_zone(devip, zsp, true);
46558c2ecf20Sopenharmony_cifini:
46568c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
46578c2ecf20Sopenharmony_ci	return res;
46588c2ecf20Sopenharmony_ci}
46598c2ecf20Sopenharmony_ci
46608c2ecf20Sopenharmony_cistatic void zbc_rwp_zone(struct sdebug_dev_info *devip,
46618c2ecf20Sopenharmony_ci			 struct sdeb_zone_state *zsp)
46628c2ecf20Sopenharmony_ci{
46638c2ecf20Sopenharmony_ci	enum sdebug_z_cond zc;
46648c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, false);
46658c2ecf20Sopenharmony_ci
46668c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp))
46678c2ecf20Sopenharmony_ci		return;
46688c2ecf20Sopenharmony_ci
46698c2ecf20Sopenharmony_ci	zc = zsp->z_cond;
46708c2ecf20Sopenharmony_ci	if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)
46718c2ecf20Sopenharmony_ci		zbc_close_zone(devip, zsp);
46728c2ecf20Sopenharmony_ci
46738c2ecf20Sopenharmony_ci	if (zsp->z_cond == ZC4_CLOSED)
46748c2ecf20Sopenharmony_ci		devip->nr_closed--;
46758c2ecf20Sopenharmony_ci
46768c2ecf20Sopenharmony_ci	if (zsp->z_wp > zsp->z_start)
46778c2ecf20Sopenharmony_ci		memset(sip->storep + zsp->z_start * sdebug_sector_size, 0,
46788c2ecf20Sopenharmony_ci		       (zsp->z_wp - zsp->z_start) * sdebug_sector_size);
46798c2ecf20Sopenharmony_ci
46808c2ecf20Sopenharmony_ci	zsp->z_non_seq_resource = false;
46818c2ecf20Sopenharmony_ci	zsp->z_wp = zsp->z_start;
46828c2ecf20Sopenharmony_ci	zsp->z_cond = ZC1_EMPTY;
46838c2ecf20Sopenharmony_ci}
46848c2ecf20Sopenharmony_ci
46858c2ecf20Sopenharmony_cistatic void zbc_rwp_all(struct sdebug_dev_info *devip)
46868c2ecf20Sopenharmony_ci{
46878c2ecf20Sopenharmony_ci	unsigned int i;
46888c2ecf20Sopenharmony_ci
46898c2ecf20Sopenharmony_ci	for (i = 0; i < devip->nr_zones; i++)
46908c2ecf20Sopenharmony_ci		zbc_rwp_zone(devip, &devip->zstate[i]);
46918c2ecf20Sopenharmony_ci}
46928c2ecf20Sopenharmony_ci
46938c2ecf20Sopenharmony_cistatic int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
46948c2ecf20Sopenharmony_ci{
46958c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp;
46968c2ecf20Sopenharmony_ci	int res = 0;
46978c2ecf20Sopenharmony_ci	u64 z_id;
46988c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
46998c2ecf20Sopenharmony_ci	bool all = cmd[14] & 0x01;
47008c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = devip2sip(devip, false);
47018c2ecf20Sopenharmony_ci	rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
47028c2ecf20Sopenharmony_ci
47038c2ecf20Sopenharmony_ci	if (!sdebug_dev_is_zoned(devip)) {
47048c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
47058c2ecf20Sopenharmony_ci		return check_condition_result;
47068c2ecf20Sopenharmony_ci	}
47078c2ecf20Sopenharmony_ci
47088c2ecf20Sopenharmony_ci	write_lock(macc_lckp);
47098c2ecf20Sopenharmony_ci
47108c2ecf20Sopenharmony_ci	if (all) {
47118c2ecf20Sopenharmony_ci		zbc_rwp_all(devip);
47128c2ecf20Sopenharmony_ci		goto fini;
47138c2ecf20Sopenharmony_ci	}
47148c2ecf20Sopenharmony_ci
47158c2ecf20Sopenharmony_ci	z_id = get_unaligned_be64(cmd + 2);
47168c2ecf20Sopenharmony_ci	if (z_id >= sdebug_capacity) {
47178c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
47188c2ecf20Sopenharmony_ci		res = check_condition_result;
47198c2ecf20Sopenharmony_ci		goto fini;
47208c2ecf20Sopenharmony_ci	}
47218c2ecf20Sopenharmony_ci
47228c2ecf20Sopenharmony_ci	zsp = zbc_zone(devip, z_id);
47238c2ecf20Sopenharmony_ci	if (z_id != zsp->z_start) {
47248c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
47258c2ecf20Sopenharmony_ci		res = check_condition_result;
47268c2ecf20Sopenharmony_ci		goto fini;
47278c2ecf20Sopenharmony_ci	}
47288c2ecf20Sopenharmony_ci	if (zbc_zone_is_conv(zsp)) {
47298c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
47308c2ecf20Sopenharmony_ci		res = check_condition_result;
47318c2ecf20Sopenharmony_ci		goto fini;
47328c2ecf20Sopenharmony_ci	}
47338c2ecf20Sopenharmony_ci
47348c2ecf20Sopenharmony_ci	zbc_rwp_zone(devip, zsp);
47358c2ecf20Sopenharmony_cifini:
47368c2ecf20Sopenharmony_ci	write_unlock(macc_lckp);
47378c2ecf20Sopenharmony_ci	return res;
47388c2ecf20Sopenharmony_ci}
47398c2ecf20Sopenharmony_ci
47408c2ecf20Sopenharmony_cistatic struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
47418c2ecf20Sopenharmony_ci{
47428c2ecf20Sopenharmony_ci	u16 hwq;
47438c2ecf20Sopenharmony_ci	u32 tag = blk_mq_unique_tag(cmnd->request);
47448c2ecf20Sopenharmony_ci
47458c2ecf20Sopenharmony_ci	hwq = blk_mq_unique_tag_to_hwq(tag);
47468c2ecf20Sopenharmony_ci
47478c2ecf20Sopenharmony_ci	pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
47488c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(hwq >= submit_queues))
47498c2ecf20Sopenharmony_ci		hwq = 0;
47508c2ecf20Sopenharmony_ci
47518c2ecf20Sopenharmony_ci	return sdebug_q_arr + hwq;
47528c2ecf20Sopenharmony_ci}
47538c2ecf20Sopenharmony_ci
47548c2ecf20Sopenharmony_cistatic u32 get_tag(struct scsi_cmnd *cmnd)
47558c2ecf20Sopenharmony_ci{
47568c2ecf20Sopenharmony_ci	return blk_mq_unique_tag(cmnd->request);
47578c2ecf20Sopenharmony_ci}
47588c2ecf20Sopenharmony_ci
47598c2ecf20Sopenharmony_ci/* Queued (deferred) command completions converge here. */
47608c2ecf20Sopenharmony_cistatic void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
47618c2ecf20Sopenharmony_ci{
47628c2ecf20Sopenharmony_ci	bool aborted = sd_dp->aborted;
47638c2ecf20Sopenharmony_ci	int qc_idx;
47648c2ecf20Sopenharmony_ci	int retiring = 0;
47658c2ecf20Sopenharmony_ci	unsigned long iflags;
47668c2ecf20Sopenharmony_ci	struct sdebug_queue *sqp;
47678c2ecf20Sopenharmony_ci	struct sdebug_queued_cmd *sqcp;
47688c2ecf20Sopenharmony_ci	struct scsi_cmnd *scp;
47698c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
47708c2ecf20Sopenharmony_ci
47718c2ecf20Sopenharmony_ci	sd_dp->defer_t = SDEB_DEFER_NONE;
47728c2ecf20Sopenharmony_ci	if (unlikely(aborted))
47738c2ecf20Sopenharmony_ci		sd_dp->aborted = false;
47748c2ecf20Sopenharmony_ci	qc_idx = sd_dp->qc_idx;
47758c2ecf20Sopenharmony_ci	sqp = sdebug_q_arr + sd_dp->sqa_idx;
47768c2ecf20Sopenharmony_ci	if (sdebug_statistics) {
47778c2ecf20Sopenharmony_ci		atomic_inc(&sdebug_completions);
47788c2ecf20Sopenharmony_ci		if (raw_smp_processor_id() != sd_dp->issuing_cpu)
47798c2ecf20Sopenharmony_ci			atomic_inc(&sdebug_miss_cpus);
47808c2ecf20Sopenharmony_ci	}
47818c2ecf20Sopenharmony_ci	if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
47828c2ecf20Sopenharmony_ci		pr_err("wild qc_idx=%d\n", qc_idx);
47838c2ecf20Sopenharmony_ci		return;
47848c2ecf20Sopenharmony_ci	}
47858c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sqp->qc_lock, iflags);
47868c2ecf20Sopenharmony_ci	sqcp = &sqp->qc_arr[qc_idx];
47878c2ecf20Sopenharmony_ci	scp = sqcp->a_cmnd;
47888c2ecf20Sopenharmony_ci	if (unlikely(scp == NULL)) {
47898c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
47908c2ecf20Sopenharmony_ci		pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n",
47918c2ecf20Sopenharmony_ci		       sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx);
47928c2ecf20Sopenharmony_ci		return;
47938c2ecf20Sopenharmony_ci	}
47948c2ecf20Sopenharmony_ci	devip = (struct sdebug_dev_info *)scp->device->hostdata;
47958c2ecf20Sopenharmony_ci	if (likely(devip))
47968c2ecf20Sopenharmony_ci		atomic_dec(&devip->num_in_q);
47978c2ecf20Sopenharmony_ci	else
47988c2ecf20Sopenharmony_ci		pr_err("devip=NULL\n");
47998c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&retired_max_queue) > 0))
48008c2ecf20Sopenharmony_ci		retiring = 1;
48018c2ecf20Sopenharmony_ci
48028c2ecf20Sopenharmony_ci	sqcp->a_cmnd = NULL;
48038c2ecf20Sopenharmony_ci	if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
48048c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
48058c2ecf20Sopenharmony_ci		pr_err("Unexpected completion\n");
48068c2ecf20Sopenharmony_ci		return;
48078c2ecf20Sopenharmony_ci	}
48088c2ecf20Sopenharmony_ci
48098c2ecf20Sopenharmony_ci	if (unlikely(retiring)) {	/* user has reduced max_queue */
48108c2ecf20Sopenharmony_ci		int k, retval;
48118c2ecf20Sopenharmony_ci
48128c2ecf20Sopenharmony_ci		retval = atomic_read(&retired_max_queue);
48138c2ecf20Sopenharmony_ci		if (qc_idx >= retval) {
48148c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
48158c2ecf20Sopenharmony_ci			pr_err("index %d too large\n", retval);
48168c2ecf20Sopenharmony_ci			return;
48178c2ecf20Sopenharmony_ci		}
48188c2ecf20Sopenharmony_ci		k = find_last_bit(sqp->in_use_bm, retval);
48198c2ecf20Sopenharmony_ci		if ((k < sdebug_max_queue) || (k == retval))
48208c2ecf20Sopenharmony_ci			atomic_set(&retired_max_queue, 0);
48218c2ecf20Sopenharmony_ci		else
48228c2ecf20Sopenharmony_ci			atomic_set(&retired_max_queue, k + 1);
48238c2ecf20Sopenharmony_ci	}
48248c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
48258c2ecf20Sopenharmony_ci	if (unlikely(aborted)) {
48268c2ecf20Sopenharmony_ci		if (sdebug_verbose)
48278c2ecf20Sopenharmony_ci			pr_info("bypassing scsi_done() due to aborted cmd\n");
48288c2ecf20Sopenharmony_ci		return;
48298c2ecf20Sopenharmony_ci	}
48308c2ecf20Sopenharmony_ci	scp->scsi_done(scp); /* callback to mid level */
48318c2ecf20Sopenharmony_ci}
48328c2ecf20Sopenharmony_ci
48338c2ecf20Sopenharmony_ci/* When high resolution timer goes off this function is called. */
48348c2ecf20Sopenharmony_cistatic enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
48358c2ecf20Sopenharmony_ci{
48368c2ecf20Sopenharmony_ci	struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
48378c2ecf20Sopenharmony_ci						  hrt);
48388c2ecf20Sopenharmony_ci	sdebug_q_cmd_complete(sd_dp);
48398c2ecf20Sopenharmony_ci	return HRTIMER_NORESTART;
48408c2ecf20Sopenharmony_ci}
48418c2ecf20Sopenharmony_ci
48428c2ecf20Sopenharmony_ci/* When work queue schedules work, it calls this function. */
48438c2ecf20Sopenharmony_cistatic void sdebug_q_cmd_wq_complete(struct work_struct *work)
48448c2ecf20Sopenharmony_ci{
48458c2ecf20Sopenharmony_ci	struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
48468c2ecf20Sopenharmony_ci						  ew.work);
48478c2ecf20Sopenharmony_ci	sdebug_q_cmd_complete(sd_dp);
48488c2ecf20Sopenharmony_ci}
48498c2ecf20Sopenharmony_ci
48508c2ecf20Sopenharmony_cistatic bool got_shared_uuid;
48518c2ecf20Sopenharmony_cistatic uuid_t shared_uuid;
48528c2ecf20Sopenharmony_ci
48538c2ecf20Sopenharmony_cistatic int sdebug_device_create_zones(struct sdebug_dev_info *devip)
48548c2ecf20Sopenharmony_ci{
48558c2ecf20Sopenharmony_ci	struct sdeb_zone_state *zsp;
48568c2ecf20Sopenharmony_ci	sector_t capacity = get_sdebug_capacity();
48578c2ecf20Sopenharmony_ci	sector_t zstart = 0;
48588c2ecf20Sopenharmony_ci	unsigned int i;
48598c2ecf20Sopenharmony_ci
48608c2ecf20Sopenharmony_ci	/*
48618c2ecf20Sopenharmony_ci	 * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out
48628c2ecf20Sopenharmony_ci	 * a zone size allowing for at least 4 zones on the device. Otherwise,
48638c2ecf20Sopenharmony_ci	 * use the specified zone size checking that at least 2 zones can be
48648c2ecf20Sopenharmony_ci	 * created for the device.
48658c2ecf20Sopenharmony_ci	 */
48668c2ecf20Sopenharmony_ci	if (!sdeb_zbc_zone_size_mb) {
48678c2ecf20Sopenharmony_ci		devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M)
48688c2ecf20Sopenharmony_ci			>> ilog2(sdebug_sector_size);
48698c2ecf20Sopenharmony_ci		while (capacity < devip->zsize << 2 && devip->zsize >= 2)
48708c2ecf20Sopenharmony_ci			devip->zsize >>= 1;
48718c2ecf20Sopenharmony_ci		if (devip->zsize < 2) {
48728c2ecf20Sopenharmony_ci			pr_err("Device capacity too small\n");
48738c2ecf20Sopenharmony_ci			return -EINVAL;
48748c2ecf20Sopenharmony_ci		}
48758c2ecf20Sopenharmony_ci	} else {
48768c2ecf20Sopenharmony_ci		if (!is_power_of_2(sdeb_zbc_zone_size_mb)) {
48778c2ecf20Sopenharmony_ci			pr_err("Zone size is not a power of 2\n");
48788c2ecf20Sopenharmony_ci			return -EINVAL;
48798c2ecf20Sopenharmony_ci		}
48808c2ecf20Sopenharmony_ci		devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M)
48818c2ecf20Sopenharmony_ci			>> ilog2(sdebug_sector_size);
48828c2ecf20Sopenharmony_ci		if (devip->zsize >= capacity) {
48838c2ecf20Sopenharmony_ci			pr_err("Zone size too large for device capacity\n");
48848c2ecf20Sopenharmony_ci			return -EINVAL;
48858c2ecf20Sopenharmony_ci		}
48868c2ecf20Sopenharmony_ci	}
48878c2ecf20Sopenharmony_ci
48888c2ecf20Sopenharmony_ci	devip->zsize_shift = ilog2(devip->zsize);
48898c2ecf20Sopenharmony_ci	devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
48908c2ecf20Sopenharmony_ci
48918c2ecf20Sopenharmony_ci	if (sdeb_zbc_nr_conv >= devip->nr_zones) {
48928c2ecf20Sopenharmony_ci		pr_err("Number of conventional zones too large\n");
48938c2ecf20Sopenharmony_ci		return -EINVAL;
48948c2ecf20Sopenharmony_ci	}
48958c2ecf20Sopenharmony_ci	devip->nr_conv_zones = sdeb_zbc_nr_conv;
48968c2ecf20Sopenharmony_ci
48978c2ecf20Sopenharmony_ci	if (devip->zmodel == BLK_ZONED_HM) {
48988c2ecf20Sopenharmony_ci		/* zbc_max_open_zones can be 0, meaning "not reported" */
48998c2ecf20Sopenharmony_ci		if (sdeb_zbc_max_open >= devip->nr_zones - 1)
49008c2ecf20Sopenharmony_ci			devip->max_open = (devip->nr_zones - 1) / 2;
49018c2ecf20Sopenharmony_ci		else
49028c2ecf20Sopenharmony_ci			devip->max_open = sdeb_zbc_max_open;
49038c2ecf20Sopenharmony_ci	}
49048c2ecf20Sopenharmony_ci
49058c2ecf20Sopenharmony_ci	devip->zstate = kcalloc(devip->nr_zones,
49068c2ecf20Sopenharmony_ci				sizeof(struct sdeb_zone_state), GFP_KERNEL);
49078c2ecf20Sopenharmony_ci	if (!devip->zstate)
49088c2ecf20Sopenharmony_ci		return -ENOMEM;
49098c2ecf20Sopenharmony_ci
49108c2ecf20Sopenharmony_ci	for (i = 0; i < devip->nr_zones; i++) {
49118c2ecf20Sopenharmony_ci		zsp = &devip->zstate[i];
49128c2ecf20Sopenharmony_ci
49138c2ecf20Sopenharmony_ci		zsp->z_start = zstart;
49148c2ecf20Sopenharmony_ci
49158c2ecf20Sopenharmony_ci		if (i < devip->nr_conv_zones) {
49168c2ecf20Sopenharmony_ci			zsp->z_type = ZBC_ZONE_TYPE_CNV;
49178c2ecf20Sopenharmony_ci			zsp->z_cond = ZBC_NOT_WRITE_POINTER;
49188c2ecf20Sopenharmony_ci			zsp->z_wp = (sector_t)-1;
49198c2ecf20Sopenharmony_ci		} else {
49208c2ecf20Sopenharmony_ci			if (devip->zmodel == BLK_ZONED_HM)
49218c2ecf20Sopenharmony_ci				zsp->z_type = ZBC_ZONE_TYPE_SWR;
49228c2ecf20Sopenharmony_ci			else
49238c2ecf20Sopenharmony_ci				zsp->z_type = ZBC_ZONE_TYPE_SWP;
49248c2ecf20Sopenharmony_ci			zsp->z_cond = ZC1_EMPTY;
49258c2ecf20Sopenharmony_ci			zsp->z_wp = zsp->z_start;
49268c2ecf20Sopenharmony_ci		}
49278c2ecf20Sopenharmony_ci
49288c2ecf20Sopenharmony_ci		if (zsp->z_start + devip->zsize < capacity)
49298c2ecf20Sopenharmony_ci			zsp->z_size = devip->zsize;
49308c2ecf20Sopenharmony_ci		else
49318c2ecf20Sopenharmony_ci			zsp->z_size = capacity - zsp->z_start;
49328c2ecf20Sopenharmony_ci
49338c2ecf20Sopenharmony_ci		zstart += zsp->z_size;
49348c2ecf20Sopenharmony_ci	}
49358c2ecf20Sopenharmony_ci
49368c2ecf20Sopenharmony_ci	return 0;
49378c2ecf20Sopenharmony_ci}
49388c2ecf20Sopenharmony_ci
49398c2ecf20Sopenharmony_cistatic struct sdebug_dev_info *sdebug_device_create(
49408c2ecf20Sopenharmony_ci			struct sdebug_host_info *sdbg_host, gfp_t flags)
49418c2ecf20Sopenharmony_ci{
49428c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
49438c2ecf20Sopenharmony_ci
49448c2ecf20Sopenharmony_ci	devip = kzalloc(sizeof(*devip), flags);
49458c2ecf20Sopenharmony_ci	if (devip) {
49468c2ecf20Sopenharmony_ci		if (sdebug_uuid_ctl == 1)
49478c2ecf20Sopenharmony_ci			uuid_gen(&devip->lu_name);
49488c2ecf20Sopenharmony_ci		else if (sdebug_uuid_ctl == 2) {
49498c2ecf20Sopenharmony_ci			if (got_shared_uuid)
49508c2ecf20Sopenharmony_ci				devip->lu_name = shared_uuid;
49518c2ecf20Sopenharmony_ci			else {
49528c2ecf20Sopenharmony_ci				uuid_gen(&shared_uuid);
49538c2ecf20Sopenharmony_ci				got_shared_uuid = true;
49548c2ecf20Sopenharmony_ci				devip->lu_name = shared_uuid;
49558c2ecf20Sopenharmony_ci			}
49568c2ecf20Sopenharmony_ci		}
49578c2ecf20Sopenharmony_ci		devip->sdbg_host = sdbg_host;
49588c2ecf20Sopenharmony_ci		if (sdeb_zbc_in_use) {
49598c2ecf20Sopenharmony_ci			devip->zmodel = sdeb_zbc_model;
49608c2ecf20Sopenharmony_ci			if (sdebug_device_create_zones(devip)) {
49618c2ecf20Sopenharmony_ci				kfree(devip);
49628c2ecf20Sopenharmony_ci				return NULL;
49638c2ecf20Sopenharmony_ci			}
49648c2ecf20Sopenharmony_ci		} else {
49658c2ecf20Sopenharmony_ci			devip->zmodel = BLK_ZONED_NONE;
49668c2ecf20Sopenharmony_ci		}
49678c2ecf20Sopenharmony_ci		devip->sdbg_host = sdbg_host;
49688c2ecf20Sopenharmony_ci		devip->create_ts = ktime_get_boottime();
49698c2ecf20Sopenharmony_ci		atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0));
49708c2ecf20Sopenharmony_ci		list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
49718c2ecf20Sopenharmony_ci	}
49728c2ecf20Sopenharmony_ci	return devip;
49738c2ecf20Sopenharmony_ci}
49748c2ecf20Sopenharmony_ci
49758c2ecf20Sopenharmony_cistatic struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
49768c2ecf20Sopenharmony_ci{
49778c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
49788c2ecf20Sopenharmony_ci	struct sdebug_dev_info *open_devip = NULL;
49798c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
49808c2ecf20Sopenharmony_ci
49818c2ecf20Sopenharmony_ci	sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
49828c2ecf20Sopenharmony_ci	if (!sdbg_host) {
49838c2ecf20Sopenharmony_ci		pr_err("Host info NULL\n");
49848c2ecf20Sopenharmony_ci		return NULL;
49858c2ecf20Sopenharmony_ci	}
49868c2ecf20Sopenharmony_ci
49878c2ecf20Sopenharmony_ci	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
49888c2ecf20Sopenharmony_ci		if ((devip->used) && (devip->channel == sdev->channel) &&
49898c2ecf20Sopenharmony_ci		    (devip->target == sdev->id) &&
49908c2ecf20Sopenharmony_ci		    (devip->lun == sdev->lun))
49918c2ecf20Sopenharmony_ci			return devip;
49928c2ecf20Sopenharmony_ci		else {
49938c2ecf20Sopenharmony_ci			if ((!devip->used) && (!open_devip))
49948c2ecf20Sopenharmony_ci				open_devip = devip;
49958c2ecf20Sopenharmony_ci		}
49968c2ecf20Sopenharmony_ci	}
49978c2ecf20Sopenharmony_ci	if (!open_devip) { /* try and make a new one */
49988c2ecf20Sopenharmony_ci		open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
49998c2ecf20Sopenharmony_ci		if (!open_devip) {
50008c2ecf20Sopenharmony_ci			pr_err("out of memory at line %d\n", __LINE__);
50018c2ecf20Sopenharmony_ci			return NULL;
50028c2ecf20Sopenharmony_ci		}
50038c2ecf20Sopenharmony_ci	}
50048c2ecf20Sopenharmony_ci
50058c2ecf20Sopenharmony_ci	open_devip->channel = sdev->channel;
50068c2ecf20Sopenharmony_ci	open_devip->target = sdev->id;
50078c2ecf20Sopenharmony_ci	open_devip->lun = sdev->lun;
50088c2ecf20Sopenharmony_ci	open_devip->sdbg_host = sdbg_host;
50098c2ecf20Sopenharmony_ci	atomic_set(&open_devip->num_in_q, 0);
50108c2ecf20Sopenharmony_ci	set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
50118c2ecf20Sopenharmony_ci	open_devip->used = true;
50128c2ecf20Sopenharmony_ci	return open_devip;
50138c2ecf20Sopenharmony_ci}
50148c2ecf20Sopenharmony_ci
50158c2ecf20Sopenharmony_cistatic int scsi_debug_slave_alloc(struct scsi_device *sdp)
50168c2ecf20Sopenharmony_ci{
50178c2ecf20Sopenharmony_ci	if (sdebug_verbose)
50188c2ecf20Sopenharmony_ci		pr_info("slave_alloc <%u %u %u %llu>\n",
50198c2ecf20Sopenharmony_ci		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50208c2ecf20Sopenharmony_ci	return 0;
50218c2ecf20Sopenharmony_ci}
50228c2ecf20Sopenharmony_ci
50238c2ecf20Sopenharmony_cistatic int scsi_debug_slave_configure(struct scsi_device *sdp)
50248c2ecf20Sopenharmony_ci{
50258c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip =
50268c2ecf20Sopenharmony_ci			(struct sdebug_dev_info *)sdp->hostdata;
50278c2ecf20Sopenharmony_ci
50288c2ecf20Sopenharmony_ci	if (sdebug_verbose)
50298c2ecf20Sopenharmony_ci		pr_info("slave_configure <%u %u %u %llu>\n",
50308c2ecf20Sopenharmony_ci		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50318c2ecf20Sopenharmony_ci	if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
50328c2ecf20Sopenharmony_ci		sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
50338c2ecf20Sopenharmony_ci	if (devip == NULL) {
50348c2ecf20Sopenharmony_ci		devip = find_build_dev_info(sdp);
50358c2ecf20Sopenharmony_ci		if (devip == NULL)
50368c2ecf20Sopenharmony_ci			return 1;  /* no resources, will be marked offline */
50378c2ecf20Sopenharmony_ci	}
50388c2ecf20Sopenharmony_ci	sdp->hostdata = devip;
50398c2ecf20Sopenharmony_ci	if (sdebug_no_uld)
50408c2ecf20Sopenharmony_ci		sdp->no_uld_attach = 1;
50418c2ecf20Sopenharmony_ci	config_cdb_len(sdp);
50428c2ecf20Sopenharmony_ci	return 0;
50438c2ecf20Sopenharmony_ci}
50448c2ecf20Sopenharmony_ci
50458c2ecf20Sopenharmony_cistatic void scsi_debug_slave_destroy(struct scsi_device *sdp)
50468c2ecf20Sopenharmony_ci{
50478c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip =
50488c2ecf20Sopenharmony_ci		(struct sdebug_dev_info *)sdp->hostdata;
50498c2ecf20Sopenharmony_ci
50508c2ecf20Sopenharmony_ci	if (sdebug_verbose)
50518c2ecf20Sopenharmony_ci		pr_info("slave_destroy <%u %u %u %llu>\n",
50528c2ecf20Sopenharmony_ci		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
50538c2ecf20Sopenharmony_ci	if (devip) {
50548c2ecf20Sopenharmony_ci		/* make this slot available for re-use */
50558c2ecf20Sopenharmony_ci		devip->used = false;
50568c2ecf20Sopenharmony_ci		sdp->hostdata = NULL;
50578c2ecf20Sopenharmony_ci	}
50588c2ecf20Sopenharmony_ci}
50598c2ecf20Sopenharmony_ci
50608c2ecf20Sopenharmony_cistatic void stop_qc_helper(struct sdebug_defer *sd_dp,
50618c2ecf20Sopenharmony_ci			   enum sdeb_defer_type defer_t)
50628c2ecf20Sopenharmony_ci{
50638c2ecf20Sopenharmony_ci	if (!sd_dp)
50648c2ecf20Sopenharmony_ci		return;
50658c2ecf20Sopenharmony_ci	if (defer_t == SDEB_DEFER_HRT)
50668c2ecf20Sopenharmony_ci		hrtimer_cancel(&sd_dp->hrt);
50678c2ecf20Sopenharmony_ci	else if (defer_t == SDEB_DEFER_WQ)
50688c2ecf20Sopenharmony_ci		cancel_work_sync(&sd_dp->ew.work);
50698c2ecf20Sopenharmony_ci}
50708c2ecf20Sopenharmony_ci
50718c2ecf20Sopenharmony_ci/* If @cmnd found deletes its timer or work queue and returns true; else
50728c2ecf20Sopenharmony_ci   returns false */
50738c2ecf20Sopenharmony_cistatic bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
50748c2ecf20Sopenharmony_ci{
50758c2ecf20Sopenharmony_ci	unsigned long iflags;
50768c2ecf20Sopenharmony_ci	int j, k, qmax, r_qmax;
50778c2ecf20Sopenharmony_ci	enum sdeb_defer_type l_defer_t;
50788c2ecf20Sopenharmony_ci	struct sdebug_queue *sqp;
50798c2ecf20Sopenharmony_ci	struct sdebug_queued_cmd *sqcp;
50808c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
50818c2ecf20Sopenharmony_ci	struct sdebug_defer *sd_dp;
50828c2ecf20Sopenharmony_ci
50838c2ecf20Sopenharmony_ci	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
50848c2ecf20Sopenharmony_ci		spin_lock_irqsave(&sqp->qc_lock, iflags);
50858c2ecf20Sopenharmony_ci		qmax = sdebug_max_queue;
50868c2ecf20Sopenharmony_ci		r_qmax = atomic_read(&retired_max_queue);
50878c2ecf20Sopenharmony_ci		if (r_qmax > qmax)
50888c2ecf20Sopenharmony_ci			qmax = r_qmax;
50898c2ecf20Sopenharmony_ci		for (k = 0; k < qmax; ++k) {
50908c2ecf20Sopenharmony_ci			if (test_bit(k, sqp->in_use_bm)) {
50918c2ecf20Sopenharmony_ci				sqcp = &sqp->qc_arr[k];
50928c2ecf20Sopenharmony_ci				if (cmnd != sqcp->a_cmnd)
50938c2ecf20Sopenharmony_ci					continue;
50948c2ecf20Sopenharmony_ci				/* found */
50958c2ecf20Sopenharmony_ci				devip = (struct sdebug_dev_info *)
50968c2ecf20Sopenharmony_ci						cmnd->device->hostdata;
50978c2ecf20Sopenharmony_ci				if (devip)
50988c2ecf20Sopenharmony_ci					atomic_dec(&devip->num_in_q);
50998c2ecf20Sopenharmony_ci				sqcp->a_cmnd = NULL;
51008c2ecf20Sopenharmony_ci				sd_dp = sqcp->sd_dp;
51018c2ecf20Sopenharmony_ci				if (sd_dp) {
51028c2ecf20Sopenharmony_ci					l_defer_t = sd_dp->defer_t;
51038c2ecf20Sopenharmony_ci					sd_dp->defer_t = SDEB_DEFER_NONE;
51048c2ecf20Sopenharmony_ci				} else
51058c2ecf20Sopenharmony_ci					l_defer_t = SDEB_DEFER_NONE;
51068c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
51078c2ecf20Sopenharmony_ci				stop_qc_helper(sd_dp, l_defer_t);
51088c2ecf20Sopenharmony_ci				clear_bit(k, sqp->in_use_bm);
51098c2ecf20Sopenharmony_ci				return true;
51108c2ecf20Sopenharmony_ci			}
51118c2ecf20Sopenharmony_ci		}
51128c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
51138c2ecf20Sopenharmony_ci	}
51148c2ecf20Sopenharmony_ci	return false;
51158c2ecf20Sopenharmony_ci}
51168c2ecf20Sopenharmony_ci
51178c2ecf20Sopenharmony_ci/* Deletes (stops) timers or work queues of all queued commands */
51188c2ecf20Sopenharmony_cistatic void stop_all_queued(void)
51198c2ecf20Sopenharmony_ci{
51208c2ecf20Sopenharmony_ci	unsigned long iflags;
51218c2ecf20Sopenharmony_ci	int j, k;
51228c2ecf20Sopenharmony_ci	enum sdeb_defer_type l_defer_t;
51238c2ecf20Sopenharmony_ci	struct sdebug_queue *sqp;
51248c2ecf20Sopenharmony_ci	struct sdebug_queued_cmd *sqcp;
51258c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
51268c2ecf20Sopenharmony_ci	struct sdebug_defer *sd_dp;
51278c2ecf20Sopenharmony_ci
51288c2ecf20Sopenharmony_ci	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
51298c2ecf20Sopenharmony_ci		spin_lock_irqsave(&sqp->qc_lock, iflags);
51308c2ecf20Sopenharmony_ci		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
51318c2ecf20Sopenharmony_ci			if (test_bit(k, sqp->in_use_bm)) {
51328c2ecf20Sopenharmony_ci				sqcp = &sqp->qc_arr[k];
51338c2ecf20Sopenharmony_ci				if (sqcp->a_cmnd == NULL)
51348c2ecf20Sopenharmony_ci					continue;
51358c2ecf20Sopenharmony_ci				devip = (struct sdebug_dev_info *)
51368c2ecf20Sopenharmony_ci					sqcp->a_cmnd->device->hostdata;
51378c2ecf20Sopenharmony_ci				if (devip)
51388c2ecf20Sopenharmony_ci					atomic_dec(&devip->num_in_q);
51398c2ecf20Sopenharmony_ci				sqcp->a_cmnd = NULL;
51408c2ecf20Sopenharmony_ci				sd_dp = sqcp->sd_dp;
51418c2ecf20Sopenharmony_ci				if (sd_dp) {
51428c2ecf20Sopenharmony_ci					l_defer_t = sd_dp->defer_t;
51438c2ecf20Sopenharmony_ci					sd_dp->defer_t = SDEB_DEFER_NONE;
51448c2ecf20Sopenharmony_ci				} else
51458c2ecf20Sopenharmony_ci					l_defer_t = SDEB_DEFER_NONE;
51468c2ecf20Sopenharmony_ci				spin_unlock_irqrestore(&sqp->qc_lock, iflags);
51478c2ecf20Sopenharmony_ci				stop_qc_helper(sd_dp, l_defer_t);
51488c2ecf20Sopenharmony_ci				clear_bit(k, sqp->in_use_bm);
51498c2ecf20Sopenharmony_ci				spin_lock_irqsave(&sqp->qc_lock, iflags);
51508c2ecf20Sopenharmony_ci			}
51518c2ecf20Sopenharmony_ci		}
51528c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
51538c2ecf20Sopenharmony_ci	}
51548c2ecf20Sopenharmony_ci}
51558c2ecf20Sopenharmony_ci
51568c2ecf20Sopenharmony_ci/* Free queued command memory on heap */
51578c2ecf20Sopenharmony_cistatic void free_all_queued(void)
51588c2ecf20Sopenharmony_ci{
51598c2ecf20Sopenharmony_ci	int j, k;
51608c2ecf20Sopenharmony_ci	struct sdebug_queue *sqp;
51618c2ecf20Sopenharmony_ci	struct sdebug_queued_cmd *sqcp;
51628c2ecf20Sopenharmony_ci
51638c2ecf20Sopenharmony_ci	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
51648c2ecf20Sopenharmony_ci		for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
51658c2ecf20Sopenharmony_ci			sqcp = &sqp->qc_arr[k];
51668c2ecf20Sopenharmony_ci			kfree(sqcp->sd_dp);
51678c2ecf20Sopenharmony_ci			sqcp->sd_dp = NULL;
51688c2ecf20Sopenharmony_ci		}
51698c2ecf20Sopenharmony_ci	}
51708c2ecf20Sopenharmony_ci}
51718c2ecf20Sopenharmony_ci
51728c2ecf20Sopenharmony_cistatic int scsi_debug_abort(struct scsi_cmnd *SCpnt)
51738c2ecf20Sopenharmony_ci{
51748c2ecf20Sopenharmony_ci	bool ok;
51758c2ecf20Sopenharmony_ci
51768c2ecf20Sopenharmony_ci	++num_aborts;
51778c2ecf20Sopenharmony_ci	if (SCpnt) {
51788c2ecf20Sopenharmony_ci		ok = stop_queued_cmnd(SCpnt);
51798c2ecf20Sopenharmony_ci		if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
51808c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, SCpnt->device,
51818c2ecf20Sopenharmony_ci				    "%s: command%s found\n", __func__,
51828c2ecf20Sopenharmony_ci				    ok ? "" : " not");
51838c2ecf20Sopenharmony_ci	}
51848c2ecf20Sopenharmony_ci	return SUCCESS;
51858c2ecf20Sopenharmony_ci}
51868c2ecf20Sopenharmony_ci
51878c2ecf20Sopenharmony_cistatic int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
51888c2ecf20Sopenharmony_ci{
51898c2ecf20Sopenharmony_ci	++num_dev_resets;
51908c2ecf20Sopenharmony_ci	if (SCpnt && SCpnt->device) {
51918c2ecf20Sopenharmony_ci		struct scsi_device *sdp = SCpnt->device;
51928c2ecf20Sopenharmony_ci		struct sdebug_dev_info *devip =
51938c2ecf20Sopenharmony_ci				(struct sdebug_dev_info *)sdp->hostdata;
51948c2ecf20Sopenharmony_ci
51958c2ecf20Sopenharmony_ci		if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
51968c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
51978c2ecf20Sopenharmony_ci		if (devip)
51988c2ecf20Sopenharmony_ci			set_bit(SDEBUG_UA_POR, devip->uas_bm);
51998c2ecf20Sopenharmony_ci	}
52008c2ecf20Sopenharmony_ci	return SUCCESS;
52018c2ecf20Sopenharmony_ci}
52028c2ecf20Sopenharmony_ci
52038c2ecf20Sopenharmony_cistatic int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
52048c2ecf20Sopenharmony_ci{
52058c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
52068c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
52078c2ecf20Sopenharmony_ci	struct scsi_device *sdp;
52088c2ecf20Sopenharmony_ci	struct Scsi_Host *hp;
52098c2ecf20Sopenharmony_ci	int k = 0;
52108c2ecf20Sopenharmony_ci
52118c2ecf20Sopenharmony_ci	++num_target_resets;
52128c2ecf20Sopenharmony_ci	if (!SCpnt)
52138c2ecf20Sopenharmony_ci		goto lie;
52148c2ecf20Sopenharmony_ci	sdp = SCpnt->device;
52158c2ecf20Sopenharmony_ci	if (!sdp)
52168c2ecf20Sopenharmony_ci		goto lie;
52178c2ecf20Sopenharmony_ci	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
52188c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
52198c2ecf20Sopenharmony_ci	hp = sdp->host;
52208c2ecf20Sopenharmony_ci	if (!hp)
52218c2ecf20Sopenharmony_ci		goto lie;
52228c2ecf20Sopenharmony_ci	sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
52238c2ecf20Sopenharmony_ci	if (sdbg_host) {
52248c2ecf20Sopenharmony_ci		list_for_each_entry(devip,
52258c2ecf20Sopenharmony_ci				    &sdbg_host->dev_info_list,
52268c2ecf20Sopenharmony_ci				    dev_list)
52278c2ecf20Sopenharmony_ci			if (devip->target == sdp->id) {
52288c2ecf20Sopenharmony_ci				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
52298c2ecf20Sopenharmony_ci				++k;
52308c2ecf20Sopenharmony_ci			}
52318c2ecf20Sopenharmony_ci	}
52328c2ecf20Sopenharmony_ci	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
52338c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdp,
52348c2ecf20Sopenharmony_ci			    "%s: %d device(s) found in target\n", __func__, k);
52358c2ecf20Sopenharmony_cilie:
52368c2ecf20Sopenharmony_ci	return SUCCESS;
52378c2ecf20Sopenharmony_ci}
52388c2ecf20Sopenharmony_ci
52398c2ecf20Sopenharmony_cistatic int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
52408c2ecf20Sopenharmony_ci{
52418c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
52428c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
52438c2ecf20Sopenharmony_ci	struct scsi_device *sdp;
52448c2ecf20Sopenharmony_ci	struct Scsi_Host *hp;
52458c2ecf20Sopenharmony_ci	int k = 0;
52468c2ecf20Sopenharmony_ci
52478c2ecf20Sopenharmony_ci	++num_bus_resets;
52488c2ecf20Sopenharmony_ci	if (!(SCpnt && SCpnt->device))
52498c2ecf20Sopenharmony_ci		goto lie;
52508c2ecf20Sopenharmony_ci	sdp = SCpnt->device;
52518c2ecf20Sopenharmony_ci	if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
52528c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
52538c2ecf20Sopenharmony_ci	hp = sdp->host;
52548c2ecf20Sopenharmony_ci	if (hp) {
52558c2ecf20Sopenharmony_ci		sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
52568c2ecf20Sopenharmony_ci		if (sdbg_host) {
52578c2ecf20Sopenharmony_ci			list_for_each_entry(devip,
52588c2ecf20Sopenharmony_ci					    &sdbg_host->dev_info_list,
52598c2ecf20Sopenharmony_ci					    dev_list) {
52608c2ecf20Sopenharmony_ci				set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
52618c2ecf20Sopenharmony_ci				++k;
52628c2ecf20Sopenharmony_ci			}
52638c2ecf20Sopenharmony_ci		}
52648c2ecf20Sopenharmony_ci	}
52658c2ecf20Sopenharmony_ci	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
52668c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdp,
52678c2ecf20Sopenharmony_ci			    "%s: %d device(s) found in host\n", __func__, k);
52688c2ecf20Sopenharmony_cilie:
52698c2ecf20Sopenharmony_ci	return SUCCESS;
52708c2ecf20Sopenharmony_ci}
52718c2ecf20Sopenharmony_ci
52728c2ecf20Sopenharmony_cistatic int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
52738c2ecf20Sopenharmony_ci{
52748c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
52758c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
52768c2ecf20Sopenharmony_ci	int k = 0;
52778c2ecf20Sopenharmony_ci
52788c2ecf20Sopenharmony_ci	++num_host_resets;
52798c2ecf20Sopenharmony_ci	if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
52808c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
52818c2ecf20Sopenharmony_ci	spin_lock(&sdebug_host_list_lock);
52828c2ecf20Sopenharmony_ci	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
52838c2ecf20Sopenharmony_ci		list_for_each_entry(devip, &sdbg_host->dev_info_list,
52848c2ecf20Sopenharmony_ci				    dev_list) {
52858c2ecf20Sopenharmony_ci			set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
52868c2ecf20Sopenharmony_ci			++k;
52878c2ecf20Sopenharmony_ci		}
52888c2ecf20Sopenharmony_ci	}
52898c2ecf20Sopenharmony_ci	spin_unlock(&sdebug_host_list_lock);
52908c2ecf20Sopenharmony_ci	stop_all_queued();
52918c2ecf20Sopenharmony_ci	if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
52928c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, SCpnt->device,
52938c2ecf20Sopenharmony_ci			    "%s: %d device(s) found\n", __func__, k);
52948c2ecf20Sopenharmony_ci	return SUCCESS;
52958c2ecf20Sopenharmony_ci}
52968c2ecf20Sopenharmony_ci
52978c2ecf20Sopenharmony_cistatic void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
52988c2ecf20Sopenharmony_ci{
52998c2ecf20Sopenharmony_ci	struct msdos_partition *pp;
53008c2ecf20Sopenharmony_ci	int starts[SDEBUG_MAX_PARTS + 2], max_part_secs;
53018c2ecf20Sopenharmony_ci	int sectors_per_part, num_sectors, k;
53028c2ecf20Sopenharmony_ci	int heads_by_sects, start_sec, end_sec;
53038c2ecf20Sopenharmony_ci
53048c2ecf20Sopenharmony_ci	/* assume partition table already zeroed */
53058c2ecf20Sopenharmony_ci	if ((sdebug_num_parts < 1) || (store_size < 1048576))
53068c2ecf20Sopenharmony_ci		return;
53078c2ecf20Sopenharmony_ci	if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
53088c2ecf20Sopenharmony_ci		sdebug_num_parts = SDEBUG_MAX_PARTS;
53098c2ecf20Sopenharmony_ci		pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
53108c2ecf20Sopenharmony_ci	}
53118c2ecf20Sopenharmony_ci	num_sectors = (int)get_sdebug_capacity();
53128c2ecf20Sopenharmony_ci	sectors_per_part = (num_sectors - sdebug_sectors_per)
53138c2ecf20Sopenharmony_ci			   / sdebug_num_parts;
53148c2ecf20Sopenharmony_ci	heads_by_sects = sdebug_heads * sdebug_sectors_per;
53158c2ecf20Sopenharmony_ci	starts[0] = sdebug_sectors_per;
53168c2ecf20Sopenharmony_ci	max_part_secs = sectors_per_part;
53178c2ecf20Sopenharmony_ci	for (k = 1; k < sdebug_num_parts; ++k) {
53188c2ecf20Sopenharmony_ci		starts[k] = ((k * sectors_per_part) / heads_by_sects)
53198c2ecf20Sopenharmony_ci			    * heads_by_sects;
53208c2ecf20Sopenharmony_ci		if (starts[k] - starts[k - 1] < max_part_secs)
53218c2ecf20Sopenharmony_ci			max_part_secs = starts[k] - starts[k - 1];
53228c2ecf20Sopenharmony_ci	}
53238c2ecf20Sopenharmony_ci	starts[sdebug_num_parts] = num_sectors;
53248c2ecf20Sopenharmony_ci	starts[sdebug_num_parts + 1] = 0;
53258c2ecf20Sopenharmony_ci
53268c2ecf20Sopenharmony_ci	ramp[510] = 0x55;	/* magic partition markings */
53278c2ecf20Sopenharmony_ci	ramp[511] = 0xAA;
53288c2ecf20Sopenharmony_ci	pp = (struct msdos_partition *)(ramp + 0x1be);
53298c2ecf20Sopenharmony_ci	for (k = 0; starts[k + 1]; ++k, ++pp) {
53308c2ecf20Sopenharmony_ci		start_sec = starts[k];
53318c2ecf20Sopenharmony_ci		end_sec = starts[k] + max_part_secs - 1;
53328c2ecf20Sopenharmony_ci		pp->boot_ind = 0;
53338c2ecf20Sopenharmony_ci
53348c2ecf20Sopenharmony_ci		pp->cyl = start_sec / heads_by_sects;
53358c2ecf20Sopenharmony_ci		pp->head = (start_sec - (pp->cyl * heads_by_sects))
53368c2ecf20Sopenharmony_ci			   / sdebug_sectors_per;
53378c2ecf20Sopenharmony_ci		pp->sector = (start_sec % sdebug_sectors_per) + 1;
53388c2ecf20Sopenharmony_ci
53398c2ecf20Sopenharmony_ci		pp->end_cyl = end_sec / heads_by_sects;
53408c2ecf20Sopenharmony_ci		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
53418c2ecf20Sopenharmony_ci			       / sdebug_sectors_per;
53428c2ecf20Sopenharmony_ci		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
53438c2ecf20Sopenharmony_ci
53448c2ecf20Sopenharmony_ci		pp->start_sect = cpu_to_le32(start_sec);
53458c2ecf20Sopenharmony_ci		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
53468c2ecf20Sopenharmony_ci		pp->sys_ind = 0x83;	/* plain Linux partition */
53478c2ecf20Sopenharmony_ci	}
53488c2ecf20Sopenharmony_ci}
53498c2ecf20Sopenharmony_ci
53508c2ecf20Sopenharmony_cistatic void block_unblock_all_queues(bool block)
53518c2ecf20Sopenharmony_ci{
53528c2ecf20Sopenharmony_ci	int j;
53538c2ecf20Sopenharmony_ci	struct sdebug_queue *sqp;
53548c2ecf20Sopenharmony_ci
53558c2ecf20Sopenharmony_ci	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
53568c2ecf20Sopenharmony_ci		atomic_set(&sqp->blocked, (int)block);
53578c2ecf20Sopenharmony_ci}
53588c2ecf20Sopenharmony_ci
53598c2ecf20Sopenharmony_ci/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
53608c2ecf20Sopenharmony_ci * commands will be processed normally before triggers occur.
53618c2ecf20Sopenharmony_ci */
53628c2ecf20Sopenharmony_cistatic void tweak_cmnd_count(void)
53638c2ecf20Sopenharmony_ci{
53648c2ecf20Sopenharmony_ci	int count, modulo;
53658c2ecf20Sopenharmony_ci
53668c2ecf20Sopenharmony_ci	modulo = abs(sdebug_every_nth);
53678c2ecf20Sopenharmony_ci	if (modulo < 2)
53688c2ecf20Sopenharmony_ci		return;
53698c2ecf20Sopenharmony_ci	block_unblock_all_queues(true);
53708c2ecf20Sopenharmony_ci	count = atomic_read(&sdebug_cmnd_count);
53718c2ecf20Sopenharmony_ci	atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
53728c2ecf20Sopenharmony_ci	block_unblock_all_queues(false);
53738c2ecf20Sopenharmony_ci}
53748c2ecf20Sopenharmony_ci
53758c2ecf20Sopenharmony_cistatic void clear_queue_stats(void)
53768c2ecf20Sopenharmony_ci{
53778c2ecf20Sopenharmony_ci	atomic_set(&sdebug_cmnd_count, 0);
53788c2ecf20Sopenharmony_ci	atomic_set(&sdebug_completions, 0);
53798c2ecf20Sopenharmony_ci	atomic_set(&sdebug_miss_cpus, 0);
53808c2ecf20Sopenharmony_ci	atomic_set(&sdebug_a_tsf, 0);
53818c2ecf20Sopenharmony_ci}
53828c2ecf20Sopenharmony_ci
53838c2ecf20Sopenharmony_cistatic bool inject_on_this_cmd(void)
53848c2ecf20Sopenharmony_ci{
53858c2ecf20Sopenharmony_ci	if (sdebug_every_nth == 0)
53868c2ecf20Sopenharmony_ci		return false;
53878c2ecf20Sopenharmony_ci	return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
53888c2ecf20Sopenharmony_ci}
53898c2ecf20Sopenharmony_ci
53908c2ecf20Sopenharmony_ci#define INCLUSIVE_TIMING_MAX_NS 1000000		/* 1 millisecond */
53918c2ecf20Sopenharmony_ci
53928c2ecf20Sopenharmony_ci/* Complete the processing of the thread that queued a SCSI command to this
53938c2ecf20Sopenharmony_ci * driver. It either completes the command by calling cmnd_done() or
53948c2ecf20Sopenharmony_ci * schedules a hr timer or work queue then returns 0. Returns
53958c2ecf20Sopenharmony_ci * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
53968c2ecf20Sopenharmony_ci */
53978c2ecf20Sopenharmony_cistatic int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
53988c2ecf20Sopenharmony_ci			 int scsi_result,
53998c2ecf20Sopenharmony_ci			 int (*pfp)(struct scsi_cmnd *,
54008c2ecf20Sopenharmony_ci				    struct sdebug_dev_info *),
54018c2ecf20Sopenharmony_ci			 int delta_jiff, int ndelay)
54028c2ecf20Sopenharmony_ci{
54038c2ecf20Sopenharmony_ci	bool new_sd_dp;
54048c2ecf20Sopenharmony_ci	bool inject = false;
54058c2ecf20Sopenharmony_ci	int k, num_in_q, qdepth;
54068c2ecf20Sopenharmony_ci	unsigned long iflags;
54078c2ecf20Sopenharmony_ci	u64 ns_from_boot = 0;
54088c2ecf20Sopenharmony_ci	struct sdebug_queue *sqp;
54098c2ecf20Sopenharmony_ci	struct sdebug_queued_cmd *sqcp;
54108c2ecf20Sopenharmony_ci	struct scsi_device *sdp;
54118c2ecf20Sopenharmony_ci	struct sdebug_defer *sd_dp;
54128c2ecf20Sopenharmony_ci
54138c2ecf20Sopenharmony_ci	if (unlikely(devip == NULL)) {
54148c2ecf20Sopenharmony_ci		if (scsi_result == 0)
54158c2ecf20Sopenharmony_ci			scsi_result = DID_NO_CONNECT << 16;
54168c2ecf20Sopenharmony_ci		goto respond_in_thread;
54178c2ecf20Sopenharmony_ci	}
54188c2ecf20Sopenharmony_ci	sdp = cmnd->device;
54198c2ecf20Sopenharmony_ci
54208c2ecf20Sopenharmony_ci	if (delta_jiff == 0)
54218c2ecf20Sopenharmony_ci		goto respond_in_thread;
54228c2ecf20Sopenharmony_ci
54238c2ecf20Sopenharmony_ci	sqp = get_queue(cmnd);
54248c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sqp->qc_lock, iflags);
54258c2ecf20Sopenharmony_ci	if (unlikely(atomic_read(&sqp->blocked))) {
54268c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
54278c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
54288c2ecf20Sopenharmony_ci	}
54298c2ecf20Sopenharmony_ci	num_in_q = atomic_read(&devip->num_in_q);
54308c2ecf20Sopenharmony_ci	qdepth = cmnd->device->queue_depth;
54318c2ecf20Sopenharmony_ci	if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
54328c2ecf20Sopenharmony_ci		if (scsi_result) {
54338c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&sqp->qc_lock, iflags);
54348c2ecf20Sopenharmony_ci			goto respond_in_thread;
54358c2ecf20Sopenharmony_ci		} else
54368c2ecf20Sopenharmony_ci			scsi_result = device_qfull_result;
54378c2ecf20Sopenharmony_ci	} else if (unlikely(sdebug_every_nth &&
54388c2ecf20Sopenharmony_ci			    (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
54398c2ecf20Sopenharmony_ci			    (scsi_result == 0))) {
54408c2ecf20Sopenharmony_ci		if ((num_in_q == (qdepth - 1)) &&
54418c2ecf20Sopenharmony_ci		    (atomic_inc_return(&sdebug_a_tsf) >=
54428c2ecf20Sopenharmony_ci		     abs(sdebug_every_nth))) {
54438c2ecf20Sopenharmony_ci			atomic_set(&sdebug_a_tsf, 0);
54448c2ecf20Sopenharmony_ci			inject = true;
54458c2ecf20Sopenharmony_ci			scsi_result = device_qfull_result;
54468c2ecf20Sopenharmony_ci		}
54478c2ecf20Sopenharmony_ci	}
54488c2ecf20Sopenharmony_ci
54498c2ecf20Sopenharmony_ci	k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
54508c2ecf20Sopenharmony_ci	if (unlikely(k >= sdebug_max_queue)) {
54518c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&sqp->qc_lock, iflags);
54528c2ecf20Sopenharmony_ci		if (scsi_result)
54538c2ecf20Sopenharmony_ci			goto respond_in_thread;
54548c2ecf20Sopenharmony_ci		else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
54558c2ecf20Sopenharmony_ci			scsi_result = device_qfull_result;
54568c2ecf20Sopenharmony_ci		if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
54578c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, sdp,
54588c2ecf20Sopenharmony_ci				    "%s: max_queue=%d exceeded, %s\n",
54598c2ecf20Sopenharmony_ci				    __func__, sdebug_max_queue,
54608c2ecf20Sopenharmony_ci				    (scsi_result ?  "status: TASK SET FULL" :
54618c2ecf20Sopenharmony_ci						    "report: host busy"));
54628c2ecf20Sopenharmony_ci		if (scsi_result)
54638c2ecf20Sopenharmony_ci			goto respond_in_thread;
54648c2ecf20Sopenharmony_ci		else
54658c2ecf20Sopenharmony_ci			return SCSI_MLQUEUE_HOST_BUSY;
54668c2ecf20Sopenharmony_ci	}
54678c2ecf20Sopenharmony_ci	set_bit(k, sqp->in_use_bm);
54688c2ecf20Sopenharmony_ci	atomic_inc(&devip->num_in_q);
54698c2ecf20Sopenharmony_ci	sqcp = &sqp->qc_arr[k];
54708c2ecf20Sopenharmony_ci	sqcp->a_cmnd = cmnd;
54718c2ecf20Sopenharmony_ci	cmnd->host_scribble = (unsigned char *)sqcp;
54728c2ecf20Sopenharmony_ci	sd_dp = sqcp->sd_dp;
54738c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sqp->qc_lock, iflags);
54748c2ecf20Sopenharmony_ci	if (!sd_dp) {
54758c2ecf20Sopenharmony_ci		sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
54768c2ecf20Sopenharmony_ci		if (!sd_dp) {
54778c2ecf20Sopenharmony_ci			atomic_dec(&devip->num_in_q);
54788c2ecf20Sopenharmony_ci			clear_bit(k, sqp->in_use_bm);
54798c2ecf20Sopenharmony_ci			return SCSI_MLQUEUE_HOST_BUSY;
54808c2ecf20Sopenharmony_ci		}
54818c2ecf20Sopenharmony_ci		new_sd_dp = true;
54828c2ecf20Sopenharmony_ci	} else {
54838c2ecf20Sopenharmony_ci		new_sd_dp = false;
54848c2ecf20Sopenharmony_ci	}
54858c2ecf20Sopenharmony_ci
54868c2ecf20Sopenharmony_ci	/* Set the hostwide tag */
54878c2ecf20Sopenharmony_ci	if (sdebug_host_max_queue)
54888c2ecf20Sopenharmony_ci		sd_dp->hc_idx = get_tag(cmnd);
54898c2ecf20Sopenharmony_ci
54908c2ecf20Sopenharmony_ci	if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS)
54918c2ecf20Sopenharmony_ci		ns_from_boot = ktime_get_boottime_ns();
54928c2ecf20Sopenharmony_ci
54938c2ecf20Sopenharmony_ci	/* one of the resp_*() response functions is called here */
54948c2ecf20Sopenharmony_ci	cmnd->result = pfp ? pfp(cmnd, devip) : 0;
54958c2ecf20Sopenharmony_ci	if (cmnd->result & SDEG_RES_IMMED_MASK) {
54968c2ecf20Sopenharmony_ci		cmnd->result &= ~SDEG_RES_IMMED_MASK;
54978c2ecf20Sopenharmony_ci		delta_jiff = ndelay = 0;
54988c2ecf20Sopenharmony_ci	}
54998c2ecf20Sopenharmony_ci	if (cmnd->result == 0 && scsi_result != 0)
55008c2ecf20Sopenharmony_ci		cmnd->result = scsi_result;
55018c2ecf20Sopenharmony_ci	if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) {
55028c2ecf20Sopenharmony_ci		if (atomic_read(&sdeb_inject_pending)) {
55038c2ecf20Sopenharmony_ci			mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO);
55048c2ecf20Sopenharmony_ci			atomic_set(&sdeb_inject_pending, 0);
55058c2ecf20Sopenharmony_ci			cmnd->result = check_condition_result;
55068c2ecf20Sopenharmony_ci		}
55078c2ecf20Sopenharmony_ci	}
55088c2ecf20Sopenharmony_ci
55098c2ecf20Sopenharmony_ci	if (unlikely(sdebug_verbose && cmnd->result))
55108c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
55118c2ecf20Sopenharmony_ci			    __func__, cmnd->result);
55128c2ecf20Sopenharmony_ci
55138c2ecf20Sopenharmony_ci	if (delta_jiff > 0 || ndelay > 0) {
55148c2ecf20Sopenharmony_ci		ktime_t kt;
55158c2ecf20Sopenharmony_ci
55168c2ecf20Sopenharmony_ci		if (delta_jiff > 0) {
55178c2ecf20Sopenharmony_ci			u64 ns = jiffies_to_nsecs(delta_jiff);
55188c2ecf20Sopenharmony_ci
55198c2ecf20Sopenharmony_ci			if (sdebug_random && ns < U32_MAX) {
55208c2ecf20Sopenharmony_ci				ns = prandom_u32_max((u32)ns);
55218c2ecf20Sopenharmony_ci			} else if (sdebug_random) {
55228c2ecf20Sopenharmony_ci				ns >>= 12;	/* scale to 4 usec precision */
55238c2ecf20Sopenharmony_ci				if (ns < U32_MAX)	/* over 4 hours max */
55248c2ecf20Sopenharmony_ci					ns = prandom_u32_max((u32)ns);
55258c2ecf20Sopenharmony_ci				ns <<= 12;
55268c2ecf20Sopenharmony_ci			}
55278c2ecf20Sopenharmony_ci			kt = ns_to_ktime(ns);
55288c2ecf20Sopenharmony_ci		} else {	/* ndelay has a 4.2 second max */
55298c2ecf20Sopenharmony_ci			kt = sdebug_random ? prandom_u32_max((u32)ndelay) :
55308c2ecf20Sopenharmony_ci					     (u32)ndelay;
55318c2ecf20Sopenharmony_ci			if (ndelay < INCLUSIVE_TIMING_MAX_NS) {
55328c2ecf20Sopenharmony_ci				u64 d = ktime_get_boottime_ns() - ns_from_boot;
55338c2ecf20Sopenharmony_ci
55348c2ecf20Sopenharmony_ci				if (kt <= d) {	/* elapsed duration >= kt */
55358c2ecf20Sopenharmony_ci					spin_lock_irqsave(&sqp->qc_lock, iflags);
55368c2ecf20Sopenharmony_ci					sqcp->a_cmnd = NULL;
55378c2ecf20Sopenharmony_ci					atomic_dec(&devip->num_in_q);
55388c2ecf20Sopenharmony_ci					clear_bit(k, sqp->in_use_bm);
55398c2ecf20Sopenharmony_ci					spin_unlock_irqrestore(&sqp->qc_lock, iflags);
55408c2ecf20Sopenharmony_ci					if (new_sd_dp)
55418c2ecf20Sopenharmony_ci						kfree(sd_dp);
55428c2ecf20Sopenharmony_ci					/* call scsi_done() from this thread */
55438c2ecf20Sopenharmony_ci					cmnd->scsi_done(cmnd);
55448c2ecf20Sopenharmony_ci					return 0;
55458c2ecf20Sopenharmony_ci				}
55468c2ecf20Sopenharmony_ci				/* otherwise reduce kt by elapsed time */
55478c2ecf20Sopenharmony_ci				kt -= d;
55488c2ecf20Sopenharmony_ci			}
55498c2ecf20Sopenharmony_ci		}
55508c2ecf20Sopenharmony_ci		if (!sd_dp->init_hrt) {
55518c2ecf20Sopenharmony_ci			sd_dp->init_hrt = true;
55528c2ecf20Sopenharmony_ci			sqcp->sd_dp = sd_dp;
55538c2ecf20Sopenharmony_ci			hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
55548c2ecf20Sopenharmony_ci				     HRTIMER_MODE_REL_PINNED);
55558c2ecf20Sopenharmony_ci			sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
55568c2ecf20Sopenharmony_ci			sd_dp->sqa_idx = sqp - sdebug_q_arr;
55578c2ecf20Sopenharmony_ci			sd_dp->qc_idx = k;
55588c2ecf20Sopenharmony_ci		}
55598c2ecf20Sopenharmony_ci		if (sdebug_statistics)
55608c2ecf20Sopenharmony_ci			sd_dp->issuing_cpu = raw_smp_processor_id();
55618c2ecf20Sopenharmony_ci		sd_dp->defer_t = SDEB_DEFER_HRT;
55628c2ecf20Sopenharmony_ci		/* schedule the invocation of scsi_done() for a later time */
55638c2ecf20Sopenharmony_ci		hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
55648c2ecf20Sopenharmony_ci	} else {	/* jdelay < 0, use work queue */
55658c2ecf20Sopenharmony_ci		if (!sd_dp->init_wq) {
55668c2ecf20Sopenharmony_ci			sd_dp->init_wq = true;
55678c2ecf20Sopenharmony_ci			sqcp->sd_dp = sd_dp;
55688c2ecf20Sopenharmony_ci			sd_dp->sqa_idx = sqp - sdebug_q_arr;
55698c2ecf20Sopenharmony_ci			sd_dp->qc_idx = k;
55708c2ecf20Sopenharmony_ci			INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
55718c2ecf20Sopenharmony_ci		}
55728c2ecf20Sopenharmony_ci		if (sdebug_statistics)
55738c2ecf20Sopenharmony_ci			sd_dp->issuing_cpu = raw_smp_processor_id();
55748c2ecf20Sopenharmony_ci		sd_dp->defer_t = SDEB_DEFER_WQ;
55758c2ecf20Sopenharmony_ci		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
55768c2ecf20Sopenharmony_ci			     atomic_read(&sdeb_inject_pending)))
55778c2ecf20Sopenharmony_ci			sd_dp->aborted = true;
55788c2ecf20Sopenharmony_ci		schedule_work(&sd_dp->ew.work);
55798c2ecf20Sopenharmony_ci		if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) &&
55808c2ecf20Sopenharmony_ci			     atomic_read(&sdeb_inject_pending))) {
55818c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", cmnd->request->tag);
55828c2ecf20Sopenharmony_ci			blk_abort_request(cmnd->request);
55838c2ecf20Sopenharmony_ci			atomic_set(&sdeb_inject_pending, 0);
55848c2ecf20Sopenharmony_ci		}
55858c2ecf20Sopenharmony_ci	}
55868c2ecf20Sopenharmony_ci	if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result))
55878c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__,
55888c2ecf20Sopenharmony_ci			    num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL");
55898c2ecf20Sopenharmony_ci	return 0;
55908c2ecf20Sopenharmony_ci
55918c2ecf20Sopenharmony_cirespond_in_thread:	/* call back to mid-layer using invocation thread */
55928c2ecf20Sopenharmony_ci	cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
55938c2ecf20Sopenharmony_ci	cmnd->result &= ~SDEG_RES_IMMED_MASK;
55948c2ecf20Sopenharmony_ci	if (cmnd->result == 0 && scsi_result != 0)
55958c2ecf20Sopenharmony_ci		cmnd->result = scsi_result;
55968c2ecf20Sopenharmony_ci	cmnd->scsi_done(cmnd);
55978c2ecf20Sopenharmony_ci	return 0;
55988c2ecf20Sopenharmony_ci}
55998c2ecf20Sopenharmony_ci
56008c2ecf20Sopenharmony_ci/* Note: The following macros create attribute files in the
56018c2ecf20Sopenharmony_ci   /sys/module/scsi_debug/parameters directory. Unfortunately this
56028c2ecf20Sopenharmony_ci   driver is unaware of a change and cannot trigger auxiliary actions
56038c2ecf20Sopenharmony_ci   as it can when the corresponding attribute in the
56048c2ecf20Sopenharmony_ci   /sys/bus/pseudo/drivers/scsi_debug directory is changed.
56058c2ecf20Sopenharmony_ci */
56068c2ecf20Sopenharmony_cimodule_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
56078c2ecf20Sopenharmony_cimodule_param_named(ato, sdebug_ato, int, S_IRUGO);
56088c2ecf20Sopenharmony_cimodule_param_named(cdb_len, sdebug_cdb_len, int, 0644);
56098c2ecf20Sopenharmony_cimodule_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
56108c2ecf20Sopenharmony_cimodule_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
56118c2ecf20Sopenharmony_cimodule_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
56128c2ecf20Sopenharmony_cimodule_param_named(dif, sdebug_dif, int, S_IRUGO);
56138c2ecf20Sopenharmony_cimodule_param_named(dix, sdebug_dix, int, S_IRUGO);
56148c2ecf20Sopenharmony_cimodule_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
56158c2ecf20Sopenharmony_cimodule_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
56168c2ecf20Sopenharmony_cimodule_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
56178c2ecf20Sopenharmony_cimodule_param_named(guard, sdebug_guard, uint, S_IRUGO);
56188c2ecf20Sopenharmony_cimodule_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
56198c2ecf20Sopenharmony_cimodule_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO);
56208c2ecf20Sopenharmony_cimodule_param_string(inq_product, sdebug_inq_product_id,
56218c2ecf20Sopenharmony_ci		    sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR);
56228c2ecf20Sopenharmony_cimodule_param_string(inq_rev, sdebug_inq_product_rev,
56238c2ecf20Sopenharmony_ci		    sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR);
56248c2ecf20Sopenharmony_cimodule_param_string(inq_vendor, sdebug_inq_vendor_id,
56258c2ecf20Sopenharmony_ci		    sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR);
56268c2ecf20Sopenharmony_cimodule_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
56278c2ecf20Sopenharmony_cimodule_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
56288c2ecf20Sopenharmony_cimodule_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
56298c2ecf20Sopenharmony_cimodule_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
56308c2ecf20Sopenharmony_cimodule_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
56318c2ecf20Sopenharmony_cimodule_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR);
56328c2ecf20Sopenharmony_cimodule_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
56338c2ecf20Sopenharmony_cimodule_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
56348c2ecf20Sopenharmony_cimodule_param_named(medium_error_count, sdebug_medium_error_count, int,
56358c2ecf20Sopenharmony_ci		   S_IRUGO | S_IWUSR);
56368c2ecf20Sopenharmony_cimodule_param_named(medium_error_start, sdebug_medium_error_start, int,
56378c2ecf20Sopenharmony_ci		   S_IRUGO | S_IWUSR);
56388c2ecf20Sopenharmony_cimodule_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
56398c2ecf20Sopenharmony_cimodule_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
56408c2ecf20Sopenharmony_cimodule_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
56418c2ecf20Sopenharmony_cimodule_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
56428c2ecf20Sopenharmony_cimodule_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
56438c2ecf20Sopenharmony_cimodule_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
56448c2ecf20Sopenharmony_cimodule_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
56458c2ecf20Sopenharmony_cimodule_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
56468c2ecf20Sopenharmony_cimodule_param_named(per_host_store, sdebug_per_host_store, bool,
56478c2ecf20Sopenharmony_ci		   S_IRUGO | S_IWUSR);
56488c2ecf20Sopenharmony_cimodule_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
56498c2ecf20Sopenharmony_cimodule_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
56508c2ecf20Sopenharmony_cimodule_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR);
56518c2ecf20Sopenharmony_cimodule_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
56528c2ecf20Sopenharmony_cimodule_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
56538c2ecf20Sopenharmony_cimodule_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
56548c2ecf20Sopenharmony_cimodule_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
56558c2ecf20Sopenharmony_cimodule_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
56568c2ecf20Sopenharmony_cimodule_param_named(submit_queues, submit_queues, int, S_IRUGO);
56578c2ecf20Sopenharmony_cimodule_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO);
56588c2ecf20Sopenharmony_cimodule_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
56598c2ecf20Sopenharmony_cimodule_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
56608c2ecf20Sopenharmony_cimodule_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
56618c2ecf20Sopenharmony_cimodule_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
56628c2ecf20Sopenharmony_cimodule_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
56638c2ecf20Sopenharmony_cimodule_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
56648c2ecf20Sopenharmony_cimodule_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
56658c2ecf20Sopenharmony_ci		   S_IRUGO | S_IWUSR);
56668c2ecf20Sopenharmony_cimodule_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
56678c2ecf20Sopenharmony_cimodule_param_named(write_same_length, sdebug_write_same_length, int,
56688c2ecf20Sopenharmony_ci		   S_IRUGO | S_IWUSR);
56698c2ecf20Sopenharmony_cimodule_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
56708c2ecf20Sopenharmony_cimodule_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
56718c2ecf20Sopenharmony_cimodule_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
56728c2ecf20Sopenharmony_cimodule_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
56738c2ecf20Sopenharmony_ci
56748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
56758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SCSI debug adapter driver");
56768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
56778c2ecf20Sopenharmony_ciMODULE_VERSION(SDEBUG_VERSION);
56788c2ecf20Sopenharmony_ci
56798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)");
56808c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
56818c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
56828c2ecf20Sopenharmony_ciMODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
56838c2ecf20Sopenharmony_ciMODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
56848c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
56858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
56868c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
56878c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
56888c2ecf20Sopenharmony_ciMODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
56898c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
56908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
56918c2ecf20Sopenharmony_ciMODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
56928c2ecf20Sopenharmony_ciMODULE_PARM_DESC(host_max_queue,
56938c2ecf20Sopenharmony_ci		 "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])");
56948c2ecf20Sopenharmony_ciMODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
56958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
56968c2ecf20Sopenharmony_ci		 SDEBUG_VERSION "\")");
56978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
56988c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lbprz,
56998c2ecf20Sopenharmony_ci		 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
57008c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
57018c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
57028c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
57038c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
57048c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
57058c2ecf20Sopenharmony_ciMODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method");
57068c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
57078c2ecf20Sopenharmony_ciMODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
57088c2ecf20Sopenharmony_ciMODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
57098c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
57108c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
57118c2ecf20Sopenharmony_ciMODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
57128c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
57138c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
57148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
57158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
57168c2ecf20Sopenharmony_ciMODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
57178c2ecf20Sopenharmony_ciMODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)");
57188c2ecf20Sopenharmony_ciMODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
57198c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
57208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns");
57218c2ecf20Sopenharmony_ciMODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
57228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
57238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
57248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
57258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
57268c2ecf20Sopenharmony_ciMODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
57278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)");
57288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
57298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
57308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
57318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
57328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(uuid_ctl,
57338c2ecf20Sopenharmony_ci		 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
57348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
57358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
57368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(wp, "Write Protect (def=0)");
57378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
57388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
57398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
57408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
57418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
57428c2ecf20Sopenharmony_ci
57438c2ecf20Sopenharmony_ci#define SDEBUG_INFO_LEN 256
57448c2ecf20Sopenharmony_cistatic char sdebug_info[SDEBUG_INFO_LEN];
57458c2ecf20Sopenharmony_ci
57468c2ecf20Sopenharmony_cistatic const char *scsi_debug_info(struct Scsi_Host *shp)
57478c2ecf20Sopenharmony_ci{
57488c2ecf20Sopenharmony_ci	int k;
57498c2ecf20Sopenharmony_ci
57508c2ecf20Sopenharmony_ci	k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
57518c2ecf20Sopenharmony_ci		      my_name, SDEBUG_VERSION, sdebug_version_date);
57528c2ecf20Sopenharmony_ci	if (k >= (SDEBUG_INFO_LEN - 1))
57538c2ecf20Sopenharmony_ci		return sdebug_info;
57548c2ecf20Sopenharmony_ci	scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
57558c2ecf20Sopenharmony_ci		  "  dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
57568c2ecf20Sopenharmony_ci		  sdebug_dev_size_mb, sdebug_opts, submit_queues,
57578c2ecf20Sopenharmony_ci		  "statistics", (int)sdebug_statistics);
57588c2ecf20Sopenharmony_ci	return sdebug_info;
57598c2ecf20Sopenharmony_ci}
57608c2ecf20Sopenharmony_ci
57618c2ecf20Sopenharmony_ci/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
57628c2ecf20Sopenharmony_cistatic int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
57638c2ecf20Sopenharmony_ci				 int length)
57648c2ecf20Sopenharmony_ci{
57658c2ecf20Sopenharmony_ci	char arr[16];
57668c2ecf20Sopenharmony_ci	int opts;
57678c2ecf20Sopenharmony_ci	int minLen = length > 15 ? 15 : length;
57688c2ecf20Sopenharmony_ci
57698c2ecf20Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
57708c2ecf20Sopenharmony_ci		return -EACCES;
57718c2ecf20Sopenharmony_ci	memcpy(arr, buffer, minLen);
57728c2ecf20Sopenharmony_ci	arr[minLen] = '\0';
57738c2ecf20Sopenharmony_ci	if (1 != sscanf(arr, "%d", &opts))
57748c2ecf20Sopenharmony_ci		return -EINVAL;
57758c2ecf20Sopenharmony_ci	sdebug_opts = opts;
57768c2ecf20Sopenharmony_ci	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
57778c2ecf20Sopenharmony_ci	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
57788c2ecf20Sopenharmony_ci	if (sdebug_every_nth != 0)
57798c2ecf20Sopenharmony_ci		tweak_cmnd_count();
57808c2ecf20Sopenharmony_ci	return length;
57818c2ecf20Sopenharmony_ci}
57828c2ecf20Sopenharmony_ci
57838c2ecf20Sopenharmony_ci/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
57848c2ecf20Sopenharmony_ci * same for each scsi_debug host (if more than one). Some of the counters
57858c2ecf20Sopenharmony_ci * output are not atomics so might be inaccurate in a busy system. */
57868c2ecf20Sopenharmony_cistatic int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
57878c2ecf20Sopenharmony_ci{
57888c2ecf20Sopenharmony_ci	int f, j, l;
57898c2ecf20Sopenharmony_ci	struct sdebug_queue *sqp;
57908c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdhp;
57918c2ecf20Sopenharmony_ci
57928c2ecf20Sopenharmony_ci	seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
57938c2ecf20Sopenharmony_ci		   SDEBUG_VERSION, sdebug_version_date);
57948c2ecf20Sopenharmony_ci	seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
57958c2ecf20Sopenharmony_ci		   sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
57968c2ecf20Sopenharmony_ci		   sdebug_opts, sdebug_every_nth);
57978c2ecf20Sopenharmony_ci	seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
57988c2ecf20Sopenharmony_ci		   sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
57998c2ecf20Sopenharmony_ci		   sdebug_sector_size, "bytes");
58008c2ecf20Sopenharmony_ci	seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
58018c2ecf20Sopenharmony_ci		   sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
58028c2ecf20Sopenharmony_ci		   num_aborts);
58038c2ecf20Sopenharmony_ci	seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
58048c2ecf20Sopenharmony_ci		   num_dev_resets, num_target_resets, num_bus_resets,
58058c2ecf20Sopenharmony_ci		   num_host_resets);
58068c2ecf20Sopenharmony_ci	seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
58078c2ecf20Sopenharmony_ci		   dix_reads, dix_writes, dif_errors);
58088c2ecf20Sopenharmony_ci	seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
58098c2ecf20Sopenharmony_ci		   sdebug_statistics);
58108c2ecf20Sopenharmony_ci	seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
58118c2ecf20Sopenharmony_ci		   atomic_read(&sdebug_cmnd_count),
58128c2ecf20Sopenharmony_ci		   atomic_read(&sdebug_completions),
58138c2ecf20Sopenharmony_ci		   "miss_cpus", atomic_read(&sdebug_miss_cpus),
58148c2ecf20Sopenharmony_ci		   atomic_read(&sdebug_a_tsf));
58158c2ecf20Sopenharmony_ci
58168c2ecf20Sopenharmony_ci	seq_printf(m, "submit_queues=%d\n", submit_queues);
58178c2ecf20Sopenharmony_ci	for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
58188c2ecf20Sopenharmony_ci		seq_printf(m, "  queue %d:\n", j);
58198c2ecf20Sopenharmony_ci		f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
58208c2ecf20Sopenharmony_ci		if (f != sdebug_max_queue) {
58218c2ecf20Sopenharmony_ci			l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
58228c2ecf20Sopenharmony_ci			seq_printf(m, "    in_use_bm BUSY: %s: %d,%d\n",
58238c2ecf20Sopenharmony_ci				   "first,last bits", f, l);
58248c2ecf20Sopenharmony_ci		}
58258c2ecf20Sopenharmony_ci	}
58268c2ecf20Sopenharmony_ci
58278c2ecf20Sopenharmony_ci	seq_printf(m, "this host_no=%d\n", host->host_no);
58288c2ecf20Sopenharmony_ci	if (!xa_empty(per_store_ap)) {
58298c2ecf20Sopenharmony_ci		bool niu;
58308c2ecf20Sopenharmony_ci		int idx;
58318c2ecf20Sopenharmony_ci		unsigned long l_idx;
58328c2ecf20Sopenharmony_ci		struct sdeb_store_info *sip;
58338c2ecf20Sopenharmony_ci
58348c2ecf20Sopenharmony_ci		seq_puts(m, "\nhost list:\n");
58358c2ecf20Sopenharmony_ci		j = 0;
58368c2ecf20Sopenharmony_ci		list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
58378c2ecf20Sopenharmony_ci			idx = sdhp->si_idx;
58388c2ecf20Sopenharmony_ci			seq_printf(m, "  %d: host_no=%d, si_idx=%d\n", j,
58398c2ecf20Sopenharmony_ci				   sdhp->shost->host_no, idx);
58408c2ecf20Sopenharmony_ci			++j;
58418c2ecf20Sopenharmony_ci		}
58428c2ecf20Sopenharmony_ci		seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n",
58438c2ecf20Sopenharmony_ci			   sdeb_most_recent_idx);
58448c2ecf20Sopenharmony_ci		j = 0;
58458c2ecf20Sopenharmony_ci		xa_for_each(per_store_ap, l_idx, sip) {
58468c2ecf20Sopenharmony_ci			niu = xa_get_mark(per_store_ap, l_idx,
58478c2ecf20Sopenharmony_ci					  SDEB_XA_NOT_IN_USE);
58488c2ecf20Sopenharmony_ci			idx = (int)l_idx;
58498c2ecf20Sopenharmony_ci			seq_printf(m, "  %d: idx=%d%s\n", j, idx,
58508c2ecf20Sopenharmony_ci				   (niu ? "  not_in_use" : ""));
58518c2ecf20Sopenharmony_ci			++j;
58528c2ecf20Sopenharmony_ci		}
58538c2ecf20Sopenharmony_ci	}
58548c2ecf20Sopenharmony_ci	return 0;
58558c2ecf20Sopenharmony_ci}
58568c2ecf20Sopenharmony_ci
58578c2ecf20Sopenharmony_cistatic ssize_t delay_show(struct device_driver *ddp, char *buf)
58588c2ecf20Sopenharmony_ci{
58598c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
58608c2ecf20Sopenharmony_ci}
58618c2ecf20Sopenharmony_ci/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
58628c2ecf20Sopenharmony_ci * of delay is jiffies.
58638c2ecf20Sopenharmony_ci */
58648c2ecf20Sopenharmony_cistatic ssize_t delay_store(struct device_driver *ddp, const char *buf,
58658c2ecf20Sopenharmony_ci			   size_t count)
58668c2ecf20Sopenharmony_ci{
58678c2ecf20Sopenharmony_ci	int jdelay, res;
58688c2ecf20Sopenharmony_ci
58698c2ecf20Sopenharmony_ci	if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
58708c2ecf20Sopenharmony_ci		res = count;
58718c2ecf20Sopenharmony_ci		if (sdebug_jdelay != jdelay) {
58728c2ecf20Sopenharmony_ci			int j, k;
58738c2ecf20Sopenharmony_ci			struct sdebug_queue *sqp;
58748c2ecf20Sopenharmony_ci
58758c2ecf20Sopenharmony_ci			block_unblock_all_queues(true);
58768c2ecf20Sopenharmony_ci			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
58778c2ecf20Sopenharmony_ci			     ++j, ++sqp) {
58788c2ecf20Sopenharmony_ci				k = find_first_bit(sqp->in_use_bm,
58798c2ecf20Sopenharmony_ci						   sdebug_max_queue);
58808c2ecf20Sopenharmony_ci				if (k != sdebug_max_queue) {
58818c2ecf20Sopenharmony_ci					res = -EBUSY;   /* queued commands */
58828c2ecf20Sopenharmony_ci					break;
58838c2ecf20Sopenharmony_ci				}
58848c2ecf20Sopenharmony_ci			}
58858c2ecf20Sopenharmony_ci			if (res > 0) {
58868c2ecf20Sopenharmony_ci				sdebug_jdelay = jdelay;
58878c2ecf20Sopenharmony_ci				sdebug_ndelay = 0;
58888c2ecf20Sopenharmony_ci			}
58898c2ecf20Sopenharmony_ci			block_unblock_all_queues(false);
58908c2ecf20Sopenharmony_ci		}
58918c2ecf20Sopenharmony_ci		return res;
58928c2ecf20Sopenharmony_ci	}
58938c2ecf20Sopenharmony_ci	return -EINVAL;
58948c2ecf20Sopenharmony_ci}
58958c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(delay);
58968c2ecf20Sopenharmony_ci
58978c2ecf20Sopenharmony_cistatic ssize_t ndelay_show(struct device_driver *ddp, char *buf)
58988c2ecf20Sopenharmony_ci{
58998c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
59008c2ecf20Sopenharmony_ci}
59018c2ecf20Sopenharmony_ci/* Returns -EBUSY if ndelay is being changed and commands are queued */
59028c2ecf20Sopenharmony_ci/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
59038c2ecf20Sopenharmony_cistatic ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
59048c2ecf20Sopenharmony_ci			    size_t count)
59058c2ecf20Sopenharmony_ci{
59068c2ecf20Sopenharmony_ci	int ndelay, res;
59078c2ecf20Sopenharmony_ci
59088c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
59098c2ecf20Sopenharmony_ci	    (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
59108c2ecf20Sopenharmony_ci		res = count;
59118c2ecf20Sopenharmony_ci		if (sdebug_ndelay != ndelay) {
59128c2ecf20Sopenharmony_ci			int j, k;
59138c2ecf20Sopenharmony_ci			struct sdebug_queue *sqp;
59148c2ecf20Sopenharmony_ci
59158c2ecf20Sopenharmony_ci			block_unblock_all_queues(true);
59168c2ecf20Sopenharmony_ci			for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
59178c2ecf20Sopenharmony_ci			     ++j, ++sqp) {
59188c2ecf20Sopenharmony_ci				k = find_first_bit(sqp->in_use_bm,
59198c2ecf20Sopenharmony_ci						   sdebug_max_queue);
59208c2ecf20Sopenharmony_ci				if (k != sdebug_max_queue) {
59218c2ecf20Sopenharmony_ci					res = -EBUSY;   /* queued commands */
59228c2ecf20Sopenharmony_ci					break;
59238c2ecf20Sopenharmony_ci				}
59248c2ecf20Sopenharmony_ci			}
59258c2ecf20Sopenharmony_ci			if (res > 0) {
59268c2ecf20Sopenharmony_ci				sdebug_ndelay = ndelay;
59278c2ecf20Sopenharmony_ci				sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
59288c2ecf20Sopenharmony_ci							: DEF_JDELAY;
59298c2ecf20Sopenharmony_ci			}
59308c2ecf20Sopenharmony_ci			block_unblock_all_queues(false);
59318c2ecf20Sopenharmony_ci		}
59328c2ecf20Sopenharmony_ci		return res;
59338c2ecf20Sopenharmony_ci	}
59348c2ecf20Sopenharmony_ci	return -EINVAL;
59358c2ecf20Sopenharmony_ci}
59368c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(ndelay);
59378c2ecf20Sopenharmony_ci
59388c2ecf20Sopenharmony_cistatic ssize_t opts_show(struct device_driver *ddp, char *buf)
59398c2ecf20Sopenharmony_ci{
59408c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
59418c2ecf20Sopenharmony_ci}
59428c2ecf20Sopenharmony_ci
59438c2ecf20Sopenharmony_cistatic ssize_t opts_store(struct device_driver *ddp, const char *buf,
59448c2ecf20Sopenharmony_ci			  size_t count)
59458c2ecf20Sopenharmony_ci{
59468c2ecf20Sopenharmony_ci	int opts;
59478c2ecf20Sopenharmony_ci	char work[20];
59488c2ecf20Sopenharmony_ci
59498c2ecf20Sopenharmony_ci	if (sscanf(buf, "%10s", work) == 1) {
59508c2ecf20Sopenharmony_ci		if (strncasecmp(work, "0x", 2) == 0) {
59518c2ecf20Sopenharmony_ci			if (kstrtoint(work + 2, 16, &opts) == 0)
59528c2ecf20Sopenharmony_ci				goto opts_done;
59538c2ecf20Sopenharmony_ci		} else {
59548c2ecf20Sopenharmony_ci			if (kstrtoint(work, 10, &opts) == 0)
59558c2ecf20Sopenharmony_ci				goto opts_done;
59568c2ecf20Sopenharmony_ci		}
59578c2ecf20Sopenharmony_ci	}
59588c2ecf20Sopenharmony_ci	return -EINVAL;
59598c2ecf20Sopenharmony_ciopts_done:
59608c2ecf20Sopenharmony_ci	sdebug_opts = opts;
59618c2ecf20Sopenharmony_ci	sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
59628c2ecf20Sopenharmony_ci	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
59638c2ecf20Sopenharmony_ci	tweak_cmnd_count();
59648c2ecf20Sopenharmony_ci	return count;
59658c2ecf20Sopenharmony_ci}
59668c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(opts);
59678c2ecf20Sopenharmony_ci
59688c2ecf20Sopenharmony_cistatic ssize_t ptype_show(struct device_driver *ddp, char *buf)
59698c2ecf20Sopenharmony_ci{
59708c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
59718c2ecf20Sopenharmony_ci}
59728c2ecf20Sopenharmony_cistatic ssize_t ptype_store(struct device_driver *ddp, const char *buf,
59738c2ecf20Sopenharmony_ci			   size_t count)
59748c2ecf20Sopenharmony_ci{
59758c2ecf20Sopenharmony_ci	int n;
59768c2ecf20Sopenharmony_ci
59778c2ecf20Sopenharmony_ci	/* Cannot change from or to TYPE_ZBC with sysfs */
59788c2ecf20Sopenharmony_ci	if (sdebug_ptype == TYPE_ZBC)
59798c2ecf20Sopenharmony_ci		return -EINVAL;
59808c2ecf20Sopenharmony_ci
59818c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
59828c2ecf20Sopenharmony_ci		if (n == TYPE_ZBC)
59838c2ecf20Sopenharmony_ci			return -EINVAL;
59848c2ecf20Sopenharmony_ci		sdebug_ptype = n;
59858c2ecf20Sopenharmony_ci		return count;
59868c2ecf20Sopenharmony_ci	}
59878c2ecf20Sopenharmony_ci	return -EINVAL;
59888c2ecf20Sopenharmony_ci}
59898c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(ptype);
59908c2ecf20Sopenharmony_ci
59918c2ecf20Sopenharmony_cistatic ssize_t dsense_show(struct device_driver *ddp, char *buf)
59928c2ecf20Sopenharmony_ci{
59938c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
59948c2ecf20Sopenharmony_ci}
59958c2ecf20Sopenharmony_cistatic ssize_t dsense_store(struct device_driver *ddp, const char *buf,
59968c2ecf20Sopenharmony_ci			    size_t count)
59978c2ecf20Sopenharmony_ci{
59988c2ecf20Sopenharmony_ci	int n;
59998c2ecf20Sopenharmony_ci
60008c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
60018c2ecf20Sopenharmony_ci		sdebug_dsense = n;
60028c2ecf20Sopenharmony_ci		return count;
60038c2ecf20Sopenharmony_ci	}
60048c2ecf20Sopenharmony_ci	return -EINVAL;
60058c2ecf20Sopenharmony_ci}
60068c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(dsense);
60078c2ecf20Sopenharmony_ci
60088c2ecf20Sopenharmony_cistatic ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
60098c2ecf20Sopenharmony_ci{
60108c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
60118c2ecf20Sopenharmony_ci}
60128c2ecf20Sopenharmony_cistatic ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
60138c2ecf20Sopenharmony_ci			     size_t count)
60148c2ecf20Sopenharmony_ci{
60158c2ecf20Sopenharmony_ci	int n, idx;
60168c2ecf20Sopenharmony_ci
60178c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
60188c2ecf20Sopenharmony_ci		bool want_store = (n == 0);
60198c2ecf20Sopenharmony_ci		struct sdebug_host_info *sdhp;
60208c2ecf20Sopenharmony_ci
60218c2ecf20Sopenharmony_ci		n = (n > 0);
60228c2ecf20Sopenharmony_ci		sdebug_fake_rw = (sdebug_fake_rw > 0);
60238c2ecf20Sopenharmony_ci		if (sdebug_fake_rw == n)
60248c2ecf20Sopenharmony_ci			return count;	/* not transitioning so do nothing */
60258c2ecf20Sopenharmony_ci
60268c2ecf20Sopenharmony_ci		if (want_store) {	/* 1 --> 0 transition, set up store */
60278c2ecf20Sopenharmony_ci			if (sdeb_first_idx < 0) {
60288c2ecf20Sopenharmony_ci				idx = sdebug_add_store();
60298c2ecf20Sopenharmony_ci				if (idx < 0)
60308c2ecf20Sopenharmony_ci					return idx;
60318c2ecf20Sopenharmony_ci			} else {
60328c2ecf20Sopenharmony_ci				idx = sdeb_first_idx;
60338c2ecf20Sopenharmony_ci				xa_clear_mark(per_store_ap, idx,
60348c2ecf20Sopenharmony_ci					      SDEB_XA_NOT_IN_USE);
60358c2ecf20Sopenharmony_ci			}
60368c2ecf20Sopenharmony_ci			/* make all hosts use same store */
60378c2ecf20Sopenharmony_ci			list_for_each_entry(sdhp, &sdebug_host_list,
60388c2ecf20Sopenharmony_ci					    host_list) {
60398c2ecf20Sopenharmony_ci				if (sdhp->si_idx != idx) {
60408c2ecf20Sopenharmony_ci					xa_set_mark(per_store_ap, sdhp->si_idx,
60418c2ecf20Sopenharmony_ci						    SDEB_XA_NOT_IN_USE);
60428c2ecf20Sopenharmony_ci					sdhp->si_idx = idx;
60438c2ecf20Sopenharmony_ci				}
60448c2ecf20Sopenharmony_ci			}
60458c2ecf20Sopenharmony_ci			sdeb_most_recent_idx = idx;
60468c2ecf20Sopenharmony_ci		} else {	/* 0 --> 1 transition is trigger for shrink */
60478c2ecf20Sopenharmony_ci			sdebug_erase_all_stores(true /* apart from first */);
60488c2ecf20Sopenharmony_ci		}
60498c2ecf20Sopenharmony_ci		sdebug_fake_rw = n;
60508c2ecf20Sopenharmony_ci		return count;
60518c2ecf20Sopenharmony_ci	}
60528c2ecf20Sopenharmony_ci	return -EINVAL;
60538c2ecf20Sopenharmony_ci}
60548c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(fake_rw);
60558c2ecf20Sopenharmony_ci
60568c2ecf20Sopenharmony_cistatic ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
60578c2ecf20Sopenharmony_ci{
60588c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
60598c2ecf20Sopenharmony_ci}
60608c2ecf20Sopenharmony_cistatic ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
60618c2ecf20Sopenharmony_ci			      size_t count)
60628c2ecf20Sopenharmony_ci{
60638c2ecf20Sopenharmony_ci	int n;
60648c2ecf20Sopenharmony_ci
60658c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
60668c2ecf20Sopenharmony_ci		sdebug_no_lun_0 = n;
60678c2ecf20Sopenharmony_ci		return count;
60688c2ecf20Sopenharmony_ci	}
60698c2ecf20Sopenharmony_ci	return -EINVAL;
60708c2ecf20Sopenharmony_ci}
60718c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(no_lun_0);
60728c2ecf20Sopenharmony_ci
60738c2ecf20Sopenharmony_cistatic ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
60748c2ecf20Sopenharmony_ci{
60758c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
60768c2ecf20Sopenharmony_ci}
60778c2ecf20Sopenharmony_cistatic ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
60788c2ecf20Sopenharmony_ci			      size_t count)
60798c2ecf20Sopenharmony_ci{
60808c2ecf20Sopenharmony_ci	int n;
60818c2ecf20Sopenharmony_ci
60828c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
60838c2ecf20Sopenharmony_ci		sdebug_num_tgts = n;
60848c2ecf20Sopenharmony_ci		sdebug_max_tgts_luns();
60858c2ecf20Sopenharmony_ci		return count;
60868c2ecf20Sopenharmony_ci	}
60878c2ecf20Sopenharmony_ci	return -EINVAL;
60888c2ecf20Sopenharmony_ci}
60898c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(num_tgts);
60908c2ecf20Sopenharmony_ci
60918c2ecf20Sopenharmony_cistatic ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
60928c2ecf20Sopenharmony_ci{
60938c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
60948c2ecf20Sopenharmony_ci}
60958c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(dev_size_mb);
60968c2ecf20Sopenharmony_ci
60978c2ecf20Sopenharmony_cistatic ssize_t per_host_store_show(struct device_driver *ddp, char *buf)
60988c2ecf20Sopenharmony_ci{
60998c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store);
61008c2ecf20Sopenharmony_ci}
61018c2ecf20Sopenharmony_ci
61028c2ecf20Sopenharmony_cistatic ssize_t per_host_store_store(struct device_driver *ddp, const char *buf,
61038c2ecf20Sopenharmony_ci				    size_t count)
61048c2ecf20Sopenharmony_ci{
61058c2ecf20Sopenharmony_ci	bool v;
61068c2ecf20Sopenharmony_ci
61078c2ecf20Sopenharmony_ci	if (kstrtobool(buf, &v))
61088c2ecf20Sopenharmony_ci		return -EINVAL;
61098c2ecf20Sopenharmony_ci
61108c2ecf20Sopenharmony_ci	sdebug_per_host_store = v;
61118c2ecf20Sopenharmony_ci	return count;
61128c2ecf20Sopenharmony_ci}
61138c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(per_host_store);
61148c2ecf20Sopenharmony_ci
61158c2ecf20Sopenharmony_cistatic ssize_t num_parts_show(struct device_driver *ddp, char *buf)
61168c2ecf20Sopenharmony_ci{
61178c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
61188c2ecf20Sopenharmony_ci}
61198c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(num_parts);
61208c2ecf20Sopenharmony_ci
61218c2ecf20Sopenharmony_cistatic ssize_t every_nth_show(struct device_driver *ddp, char *buf)
61228c2ecf20Sopenharmony_ci{
61238c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
61248c2ecf20Sopenharmony_ci}
61258c2ecf20Sopenharmony_cistatic ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
61268c2ecf20Sopenharmony_ci			       size_t count)
61278c2ecf20Sopenharmony_ci{
61288c2ecf20Sopenharmony_ci	int nth;
61298c2ecf20Sopenharmony_ci	char work[20];
61308c2ecf20Sopenharmony_ci
61318c2ecf20Sopenharmony_ci	if (sscanf(buf, "%10s", work) == 1) {
61328c2ecf20Sopenharmony_ci		if (strncasecmp(work, "0x", 2) == 0) {
61338c2ecf20Sopenharmony_ci			if (kstrtoint(work + 2, 16, &nth) == 0)
61348c2ecf20Sopenharmony_ci				goto every_nth_done;
61358c2ecf20Sopenharmony_ci		} else {
61368c2ecf20Sopenharmony_ci			if (kstrtoint(work, 10, &nth) == 0)
61378c2ecf20Sopenharmony_ci				goto every_nth_done;
61388c2ecf20Sopenharmony_ci		}
61398c2ecf20Sopenharmony_ci	}
61408c2ecf20Sopenharmony_ci	return -EINVAL;
61418c2ecf20Sopenharmony_ci
61428c2ecf20Sopenharmony_cievery_nth_done:
61438c2ecf20Sopenharmony_ci	sdebug_every_nth = nth;
61448c2ecf20Sopenharmony_ci	if (nth && !sdebug_statistics) {
61458c2ecf20Sopenharmony_ci		pr_info("every_nth needs statistics=1, set it\n");
61468c2ecf20Sopenharmony_ci		sdebug_statistics = true;
61478c2ecf20Sopenharmony_ci	}
61488c2ecf20Sopenharmony_ci	tweak_cmnd_count();
61498c2ecf20Sopenharmony_ci	return count;
61508c2ecf20Sopenharmony_ci}
61518c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(every_nth);
61528c2ecf20Sopenharmony_ci
61538c2ecf20Sopenharmony_cistatic ssize_t lun_format_show(struct device_driver *ddp, char *buf)
61548c2ecf20Sopenharmony_ci{
61558c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am);
61568c2ecf20Sopenharmony_ci}
61578c2ecf20Sopenharmony_cistatic ssize_t lun_format_store(struct device_driver *ddp, const char *buf,
61588c2ecf20Sopenharmony_ci				size_t count)
61598c2ecf20Sopenharmony_ci{
61608c2ecf20Sopenharmony_ci	int n;
61618c2ecf20Sopenharmony_ci	bool changed;
61628c2ecf20Sopenharmony_ci
61638c2ecf20Sopenharmony_ci	if (kstrtoint(buf, 0, &n))
61648c2ecf20Sopenharmony_ci		return -EINVAL;
61658c2ecf20Sopenharmony_ci	if (n >= 0) {
61668c2ecf20Sopenharmony_ci		if (n > (int)SAM_LUN_AM_FLAT) {
61678c2ecf20Sopenharmony_ci			pr_warn("only LUN address methods 0 and 1 are supported\n");
61688c2ecf20Sopenharmony_ci			return -EINVAL;
61698c2ecf20Sopenharmony_ci		}
61708c2ecf20Sopenharmony_ci		changed = ((int)sdebug_lun_am != n);
61718c2ecf20Sopenharmony_ci		sdebug_lun_am = n;
61728c2ecf20Sopenharmony_ci		if (changed && sdebug_scsi_level >= 5) {	/* >= SPC-3 */
61738c2ecf20Sopenharmony_ci			struct sdebug_host_info *sdhp;
61748c2ecf20Sopenharmony_ci			struct sdebug_dev_info *dp;
61758c2ecf20Sopenharmony_ci
61768c2ecf20Sopenharmony_ci			spin_lock(&sdebug_host_list_lock);
61778c2ecf20Sopenharmony_ci			list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
61788c2ecf20Sopenharmony_ci				list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
61798c2ecf20Sopenharmony_ci					set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
61808c2ecf20Sopenharmony_ci				}
61818c2ecf20Sopenharmony_ci			}
61828c2ecf20Sopenharmony_ci			spin_unlock(&sdebug_host_list_lock);
61838c2ecf20Sopenharmony_ci		}
61848c2ecf20Sopenharmony_ci		return count;
61858c2ecf20Sopenharmony_ci	}
61868c2ecf20Sopenharmony_ci	return -EINVAL;
61878c2ecf20Sopenharmony_ci}
61888c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(lun_format);
61898c2ecf20Sopenharmony_ci
61908c2ecf20Sopenharmony_cistatic ssize_t max_luns_show(struct device_driver *ddp, char *buf)
61918c2ecf20Sopenharmony_ci{
61928c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
61938c2ecf20Sopenharmony_ci}
61948c2ecf20Sopenharmony_cistatic ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
61958c2ecf20Sopenharmony_ci			      size_t count)
61968c2ecf20Sopenharmony_ci{
61978c2ecf20Sopenharmony_ci	int n;
61988c2ecf20Sopenharmony_ci	bool changed;
61998c2ecf20Sopenharmony_ci
62008c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
62018c2ecf20Sopenharmony_ci		if (n > 256) {
62028c2ecf20Sopenharmony_ci			pr_warn("max_luns can be no more than 256\n");
62038c2ecf20Sopenharmony_ci			return -EINVAL;
62048c2ecf20Sopenharmony_ci		}
62058c2ecf20Sopenharmony_ci		changed = (sdebug_max_luns != n);
62068c2ecf20Sopenharmony_ci		sdebug_max_luns = n;
62078c2ecf20Sopenharmony_ci		sdebug_max_tgts_luns();
62088c2ecf20Sopenharmony_ci		if (changed && (sdebug_scsi_level >= 5)) {	/* >= SPC-3 */
62098c2ecf20Sopenharmony_ci			struct sdebug_host_info *sdhp;
62108c2ecf20Sopenharmony_ci			struct sdebug_dev_info *dp;
62118c2ecf20Sopenharmony_ci
62128c2ecf20Sopenharmony_ci			spin_lock(&sdebug_host_list_lock);
62138c2ecf20Sopenharmony_ci			list_for_each_entry(sdhp, &sdebug_host_list,
62148c2ecf20Sopenharmony_ci					    host_list) {
62158c2ecf20Sopenharmony_ci				list_for_each_entry(dp, &sdhp->dev_info_list,
62168c2ecf20Sopenharmony_ci						    dev_list) {
62178c2ecf20Sopenharmony_ci					set_bit(SDEBUG_UA_LUNS_CHANGED,
62188c2ecf20Sopenharmony_ci						dp->uas_bm);
62198c2ecf20Sopenharmony_ci				}
62208c2ecf20Sopenharmony_ci			}
62218c2ecf20Sopenharmony_ci			spin_unlock(&sdebug_host_list_lock);
62228c2ecf20Sopenharmony_ci		}
62238c2ecf20Sopenharmony_ci		return count;
62248c2ecf20Sopenharmony_ci	}
62258c2ecf20Sopenharmony_ci	return -EINVAL;
62268c2ecf20Sopenharmony_ci}
62278c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(max_luns);
62288c2ecf20Sopenharmony_ci
62298c2ecf20Sopenharmony_cistatic ssize_t max_queue_show(struct device_driver *ddp, char *buf)
62308c2ecf20Sopenharmony_ci{
62318c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
62328c2ecf20Sopenharmony_ci}
62338c2ecf20Sopenharmony_ci/* N.B. max_queue can be changed while there are queued commands. In flight
62348c2ecf20Sopenharmony_ci * commands beyond the new max_queue will be completed. */
62358c2ecf20Sopenharmony_cistatic ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
62368c2ecf20Sopenharmony_ci			       size_t count)
62378c2ecf20Sopenharmony_ci{
62388c2ecf20Sopenharmony_ci	int j, n, k, a;
62398c2ecf20Sopenharmony_ci	struct sdebug_queue *sqp;
62408c2ecf20Sopenharmony_ci
62418c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
62428c2ecf20Sopenharmony_ci	    (n <= SDEBUG_CANQUEUE) &&
62438c2ecf20Sopenharmony_ci	    (sdebug_host_max_queue == 0)) {
62448c2ecf20Sopenharmony_ci		block_unblock_all_queues(true);
62458c2ecf20Sopenharmony_ci		k = 0;
62468c2ecf20Sopenharmony_ci		for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
62478c2ecf20Sopenharmony_ci		     ++j, ++sqp) {
62488c2ecf20Sopenharmony_ci			a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
62498c2ecf20Sopenharmony_ci			if (a > k)
62508c2ecf20Sopenharmony_ci				k = a;
62518c2ecf20Sopenharmony_ci		}
62528c2ecf20Sopenharmony_ci		sdebug_max_queue = n;
62538c2ecf20Sopenharmony_ci		if (k == SDEBUG_CANQUEUE)
62548c2ecf20Sopenharmony_ci			atomic_set(&retired_max_queue, 0);
62558c2ecf20Sopenharmony_ci		else if (k >= n)
62568c2ecf20Sopenharmony_ci			atomic_set(&retired_max_queue, k + 1);
62578c2ecf20Sopenharmony_ci		else
62588c2ecf20Sopenharmony_ci			atomic_set(&retired_max_queue, 0);
62598c2ecf20Sopenharmony_ci		block_unblock_all_queues(false);
62608c2ecf20Sopenharmony_ci		return count;
62618c2ecf20Sopenharmony_ci	}
62628c2ecf20Sopenharmony_ci	return -EINVAL;
62638c2ecf20Sopenharmony_ci}
62648c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(max_queue);
62658c2ecf20Sopenharmony_ci
62668c2ecf20Sopenharmony_cistatic ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
62678c2ecf20Sopenharmony_ci{
62688c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
62698c2ecf20Sopenharmony_ci}
62708c2ecf20Sopenharmony_ci
62718c2ecf20Sopenharmony_ci/*
62728c2ecf20Sopenharmony_ci * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
62738c2ecf20Sopenharmony_ci * in range [0, sdebug_host_max_queue), we can't change it.
62748c2ecf20Sopenharmony_ci */
62758c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(host_max_queue);
62768c2ecf20Sopenharmony_ci
62778c2ecf20Sopenharmony_cistatic ssize_t no_uld_show(struct device_driver *ddp, char *buf)
62788c2ecf20Sopenharmony_ci{
62798c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
62808c2ecf20Sopenharmony_ci}
62818c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(no_uld);
62828c2ecf20Sopenharmony_ci
62838c2ecf20Sopenharmony_cistatic ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
62848c2ecf20Sopenharmony_ci{
62858c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
62868c2ecf20Sopenharmony_ci}
62878c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(scsi_level);
62888c2ecf20Sopenharmony_ci
62898c2ecf20Sopenharmony_cistatic ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
62908c2ecf20Sopenharmony_ci{
62918c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
62928c2ecf20Sopenharmony_ci}
62938c2ecf20Sopenharmony_cistatic ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
62948c2ecf20Sopenharmony_ci				size_t count)
62958c2ecf20Sopenharmony_ci{
62968c2ecf20Sopenharmony_ci	int n;
62978c2ecf20Sopenharmony_ci	bool changed;
62988c2ecf20Sopenharmony_ci
62998c2ecf20Sopenharmony_ci	/* Ignore capacity change for ZBC drives for now */
63008c2ecf20Sopenharmony_ci	if (sdeb_zbc_in_use)
63018c2ecf20Sopenharmony_ci		return -ENOTSUPP;
63028c2ecf20Sopenharmony_ci
63038c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
63048c2ecf20Sopenharmony_ci		changed = (sdebug_virtual_gb != n);
63058c2ecf20Sopenharmony_ci		sdebug_virtual_gb = n;
63068c2ecf20Sopenharmony_ci		sdebug_capacity = get_sdebug_capacity();
63078c2ecf20Sopenharmony_ci		if (changed) {
63088c2ecf20Sopenharmony_ci			struct sdebug_host_info *sdhp;
63098c2ecf20Sopenharmony_ci			struct sdebug_dev_info *dp;
63108c2ecf20Sopenharmony_ci
63118c2ecf20Sopenharmony_ci			spin_lock(&sdebug_host_list_lock);
63128c2ecf20Sopenharmony_ci			list_for_each_entry(sdhp, &sdebug_host_list,
63138c2ecf20Sopenharmony_ci					    host_list) {
63148c2ecf20Sopenharmony_ci				list_for_each_entry(dp, &sdhp->dev_info_list,
63158c2ecf20Sopenharmony_ci						    dev_list) {
63168c2ecf20Sopenharmony_ci					set_bit(SDEBUG_UA_CAPACITY_CHANGED,
63178c2ecf20Sopenharmony_ci						dp->uas_bm);
63188c2ecf20Sopenharmony_ci				}
63198c2ecf20Sopenharmony_ci			}
63208c2ecf20Sopenharmony_ci			spin_unlock(&sdebug_host_list_lock);
63218c2ecf20Sopenharmony_ci		}
63228c2ecf20Sopenharmony_ci		return count;
63238c2ecf20Sopenharmony_ci	}
63248c2ecf20Sopenharmony_ci	return -EINVAL;
63258c2ecf20Sopenharmony_ci}
63268c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(virtual_gb);
63278c2ecf20Sopenharmony_ci
63288c2ecf20Sopenharmony_cistatic ssize_t add_host_show(struct device_driver *ddp, char *buf)
63298c2ecf20Sopenharmony_ci{
63308c2ecf20Sopenharmony_ci	/* absolute number of hosts currently active is what is shown */
63318c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
63328c2ecf20Sopenharmony_ci}
63338c2ecf20Sopenharmony_ci
63348c2ecf20Sopenharmony_cistatic ssize_t add_host_store(struct device_driver *ddp, const char *buf,
63358c2ecf20Sopenharmony_ci			      size_t count)
63368c2ecf20Sopenharmony_ci{
63378c2ecf20Sopenharmony_ci	bool found;
63388c2ecf20Sopenharmony_ci	unsigned long idx;
63398c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip;
63408c2ecf20Sopenharmony_ci	bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
63418c2ecf20Sopenharmony_ci	int delta_hosts;
63428c2ecf20Sopenharmony_ci
63438c2ecf20Sopenharmony_ci	if (sscanf(buf, "%d", &delta_hosts) != 1)
63448c2ecf20Sopenharmony_ci		return -EINVAL;
63458c2ecf20Sopenharmony_ci	if (delta_hosts > 0) {
63468c2ecf20Sopenharmony_ci		do {
63478c2ecf20Sopenharmony_ci			found = false;
63488c2ecf20Sopenharmony_ci			if (want_phs) {
63498c2ecf20Sopenharmony_ci				xa_for_each_marked(per_store_ap, idx, sip,
63508c2ecf20Sopenharmony_ci						   SDEB_XA_NOT_IN_USE) {
63518c2ecf20Sopenharmony_ci					sdeb_most_recent_idx = (int)idx;
63528c2ecf20Sopenharmony_ci					found = true;
63538c2ecf20Sopenharmony_ci					break;
63548c2ecf20Sopenharmony_ci				}
63558c2ecf20Sopenharmony_ci				if (found)	/* re-use case */
63568c2ecf20Sopenharmony_ci					sdebug_add_host_helper((int)idx);
63578c2ecf20Sopenharmony_ci				else
63588c2ecf20Sopenharmony_ci					sdebug_do_add_host(true);
63598c2ecf20Sopenharmony_ci			} else {
63608c2ecf20Sopenharmony_ci				sdebug_do_add_host(false);
63618c2ecf20Sopenharmony_ci			}
63628c2ecf20Sopenharmony_ci		} while (--delta_hosts);
63638c2ecf20Sopenharmony_ci	} else if (delta_hosts < 0) {
63648c2ecf20Sopenharmony_ci		do {
63658c2ecf20Sopenharmony_ci			sdebug_do_remove_host(false);
63668c2ecf20Sopenharmony_ci		} while (++delta_hosts);
63678c2ecf20Sopenharmony_ci	}
63688c2ecf20Sopenharmony_ci	return count;
63698c2ecf20Sopenharmony_ci}
63708c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(add_host);
63718c2ecf20Sopenharmony_ci
63728c2ecf20Sopenharmony_cistatic ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
63738c2ecf20Sopenharmony_ci{
63748c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
63758c2ecf20Sopenharmony_ci}
63768c2ecf20Sopenharmony_cistatic ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
63778c2ecf20Sopenharmony_ci				    size_t count)
63788c2ecf20Sopenharmony_ci{
63798c2ecf20Sopenharmony_ci	int n;
63808c2ecf20Sopenharmony_ci
63818c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
63828c2ecf20Sopenharmony_ci		sdebug_vpd_use_hostno = n;
63838c2ecf20Sopenharmony_ci		return count;
63848c2ecf20Sopenharmony_ci	}
63858c2ecf20Sopenharmony_ci	return -EINVAL;
63868c2ecf20Sopenharmony_ci}
63878c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(vpd_use_hostno);
63888c2ecf20Sopenharmony_ci
63898c2ecf20Sopenharmony_cistatic ssize_t statistics_show(struct device_driver *ddp, char *buf)
63908c2ecf20Sopenharmony_ci{
63918c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
63928c2ecf20Sopenharmony_ci}
63938c2ecf20Sopenharmony_cistatic ssize_t statistics_store(struct device_driver *ddp, const char *buf,
63948c2ecf20Sopenharmony_ci				size_t count)
63958c2ecf20Sopenharmony_ci{
63968c2ecf20Sopenharmony_ci	int n;
63978c2ecf20Sopenharmony_ci
63988c2ecf20Sopenharmony_ci	if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
63998c2ecf20Sopenharmony_ci		if (n > 0)
64008c2ecf20Sopenharmony_ci			sdebug_statistics = true;
64018c2ecf20Sopenharmony_ci		else {
64028c2ecf20Sopenharmony_ci			clear_queue_stats();
64038c2ecf20Sopenharmony_ci			sdebug_statistics = false;
64048c2ecf20Sopenharmony_ci		}
64058c2ecf20Sopenharmony_ci		return count;
64068c2ecf20Sopenharmony_ci	}
64078c2ecf20Sopenharmony_ci	return -EINVAL;
64088c2ecf20Sopenharmony_ci}
64098c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(statistics);
64108c2ecf20Sopenharmony_ci
64118c2ecf20Sopenharmony_cistatic ssize_t sector_size_show(struct device_driver *ddp, char *buf)
64128c2ecf20Sopenharmony_ci{
64138c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
64148c2ecf20Sopenharmony_ci}
64158c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(sector_size);
64168c2ecf20Sopenharmony_ci
64178c2ecf20Sopenharmony_cistatic ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
64188c2ecf20Sopenharmony_ci{
64198c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
64208c2ecf20Sopenharmony_ci}
64218c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(submit_queues);
64228c2ecf20Sopenharmony_ci
64238c2ecf20Sopenharmony_cistatic ssize_t dix_show(struct device_driver *ddp, char *buf)
64248c2ecf20Sopenharmony_ci{
64258c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
64268c2ecf20Sopenharmony_ci}
64278c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(dix);
64288c2ecf20Sopenharmony_ci
64298c2ecf20Sopenharmony_cistatic ssize_t dif_show(struct device_driver *ddp, char *buf)
64308c2ecf20Sopenharmony_ci{
64318c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
64328c2ecf20Sopenharmony_ci}
64338c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(dif);
64348c2ecf20Sopenharmony_ci
64358c2ecf20Sopenharmony_cistatic ssize_t guard_show(struct device_driver *ddp, char *buf)
64368c2ecf20Sopenharmony_ci{
64378c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
64388c2ecf20Sopenharmony_ci}
64398c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(guard);
64408c2ecf20Sopenharmony_ci
64418c2ecf20Sopenharmony_cistatic ssize_t ato_show(struct device_driver *ddp, char *buf)
64428c2ecf20Sopenharmony_ci{
64438c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
64448c2ecf20Sopenharmony_ci}
64458c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(ato);
64468c2ecf20Sopenharmony_ci
64478c2ecf20Sopenharmony_cistatic ssize_t map_show(struct device_driver *ddp, char *buf)
64488c2ecf20Sopenharmony_ci{
64498c2ecf20Sopenharmony_ci	ssize_t count = 0;
64508c2ecf20Sopenharmony_ci
64518c2ecf20Sopenharmony_ci	if (!scsi_debug_lbp())
64528c2ecf20Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "0-%u\n",
64538c2ecf20Sopenharmony_ci				 sdebug_store_sectors);
64548c2ecf20Sopenharmony_ci
64558c2ecf20Sopenharmony_ci	if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) {
64568c2ecf20Sopenharmony_ci		struct sdeb_store_info *sip = xa_load(per_store_ap, 0);
64578c2ecf20Sopenharmony_ci
64588c2ecf20Sopenharmony_ci		if (sip)
64598c2ecf20Sopenharmony_ci			count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
64608c2ecf20Sopenharmony_ci					  (int)map_size, sip->map_storep);
64618c2ecf20Sopenharmony_ci	}
64628c2ecf20Sopenharmony_ci	buf[count++] = '\n';
64638c2ecf20Sopenharmony_ci	buf[count] = '\0';
64648c2ecf20Sopenharmony_ci
64658c2ecf20Sopenharmony_ci	return count;
64668c2ecf20Sopenharmony_ci}
64678c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(map);
64688c2ecf20Sopenharmony_ci
64698c2ecf20Sopenharmony_cistatic ssize_t random_show(struct device_driver *ddp, char *buf)
64708c2ecf20Sopenharmony_ci{
64718c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random);
64728c2ecf20Sopenharmony_ci}
64738c2ecf20Sopenharmony_ci
64748c2ecf20Sopenharmony_cistatic ssize_t random_store(struct device_driver *ddp, const char *buf,
64758c2ecf20Sopenharmony_ci			    size_t count)
64768c2ecf20Sopenharmony_ci{
64778c2ecf20Sopenharmony_ci	bool v;
64788c2ecf20Sopenharmony_ci
64798c2ecf20Sopenharmony_ci	if (kstrtobool(buf, &v))
64808c2ecf20Sopenharmony_ci		return -EINVAL;
64818c2ecf20Sopenharmony_ci
64828c2ecf20Sopenharmony_ci	sdebug_random = v;
64838c2ecf20Sopenharmony_ci	return count;
64848c2ecf20Sopenharmony_ci}
64858c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(random);
64868c2ecf20Sopenharmony_ci
64878c2ecf20Sopenharmony_cistatic ssize_t removable_show(struct device_driver *ddp, char *buf)
64888c2ecf20Sopenharmony_ci{
64898c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
64908c2ecf20Sopenharmony_ci}
64918c2ecf20Sopenharmony_cistatic ssize_t removable_store(struct device_driver *ddp, const char *buf,
64928c2ecf20Sopenharmony_ci			       size_t count)
64938c2ecf20Sopenharmony_ci{
64948c2ecf20Sopenharmony_ci	int n;
64958c2ecf20Sopenharmony_ci
64968c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
64978c2ecf20Sopenharmony_ci		sdebug_removable = (n > 0);
64988c2ecf20Sopenharmony_ci		return count;
64998c2ecf20Sopenharmony_ci	}
65008c2ecf20Sopenharmony_ci	return -EINVAL;
65018c2ecf20Sopenharmony_ci}
65028c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(removable);
65038c2ecf20Sopenharmony_ci
65048c2ecf20Sopenharmony_cistatic ssize_t host_lock_show(struct device_driver *ddp, char *buf)
65058c2ecf20Sopenharmony_ci{
65068c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
65078c2ecf20Sopenharmony_ci}
65088c2ecf20Sopenharmony_ci/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
65098c2ecf20Sopenharmony_cistatic ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
65108c2ecf20Sopenharmony_ci			       size_t count)
65118c2ecf20Sopenharmony_ci{
65128c2ecf20Sopenharmony_ci	int n;
65138c2ecf20Sopenharmony_ci
65148c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
65158c2ecf20Sopenharmony_ci		sdebug_host_lock = (n > 0);
65168c2ecf20Sopenharmony_ci		return count;
65178c2ecf20Sopenharmony_ci	}
65188c2ecf20Sopenharmony_ci	return -EINVAL;
65198c2ecf20Sopenharmony_ci}
65208c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(host_lock);
65218c2ecf20Sopenharmony_ci
65228c2ecf20Sopenharmony_cistatic ssize_t strict_show(struct device_driver *ddp, char *buf)
65238c2ecf20Sopenharmony_ci{
65248c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
65258c2ecf20Sopenharmony_ci}
65268c2ecf20Sopenharmony_cistatic ssize_t strict_store(struct device_driver *ddp, const char *buf,
65278c2ecf20Sopenharmony_ci			    size_t count)
65288c2ecf20Sopenharmony_ci{
65298c2ecf20Sopenharmony_ci	int n;
65308c2ecf20Sopenharmony_ci
65318c2ecf20Sopenharmony_ci	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
65328c2ecf20Sopenharmony_ci		sdebug_strict = (n > 0);
65338c2ecf20Sopenharmony_ci		return count;
65348c2ecf20Sopenharmony_ci	}
65358c2ecf20Sopenharmony_ci	return -EINVAL;
65368c2ecf20Sopenharmony_ci}
65378c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(strict);
65388c2ecf20Sopenharmony_ci
65398c2ecf20Sopenharmony_cistatic ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
65408c2ecf20Sopenharmony_ci{
65418c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
65428c2ecf20Sopenharmony_ci}
65438c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(uuid_ctl);
65448c2ecf20Sopenharmony_ci
65458c2ecf20Sopenharmony_cistatic ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
65468c2ecf20Sopenharmony_ci{
65478c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
65488c2ecf20Sopenharmony_ci}
65498c2ecf20Sopenharmony_cistatic ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
65508c2ecf20Sopenharmony_ci			     size_t count)
65518c2ecf20Sopenharmony_ci{
65528c2ecf20Sopenharmony_ci	int ret, n;
65538c2ecf20Sopenharmony_ci
65548c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &n);
65558c2ecf20Sopenharmony_ci	if (ret)
65568c2ecf20Sopenharmony_ci		return ret;
65578c2ecf20Sopenharmony_ci	sdebug_cdb_len = n;
65588c2ecf20Sopenharmony_ci	all_config_cdb_len();
65598c2ecf20Sopenharmony_ci	return count;
65608c2ecf20Sopenharmony_ci}
65618c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RW(cdb_len);
65628c2ecf20Sopenharmony_ci
65638c2ecf20Sopenharmony_cistatic const char * const zbc_model_strs_a[] = {
65648c2ecf20Sopenharmony_ci	[BLK_ZONED_NONE] = "none",
65658c2ecf20Sopenharmony_ci	[BLK_ZONED_HA]   = "host-aware",
65668c2ecf20Sopenharmony_ci	[BLK_ZONED_HM]   = "host-managed",
65678c2ecf20Sopenharmony_ci};
65688c2ecf20Sopenharmony_ci
65698c2ecf20Sopenharmony_cistatic const char * const zbc_model_strs_b[] = {
65708c2ecf20Sopenharmony_ci	[BLK_ZONED_NONE] = "no",
65718c2ecf20Sopenharmony_ci	[BLK_ZONED_HA]   = "aware",
65728c2ecf20Sopenharmony_ci	[BLK_ZONED_HM]   = "managed",
65738c2ecf20Sopenharmony_ci};
65748c2ecf20Sopenharmony_ci
65758c2ecf20Sopenharmony_cistatic const char * const zbc_model_strs_c[] = {
65768c2ecf20Sopenharmony_ci	[BLK_ZONED_NONE] = "0",
65778c2ecf20Sopenharmony_ci	[BLK_ZONED_HA]   = "1",
65788c2ecf20Sopenharmony_ci	[BLK_ZONED_HM]   = "2",
65798c2ecf20Sopenharmony_ci};
65808c2ecf20Sopenharmony_ci
65818c2ecf20Sopenharmony_cistatic int sdeb_zbc_model_str(const char *cp)
65828c2ecf20Sopenharmony_ci{
65838c2ecf20Sopenharmony_ci	int res = sysfs_match_string(zbc_model_strs_a, cp);
65848c2ecf20Sopenharmony_ci
65858c2ecf20Sopenharmony_ci	if (res < 0) {
65868c2ecf20Sopenharmony_ci		res = sysfs_match_string(zbc_model_strs_b, cp);
65878c2ecf20Sopenharmony_ci		if (res < 0) {
65888c2ecf20Sopenharmony_ci			res = sysfs_match_string(zbc_model_strs_c, cp);
65898c2ecf20Sopenharmony_ci			if (res < 0)
65908c2ecf20Sopenharmony_ci				return -EINVAL;
65918c2ecf20Sopenharmony_ci		}
65928c2ecf20Sopenharmony_ci	}
65938c2ecf20Sopenharmony_ci	return res;
65948c2ecf20Sopenharmony_ci}
65958c2ecf20Sopenharmony_ci
65968c2ecf20Sopenharmony_cistatic ssize_t zbc_show(struct device_driver *ddp, char *buf)
65978c2ecf20Sopenharmony_ci{
65988c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n",
65998c2ecf20Sopenharmony_ci			 zbc_model_strs_a[sdeb_zbc_model]);
66008c2ecf20Sopenharmony_ci}
66018c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(zbc);
66028c2ecf20Sopenharmony_ci
66038c2ecf20Sopenharmony_cistatic ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf)
66048c2ecf20Sopenharmony_ci{
66058c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready);
66068c2ecf20Sopenharmony_ci}
66078c2ecf20Sopenharmony_cistatic DRIVER_ATTR_RO(tur_ms_to_ready);
66088c2ecf20Sopenharmony_ci
66098c2ecf20Sopenharmony_ci/* Note: The following array creates attribute files in the
66108c2ecf20Sopenharmony_ci   /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
66118c2ecf20Sopenharmony_ci   files (over those found in the /sys/module/scsi_debug/parameters
66128c2ecf20Sopenharmony_ci   directory) is that auxiliary actions can be triggered when an attribute
66138c2ecf20Sopenharmony_ci   is changed. For example see: add_host_store() above.
66148c2ecf20Sopenharmony_ci */
66158c2ecf20Sopenharmony_ci
66168c2ecf20Sopenharmony_cistatic struct attribute *sdebug_drv_attrs[] = {
66178c2ecf20Sopenharmony_ci	&driver_attr_delay.attr,
66188c2ecf20Sopenharmony_ci	&driver_attr_opts.attr,
66198c2ecf20Sopenharmony_ci	&driver_attr_ptype.attr,
66208c2ecf20Sopenharmony_ci	&driver_attr_dsense.attr,
66218c2ecf20Sopenharmony_ci	&driver_attr_fake_rw.attr,
66228c2ecf20Sopenharmony_ci	&driver_attr_host_max_queue.attr,
66238c2ecf20Sopenharmony_ci	&driver_attr_no_lun_0.attr,
66248c2ecf20Sopenharmony_ci	&driver_attr_num_tgts.attr,
66258c2ecf20Sopenharmony_ci	&driver_attr_dev_size_mb.attr,
66268c2ecf20Sopenharmony_ci	&driver_attr_num_parts.attr,
66278c2ecf20Sopenharmony_ci	&driver_attr_every_nth.attr,
66288c2ecf20Sopenharmony_ci	&driver_attr_lun_format.attr,
66298c2ecf20Sopenharmony_ci	&driver_attr_max_luns.attr,
66308c2ecf20Sopenharmony_ci	&driver_attr_max_queue.attr,
66318c2ecf20Sopenharmony_ci	&driver_attr_no_uld.attr,
66328c2ecf20Sopenharmony_ci	&driver_attr_scsi_level.attr,
66338c2ecf20Sopenharmony_ci	&driver_attr_virtual_gb.attr,
66348c2ecf20Sopenharmony_ci	&driver_attr_add_host.attr,
66358c2ecf20Sopenharmony_ci	&driver_attr_per_host_store.attr,
66368c2ecf20Sopenharmony_ci	&driver_attr_vpd_use_hostno.attr,
66378c2ecf20Sopenharmony_ci	&driver_attr_sector_size.attr,
66388c2ecf20Sopenharmony_ci	&driver_attr_statistics.attr,
66398c2ecf20Sopenharmony_ci	&driver_attr_submit_queues.attr,
66408c2ecf20Sopenharmony_ci	&driver_attr_dix.attr,
66418c2ecf20Sopenharmony_ci	&driver_attr_dif.attr,
66428c2ecf20Sopenharmony_ci	&driver_attr_guard.attr,
66438c2ecf20Sopenharmony_ci	&driver_attr_ato.attr,
66448c2ecf20Sopenharmony_ci	&driver_attr_map.attr,
66458c2ecf20Sopenharmony_ci	&driver_attr_random.attr,
66468c2ecf20Sopenharmony_ci	&driver_attr_removable.attr,
66478c2ecf20Sopenharmony_ci	&driver_attr_host_lock.attr,
66488c2ecf20Sopenharmony_ci	&driver_attr_ndelay.attr,
66498c2ecf20Sopenharmony_ci	&driver_attr_strict.attr,
66508c2ecf20Sopenharmony_ci	&driver_attr_uuid_ctl.attr,
66518c2ecf20Sopenharmony_ci	&driver_attr_cdb_len.attr,
66528c2ecf20Sopenharmony_ci	&driver_attr_tur_ms_to_ready.attr,
66538c2ecf20Sopenharmony_ci	&driver_attr_zbc.attr,
66548c2ecf20Sopenharmony_ci	NULL,
66558c2ecf20Sopenharmony_ci};
66568c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(sdebug_drv);
66578c2ecf20Sopenharmony_ci
66588c2ecf20Sopenharmony_cistatic struct device *pseudo_primary;
66598c2ecf20Sopenharmony_ci
66608c2ecf20Sopenharmony_cistatic int __init scsi_debug_init(void)
66618c2ecf20Sopenharmony_ci{
66628c2ecf20Sopenharmony_ci	bool want_store = (sdebug_fake_rw == 0);
66638c2ecf20Sopenharmony_ci	unsigned long sz;
66648c2ecf20Sopenharmony_ci	int k, ret, hosts_to_add;
66658c2ecf20Sopenharmony_ci	int idx = -1;
66668c2ecf20Sopenharmony_ci
66678c2ecf20Sopenharmony_ci	ramdisk_lck_a[0] = &atomic_rw;
66688c2ecf20Sopenharmony_ci	ramdisk_lck_a[1] = &atomic_rw2;
66698c2ecf20Sopenharmony_ci	atomic_set(&retired_max_queue, 0);
66708c2ecf20Sopenharmony_ci
66718c2ecf20Sopenharmony_ci	if (sdebug_ndelay >= 1000 * 1000 * 1000) {
66728c2ecf20Sopenharmony_ci		pr_warn("ndelay must be less than 1 second, ignored\n");
66738c2ecf20Sopenharmony_ci		sdebug_ndelay = 0;
66748c2ecf20Sopenharmony_ci	} else if (sdebug_ndelay > 0)
66758c2ecf20Sopenharmony_ci		sdebug_jdelay = JDELAY_OVERRIDDEN;
66768c2ecf20Sopenharmony_ci
66778c2ecf20Sopenharmony_ci	switch (sdebug_sector_size) {
66788c2ecf20Sopenharmony_ci	case  512:
66798c2ecf20Sopenharmony_ci	case 1024:
66808c2ecf20Sopenharmony_ci	case 2048:
66818c2ecf20Sopenharmony_ci	case 4096:
66828c2ecf20Sopenharmony_ci		break;
66838c2ecf20Sopenharmony_ci	default:
66848c2ecf20Sopenharmony_ci		pr_err("invalid sector_size %d\n", sdebug_sector_size);
66858c2ecf20Sopenharmony_ci		return -EINVAL;
66868c2ecf20Sopenharmony_ci	}
66878c2ecf20Sopenharmony_ci
66888c2ecf20Sopenharmony_ci	switch (sdebug_dif) {
66898c2ecf20Sopenharmony_ci	case T10_PI_TYPE0_PROTECTION:
66908c2ecf20Sopenharmony_ci		break;
66918c2ecf20Sopenharmony_ci	case T10_PI_TYPE1_PROTECTION:
66928c2ecf20Sopenharmony_ci	case T10_PI_TYPE2_PROTECTION:
66938c2ecf20Sopenharmony_ci	case T10_PI_TYPE3_PROTECTION:
66948c2ecf20Sopenharmony_ci		have_dif_prot = true;
66958c2ecf20Sopenharmony_ci		break;
66968c2ecf20Sopenharmony_ci
66978c2ecf20Sopenharmony_ci	default:
66988c2ecf20Sopenharmony_ci		pr_err("dif must be 0, 1, 2 or 3\n");
66998c2ecf20Sopenharmony_ci		return -EINVAL;
67008c2ecf20Sopenharmony_ci	}
67018c2ecf20Sopenharmony_ci
67028c2ecf20Sopenharmony_ci	if (sdebug_num_tgts < 0) {
67038c2ecf20Sopenharmony_ci		pr_err("num_tgts must be >= 0\n");
67048c2ecf20Sopenharmony_ci		return -EINVAL;
67058c2ecf20Sopenharmony_ci	}
67068c2ecf20Sopenharmony_ci
67078c2ecf20Sopenharmony_ci	if (sdebug_guard > 1) {
67088c2ecf20Sopenharmony_ci		pr_err("guard must be 0 or 1\n");
67098c2ecf20Sopenharmony_ci		return -EINVAL;
67108c2ecf20Sopenharmony_ci	}
67118c2ecf20Sopenharmony_ci
67128c2ecf20Sopenharmony_ci	if (sdebug_ato > 1) {
67138c2ecf20Sopenharmony_ci		pr_err("ato must be 0 or 1\n");
67148c2ecf20Sopenharmony_ci		return -EINVAL;
67158c2ecf20Sopenharmony_ci	}
67168c2ecf20Sopenharmony_ci
67178c2ecf20Sopenharmony_ci	if (sdebug_physblk_exp > 15) {
67188c2ecf20Sopenharmony_ci		pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
67198c2ecf20Sopenharmony_ci		return -EINVAL;
67208c2ecf20Sopenharmony_ci	}
67218c2ecf20Sopenharmony_ci
67228c2ecf20Sopenharmony_ci	sdebug_lun_am = sdebug_lun_am_i;
67238c2ecf20Sopenharmony_ci	if (sdebug_lun_am > SAM_LUN_AM_FLAT) {
67248c2ecf20Sopenharmony_ci		pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am);
67258c2ecf20Sopenharmony_ci		sdebug_lun_am = SAM_LUN_AM_PERIPHERAL;
67268c2ecf20Sopenharmony_ci	}
67278c2ecf20Sopenharmony_ci
67288c2ecf20Sopenharmony_ci	if (sdebug_max_luns > 256) {
67298c2ecf20Sopenharmony_ci		if (sdebug_max_luns > 16384) {
67308c2ecf20Sopenharmony_ci			pr_warn("max_luns can be no more than 16384, use default\n");
67318c2ecf20Sopenharmony_ci			sdebug_max_luns = DEF_MAX_LUNS;
67328c2ecf20Sopenharmony_ci		}
67338c2ecf20Sopenharmony_ci		sdebug_lun_am = SAM_LUN_AM_FLAT;
67348c2ecf20Sopenharmony_ci	}
67358c2ecf20Sopenharmony_ci
67368c2ecf20Sopenharmony_ci	if (sdebug_lowest_aligned > 0x3fff) {
67378c2ecf20Sopenharmony_ci		pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
67388c2ecf20Sopenharmony_ci		return -EINVAL;
67398c2ecf20Sopenharmony_ci	}
67408c2ecf20Sopenharmony_ci
67418c2ecf20Sopenharmony_ci	if (submit_queues < 1) {
67428c2ecf20Sopenharmony_ci		pr_err("submit_queues must be 1 or more\n");
67438c2ecf20Sopenharmony_ci		return -EINVAL;
67448c2ecf20Sopenharmony_ci	}
67458c2ecf20Sopenharmony_ci
67468c2ecf20Sopenharmony_ci	if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) {
67478c2ecf20Sopenharmony_ci		pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE);
67488c2ecf20Sopenharmony_ci		return -EINVAL;
67498c2ecf20Sopenharmony_ci	}
67508c2ecf20Sopenharmony_ci
67518c2ecf20Sopenharmony_ci	if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) ||
67528c2ecf20Sopenharmony_ci	    (sdebug_host_max_queue < 0)) {
67538c2ecf20Sopenharmony_ci		pr_err("host_max_queue must be in range [0 %d]\n",
67548c2ecf20Sopenharmony_ci		       SDEBUG_CANQUEUE);
67558c2ecf20Sopenharmony_ci		return -EINVAL;
67568c2ecf20Sopenharmony_ci	}
67578c2ecf20Sopenharmony_ci
67588c2ecf20Sopenharmony_ci	if (sdebug_host_max_queue &&
67598c2ecf20Sopenharmony_ci	    (sdebug_max_queue != sdebug_host_max_queue)) {
67608c2ecf20Sopenharmony_ci		sdebug_max_queue = sdebug_host_max_queue;
67618c2ecf20Sopenharmony_ci		pr_warn("fixing max submit queue depth to host max queue depth, %d\n",
67628c2ecf20Sopenharmony_ci			sdebug_max_queue);
67638c2ecf20Sopenharmony_ci	}
67648c2ecf20Sopenharmony_ci
67658c2ecf20Sopenharmony_ci	sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
67668c2ecf20Sopenharmony_ci			       GFP_KERNEL);
67678c2ecf20Sopenharmony_ci	if (sdebug_q_arr == NULL)
67688c2ecf20Sopenharmony_ci		return -ENOMEM;
67698c2ecf20Sopenharmony_ci	for (k = 0; k < submit_queues; ++k)
67708c2ecf20Sopenharmony_ci		spin_lock_init(&sdebug_q_arr[k].qc_lock);
67718c2ecf20Sopenharmony_ci
67728c2ecf20Sopenharmony_ci	/*
67738c2ecf20Sopenharmony_ci	 * check for host managed zoned block device specified with
67748c2ecf20Sopenharmony_ci	 * ptype=0x14 or zbc=XXX.
67758c2ecf20Sopenharmony_ci	 */
67768c2ecf20Sopenharmony_ci	if (sdebug_ptype == TYPE_ZBC) {
67778c2ecf20Sopenharmony_ci		sdeb_zbc_model = BLK_ZONED_HM;
67788c2ecf20Sopenharmony_ci	} else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) {
67798c2ecf20Sopenharmony_ci		k = sdeb_zbc_model_str(sdeb_zbc_model_s);
67808c2ecf20Sopenharmony_ci		if (k < 0) {
67818c2ecf20Sopenharmony_ci			ret = k;
67828c2ecf20Sopenharmony_ci			goto free_q_arr;
67838c2ecf20Sopenharmony_ci		}
67848c2ecf20Sopenharmony_ci		sdeb_zbc_model = k;
67858c2ecf20Sopenharmony_ci		switch (sdeb_zbc_model) {
67868c2ecf20Sopenharmony_ci		case BLK_ZONED_NONE:
67878c2ecf20Sopenharmony_ci		case BLK_ZONED_HA:
67888c2ecf20Sopenharmony_ci			sdebug_ptype = TYPE_DISK;
67898c2ecf20Sopenharmony_ci			break;
67908c2ecf20Sopenharmony_ci		case BLK_ZONED_HM:
67918c2ecf20Sopenharmony_ci			sdebug_ptype = TYPE_ZBC;
67928c2ecf20Sopenharmony_ci			break;
67938c2ecf20Sopenharmony_ci		default:
67948c2ecf20Sopenharmony_ci			pr_err("Invalid ZBC model\n");
67958c2ecf20Sopenharmony_ci			ret = -EINVAL;
67968c2ecf20Sopenharmony_ci			goto free_q_arr;
67978c2ecf20Sopenharmony_ci		}
67988c2ecf20Sopenharmony_ci	}
67998c2ecf20Sopenharmony_ci	if (sdeb_zbc_model != BLK_ZONED_NONE) {
68008c2ecf20Sopenharmony_ci		sdeb_zbc_in_use = true;
68018c2ecf20Sopenharmony_ci		if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
68028c2ecf20Sopenharmony_ci			sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB;
68038c2ecf20Sopenharmony_ci	}
68048c2ecf20Sopenharmony_ci
68058c2ecf20Sopenharmony_ci	if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT)
68068c2ecf20Sopenharmony_ci		sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
68078c2ecf20Sopenharmony_ci	if (sdebug_dev_size_mb < 1)
68088c2ecf20Sopenharmony_ci		sdebug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
68098c2ecf20Sopenharmony_ci	sz = (unsigned long)sdebug_dev_size_mb * 1048576;
68108c2ecf20Sopenharmony_ci	sdebug_store_sectors = sz / sdebug_sector_size;
68118c2ecf20Sopenharmony_ci	sdebug_capacity = get_sdebug_capacity();
68128c2ecf20Sopenharmony_ci
68138c2ecf20Sopenharmony_ci	/* play around with geometry, don't waste too much on track 0 */
68148c2ecf20Sopenharmony_ci	sdebug_heads = 8;
68158c2ecf20Sopenharmony_ci	sdebug_sectors_per = 32;
68168c2ecf20Sopenharmony_ci	if (sdebug_dev_size_mb >= 256)
68178c2ecf20Sopenharmony_ci		sdebug_heads = 64;
68188c2ecf20Sopenharmony_ci	else if (sdebug_dev_size_mb >= 16)
68198c2ecf20Sopenharmony_ci		sdebug_heads = 32;
68208c2ecf20Sopenharmony_ci	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
68218c2ecf20Sopenharmony_ci			       (sdebug_sectors_per * sdebug_heads);
68228c2ecf20Sopenharmony_ci	if (sdebug_cylinders_per >= 1024) {
68238c2ecf20Sopenharmony_ci		/* other LLDs do this; implies >= 1GB ram disk ... */
68248c2ecf20Sopenharmony_ci		sdebug_heads = 255;
68258c2ecf20Sopenharmony_ci		sdebug_sectors_per = 63;
68268c2ecf20Sopenharmony_ci		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
68278c2ecf20Sopenharmony_ci			       (sdebug_sectors_per * sdebug_heads);
68288c2ecf20Sopenharmony_ci	}
68298c2ecf20Sopenharmony_ci	if (scsi_debug_lbp()) {
68308c2ecf20Sopenharmony_ci		sdebug_unmap_max_blocks =
68318c2ecf20Sopenharmony_ci			clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
68328c2ecf20Sopenharmony_ci
68338c2ecf20Sopenharmony_ci		sdebug_unmap_max_desc =
68348c2ecf20Sopenharmony_ci			clamp(sdebug_unmap_max_desc, 0U, 256U);
68358c2ecf20Sopenharmony_ci
68368c2ecf20Sopenharmony_ci		sdebug_unmap_granularity =
68378c2ecf20Sopenharmony_ci			clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
68388c2ecf20Sopenharmony_ci
68398c2ecf20Sopenharmony_ci		if (sdebug_unmap_alignment &&
68408c2ecf20Sopenharmony_ci		    sdebug_unmap_granularity <=
68418c2ecf20Sopenharmony_ci		    sdebug_unmap_alignment) {
68428c2ecf20Sopenharmony_ci			pr_err("ERR: unmap_granularity <= unmap_alignment\n");
68438c2ecf20Sopenharmony_ci			ret = -EINVAL;
68448c2ecf20Sopenharmony_ci			goto free_q_arr;
68458c2ecf20Sopenharmony_ci		}
68468c2ecf20Sopenharmony_ci	}
68478c2ecf20Sopenharmony_ci	xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ);
68488c2ecf20Sopenharmony_ci	if (want_store) {
68498c2ecf20Sopenharmony_ci		idx = sdebug_add_store();
68508c2ecf20Sopenharmony_ci		if (idx < 0) {
68518c2ecf20Sopenharmony_ci			ret = idx;
68528c2ecf20Sopenharmony_ci			goto free_q_arr;
68538c2ecf20Sopenharmony_ci		}
68548c2ecf20Sopenharmony_ci	}
68558c2ecf20Sopenharmony_ci
68568c2ecf20Sopenharmony_ci	pseudo_primary = root_device_register("pseudo_0");
68578c2ecf20Sopenharmony_ci	if (IS_ERR(pseudo_primary)) {
68588c2ecf20Sopenharmony_ci		pr_warn("root_device_register() error\n");
68598c2ecf20Sopenharmony_ci		ret = PTR_ERR(pseudo_primary);
68608c2ecf20Sopenharmony_ci		goto free_vm;
68618c2ecf20Sopenharmony_ci	}
68628c2ecf20Sopenharmony_ci	ret = bus_register(&pseudo_lld_bus);
68638c2ecf20Sopenharmony_ci	if (ret < 0) {
68648c2ecf20Sopenharmony_ci		pr_warn("bus_register error: %d\n", ret);
68658c2ecf20Sopenharmony_ci		goto dev_unreg;
68668c2ecf20Sopenharmony_ci	}
68678c2ecf20Sopenharmony_ci	ret = driver_register(&sdebug_driverfs_driver);
68688c2ecf20Sopenharmony_ci	if (ret < 0) {
68698c2ecf20Sopenharmony_ci		pr_warn("driver_register error: %d\n", ret);
68708c2ecf20Sopenharmony_ci		goto bus_unreg;
68718c2ecf20Sopenharmony_ci	}
68728c2ecf20Sopenharmony_ci
68738c2ecf20Sopenharmony_ci	hosts_to_add = sdebug_add_host;
68748c2ecf20Sopenharmony_ci	sdebug_add_host = 0;
68758c2ecf20Sopenharmony_ci
68768c2ecf20Sopenharmony_ci	for (k = 0; k < hosts_to_add; k++) {
68778c2ecf20Sopenharmony_ci		if (want_store && k == 0) {
68788c2ecf20Sopenharmony_ci			ret = sdebug_add_host_helper(idx);
68798c2ecf20Sopenharmony_ci			if (ret < 0) {
68808c2ecf20Sopenharmony_ci				pr_err("add_host_helper k=%d, error=%d\n",
68818c2ecf20Sopenharmony_ci				       k, -ret);
68828c2ecf20Sopenharmony_ci				break;
68838c2ecf20Sopenharmony_ci			}
68848c2ecf20Sopenharmony_ci		} else {
68858c2ecf20Sopenharmony_ci			ret = sdebug_do_add_host(want_store &&
68868c2ecf20Sopenharmony_ci						 sdebug_per_host_store);
68878c2ecf20Sopenharmony_ci			if (ret < 0) {
68888c2ecf20Sopenharmony_ci				pr_err("add_host k=%d error=%d\n", k, -ret);
68898c2ecf20Sopenharmony_ci				break;
68908c2ecf20Sopenharmony_ci			}
68918c2ecf20Sopenharmony_ci		}
68928c2ecf20Sopenharmony_ci	}
68938c2ecf20Sopenharmony_ci	if (sdebug_verbose)
68948c2ecf20Sopenharmony_ci		pr_info("built %d host(s)\n", sdebug_num_hosts);
68958c2ecf20Sopenharmony_ci
68968c2ecf20Sopenharmony_ci	return 0;
68978c2ecf20Sopenharmony_ci
68988c2ecf20Sopenharmony_cibus_unreg:
68998c2ecf20Sopenharmony_ci	bus_unregister(&pseudo_lld_bus);
69008c2ecf20Sopenharmony_cidev_unreg:
69018c2ecf20Sopenharmony_ci	root_device_unregister(pseudo_primary);
69028c2ecf20Sopenharmony_cifree_vm:
69038c2ecf20Sopenharmony_ci	sdebug_erase_store(idx, NULL);
69048c2ecf20Sopenharmony_cifree_q_arr:
69058c2ecf20Sopenharmony_ci	kfree(sdebug_q_arr);
69068c2ecf20Sopenharmony_ci	return ret;
69078c2ecf20Sopenharmony_ci}
69088c2ecf20Sopenharmony_ci
69098c2ecf20Sopenharmony_cistatic void __exit scsi_debug_exit(void)
69108c2ecf20Sopenharmony_ci{
69118c2ecf20Sopenharmony_ci	int k = sdebug_num_hosts;
69128c2ecf20Sopenharmony_ci
69138c2ecf20Sopenharmony_ci	stop_all_queued();
69148c2ecf20Sopenharmony_ci	for (; k; k--)
69158c2ecf20Sopenharmony_ci		sdebug_do_remove_host(true);
69168c2ecf20Sopenharmony_ci	free_all_queued();
69178c2ecf20Sopenharmony_ci	driver_unregister(&sdebug_driverfs_driver);
69188c2ecf20Sopenharmony_ci	bus_unregister(&pseudo_lld_bus);
69198c2ecf20Sopenharmony_ci	root_device_unregister(pseudo_primary);
69208c2ecf20Sopenharmony_ci
69218c2ecf20Sopenharmony_ci	sdebug_erase_all_stores(false);
69228c2ecf20Sopenharmony_ci	xa_destroy(per_store_ap);
69238c2ecf20Sopenharmony_ci	kfree(sdebug_q_arr);
69248c2ecf20Sopenharmony_ci}
69258c2ecf20Sopenharmony_ci
69268c2ecf20Sopenharmony_cidevice_initcall(scsi_debug_init);
69278c2ecf20Sopenharmony_cimodule_exit(scsi_debug_exit);
69288c2ecf20Sopenharmony_ci
69298c2ecf20Sopenharmony_cistatic void sdebug_release_adapter(struct device *dev)
69308c2ecf20Sopenharmony_ci{
69318c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
69328c2ecf20Sopenharmony_ci
69338c2ecf20Sopenharmony_ci	sdbg_host = to_sdebug_host(dev);
69348c2ecf20Sopenharmony_ci	kfree(sdbg_host);
69358c2ecf20Sopenharmony_ci}
69368c2ecf20Sopenharmony_ci
69378c2ecf20Sopenharmony_ci/* idx must be valid, if sip is NULL then it will be obtained using idx */
69388c2ecf20Sopenharmony_cistatic void sdebug_erase_store(int idx, struct sdeb_store_info *sip)
69398c2ecf20Sopenharmony_ci{
69408c2ecf20Sopenharmony_ci	if (idx < 0)
69418c2ecf20Sopenharmony_ci		return;
69428c2ecf20Sopenharmony_ci	if (!sip) {
69438c2ecf20Sopenharmony_ci		if (xa_empty(per_store_ap))
69448c2ecf20Sopenharmony_ci			return;
69458c2ecf20Sopenharmony_ci		sip = xa_load(per_store_ap, idx);
69468c2ecf20Sopenharmony_ci		if (!sip)
69478c2ecf20Sopenharmony_ci			return;
69488c2ecf20Sopenharmony_ci	}
69498c2ecf20Sopenharmony_ci	vfree(sip->map_storep);
69508c2ecf20Sopenharmony_ci	vfree(sip->dif_storep);
69518c2ecf20Sopenharmony_ci	vfree(sip->storep);
69528c2ecf20Sopenharmony_ci	xa_erase(per_store_ap, idx);
69538c2ecf20Sopenharmony_ci	kfree(sip);
69548c2ecf20Sopenharmony_ci}
69558c2ecf20Sopenharmony_ci
69568c2ecf20Sopenharmony_ci/* Assume apart_from_first==false only in shutdown case. */
69578c2ecf20Sopenharmony_cistatic void sdebug_erase_all_stores(bool apart_from_first)
69588c2ecf20Sopenharmony_ci{
69598c2ecf20Sopenharmony_ci	unsigned long idx;
69608c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = NULL;
69618c2ecf20Sopenharmony_ci
69628c2ecf20Sopenharmony_ci	xa_for_each(per_store_ap, idx, sip) {
69638c2ecf20Sopenharmony_ci		if (apart_from_first)
69648c2ecf20Sopenharmony_ci			apart_from_first = false;
69658c2ecf20Sopenharmony_ci		else
69668c2ecf20Sopenharmony_ci			sdebug_erase_store(idx, sip);
69678c2ecf20Sopenharmony_ci	}
69688c2ecf20Sopenharmony_ci	if (apart_from_first)
69698c2ecf20Sopenharmony_ci		sdeb_most_recent_idx = sdeb_first_idx;
69708c2ecf20Sopenharmony_ci}
69718c2ecf20Sopenharmony_ci
69728c2ecf20Sopenharmony_ci/*
69738c2ecf20Sopenharmony_ci * Returns store xarray new element index (idx) if >=0 else negated errno.
69748c2ecf20Sopenharmony_ci * Limit the number of stores to 65536.
69758c2ecf20Sopenharmony_ci */
69768c2ecf20Sopenharmony_cistatic int sdebug_add_store(void)
69778c2ecf20Sopenharmony_ci{
69788c2ecf20Sopenharmony_ci	int res;
69798c2ecf20Sopenharmony_ci	u32 n_idx;
69808c2ecf20Sopenharmony_ci	unsigned long iflags;
69818c2ecf20Sopenharmony_ci	unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576;
69828c2ecf20Sopenharmony_ci	struct sdeb_store_info *sip = NULL;
69838c2ecf20Sopenharmony_ci	struct xa_limit xal = { .max = 1 << 16, .min = 0 };
69848c2ecf20Sopenharmony_ci
69858c2ecf20Sopenharmony_ci	sip = kzalloc(sizeof(*sip), GFP_KERNEL);
69868c2ecf20Sopenharmony_ci	if (!sip)
69878c2ecf20Sopenharmony_ci		return -ENOMEM;
69888c2ecf20Sopenharmony_ci
69898c2ecf20Sopenharmony_ci	xa_lock_irqsave(per_store_ap, iflags);
69908c2ecf20Sopenharmony_ci	res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC);
69918c2ecf20Sopenharmony_ci	if (unlikely(res < 0)) {
69928c2ecf20Sopenharmony_ci		xa_unlock_irqrestore(per_store_ap, iflags);
69938c2ecf20Sopenharmony_ci		kfree(sip);
69948c2ecf20Sopenharmony_ci		pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res);
69958c2ecf20Sopenharmony_ci		return res;
69968c2ecf20Sopenharmony_ci	}
69978c2ecf20Sopenharmony_ci	sdeb_most_recent_idx = n_idx;
69988c2ecf20Sopenharmony_ci	if (sdeb_first_idx < 0)
69998c2ecf20Sopenharmony_ci		sdeb_first_idx = n_idx;
70008c2ecf20Sopenharmony_ci	xa_unlock_irqrestore(per_store_ap, iflags);
70018c2ecf20Sopenharmony_ci
70028c2ecf20Sopenharmony_ci	res = -ENOMEM;
70038c2ecf20Sopenharmony_ci	sip->storep = vzalloc(sz);
70048c2ecf20Sopenharmony_ci	if (!sip->storep) {
70058c2ecf20Sopenharmony_ci		pr_err("user data oom\n");
70068c2ecf20Sopenharmony_ci		goto err;
70078c2ecf20Sopenharmony_ci	}
70088c2ecf20Sopenharmony_ci	if (sdebug_num_parts > 0)
70098c2ecf20Sopenharmony_ci		sdebug_build_parts(sip->storep, sz);
70108c2ecf20Sopenharmony_ci
70118c2ecf20Sopenharmony_ci	/* DIF/DIX: what T10 calls Protection Information (PI) */
70128c2ecf20Sopenharmony_ci	if (sdebug_dix) {
70138c2ecf20Sopenharmony_ci		int dif_size;
70148c2ecf20Sopenharmony_ci
70158c2ecf20Sopenharmony_ci		dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
70168c2ecf20Sopenharmony_ci		sip->dif_storep = vmalloc(dif_size);
70178c2ecf20Sopenharmony_ci
70188c2ecf20Sopenharmony_ci		pr_info("dif_storep %u bytes @ %pK\n", dif_size,
70198c2ecf20Sopenharmony_ci			sip->dif_storep);
70208c2ecf20Sopenharmony_ci
70218c2ecf20Sopenharmony_ci		if (!sip->dif_storep) {
70228c2ecf20Sopenharmony_ci			pr_err("DIX oom\n");
70238c2ecf20Sopenharmony_ci			goto err;
70248c2ecf20Sopenharmony_ci		}
70258c2ecf20Sopenharmony_ci		memset(sip->dif_storep, 0xff, dif_size);
70268c2ecf20Sopenharmony_ci	}
70278c2ecf20Sopenharmony_ci	/* Logical Block Provisioning */
70288c2ecf20Sopenharmony_ci	if (scsi_debug_lbp()) {
70298c2ecf20Sopenharmony_ci		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
70308c2ecf20Sopenharmony_ci		sip->map_storep = vmalloc(array_size(sizeof(long),
70318c2ecf20Sopenharmony_ci						     BITS_TO_LONGS(map_size)));
70328c2ecf20Sopenharmony_ci
70338c2ecf20Sopenharmony_ci		pr_info("%lu provisioning blocks\n", map_size);
70348c2ecf20Sopenharmony_ci
70358c2ecf20Sopenharmony_ci		if (!sip->map_storep) {
70368c2ecf20Sopenharmony_ci			pr_err("LBP map oom\n");
70378c2ecf20Sopenharmony_ci			goto err;
70388c2ecf20Sopenharmony_ci		}
70398c2ecf20Sopenharmony_ci
70408c2ecf20Sopenharmony_ci		bitmap_zero(sip->map_storep, map_size);
70418c2ecf20Sopenharmony_ci
70428c2ecf20Sopenharmony_ci		/* Map first 1KB for partition table */
70438c2ecf20Sopenharmony_ci		if (sdebug_num_parts)
70448c2ecf20Sopenharmony_ci			map_region(sip, 0, 2);
70458c2ecf20Sopenharmony_ci	}
70468c2ecf20Sopenharmony_ci
70478c2ecf20Sopenharmony_ci	rwlock_init(&sip->macc_lck);
70488c2ecf20Sopenharmony_ci	return (int)n_idx;
70498c2ecf20Sopenharmony_cierr:
70508c2ecf20Sopenharmony_ci	sdebug_erase_store((int)n_idx, sip);
70518c2ecf20Sopenharmony_ci	pr_warn("%s: failed, errno=%d\n", __func__, -res);
70528c2ecf20Sopenharmony_ci	return res;
70538c2ecf20Sopenharmony_ci}
70548c2ecf20Sopenharmony_ci
70558c2ecf20Sopenharmony_cistatic int sdebug_add_host_helper(int per_host_idx)
70568c2ecf20Sopenharmony_ci{
70578c2ecf20Sopenharmony_ci	int k, devs_per_host, idx;
70588c2ecf20Sopenharmony_ci	int error = -ENOMEM;
70598c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
70608c2ecf20Sopenharmony_ci	struct sdebug_dev_info *sdbg_devinfo, *tmp;
70618c2ecf20Sopenharmony_ci
70628c2ecf20Sopenharmony_ci	sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
70638c2ecf20Sopenharmony_ci	if (!sdbg_host)
70648c2ecf20Sopenharmony_ci		return -ENOMEM;
70658c2ecf20Sopenharmony_ci	idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx;
70668c2ecf20Sopenharmony_ci	if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE))
70678c2ecf20Sopenharmony_ci		xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
70688c2ecf20Sopenharmony_ci	sdbg_host->si_idx = idx;
70698c2ecf20Sopenharmony_ci
70708c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sdbg_host->dev_info_list);
70718c2ecf20Sopenharmony_ci
70728c2ecf20Sopenharmony_ci	devs_per_host = sdebug_num_tgts * sdebug_max_luns;
70738c2ecf20Sopenharmony_ci	for (k = 0; k < devs_per_host; k++) {
70748c2ecf20Sopenharmony_ci		sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
70758c2ecf20Sopenharmony_ci		if (!sdbg_devinfo)
70768c2ecf20Sopenharmony_ci			goto clean;
70778c2ecf20Sopenharmony_ci	}
70788c2ecf20Sopenharmony_ci
70798c2ecf20Sopenharmony_ci	spin_lock(&sdebug_host_list_lock);
70808c2ecf20Sopenharmony_ci	list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
70818c2ecf20Sopenharmony_ci	spin_unlock(&sdebug_host_list_lock);
70828c2ecf20Sopenharmony_ci
70838c2ecf20Sopenharmony_ci	sdbg_host->dev.bus = &pseudo_lld_bus;
70848c2ecf20Sopenharmony_ci	sdbg_host->dev.parent = pseudo_primary;
70858c2ecf20Sopenharmony_ci	sdbg_host->dev.release = &sdebug_release_adapter;
70868c2ecf20Sopenharmony_ci	dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
70878c2ecf20Sopenharmony_ci
70888c2ecf20Sopenharmony_ci	error = device_register(&sdbg_host->dev);
70898c2ecf20Sopenharmony_ci	if (error) {
70908c2ecf20Sopenharmony_ci		spin_lock(&sdebug_host_list_lock);
70918c2ecf20Sopenharmony_ci		list_del(&sdbg_host->host_list);
70928c2ecf20Sopenharmony_ci		spin_unlock(&sdebug_host_list_lock);
70938c2ecf20Sopenharmony_ci		goto clean;
70948c2ecf20Sopenharmony_ci	}
70958c2ecf20Sopenharmony_ci
70968c2ecf20Sopenharmony_ci	++sdebug_num_hosts;
70978c2ecf20Sopenharmony_ci	return 0;
70988c2ecf20Sopenharmony_ci
70998c2ecf20Sopenharmony_ciclean:
71008c2ecf20Sopenharmony_ci	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
71018c2ecf20Sopenharmony_ci				 dev_list) {
71028c2ecf20Sopenharmony_ci		list_del(&sdbg_devinfo->dev_list);
71038c2ecf20Sopenharmony_ci		kfree(sdbg_devinfo->zstate);
71048c2ecf20Sopenharmony_ci		kfree(sdbg_devinfo);
71058c2ecf20Sopenharmony_ci	}
71068c2ecf20Sopenharmony_ci	if (sdbg_host->dev.release)
71078c2ecf20Sopenharmony_ci		put_device(&sdbg_host->dev);
71088c2ecf20Sopenharmony_ci	else
71098c2ecf20Sopenharmony_ci		kfree(sdbg_host);
71108c2ecf20Sopenharmony_ci	pr_warn("%s: failed, errno=%d\n", __func__, -error);
71118c2ecf20Sopenharmony_ci	return error;
71128c2ecf20Sopenharmony_ci}
71138c2ecf20Sopenharmony_ci
71148c2ecf20Sopenharmony_cistatic int sdebug_do_add_host(bool mk_new_store)
71158c2ecf20Sopenharmony_ci{
71168c2ecf20Sopenharmony_ci	int ph_idx = sdeb_most_recent_idx;
71178c2ecf20Sopenharmony_ci
71188c2ecf20Sopenharmony_ci	if (mk_new_store) {
71198c2ecf20Sopenharmony_ci		ph_idx = sdebug_add_store();
71208c2ecf20Sopenharmony_ci		if (ph_idx < 0)
71218c2ecf20Sopenharmony_ci			return ph_idx;
71228c2ecf20Sopenharmony_ci	}
71238c2ecf20Sopenharmony_ci	return sdebug_add_host_helper(ph_idx);
71248c2ecf20Sopenharmony_ci}
71258c2ecf20Sopenharmony_ci
71268c2ecf20Sopenharmony_cistatic void sdebug_do_remove_host(bool the_end)
71278c2ecf20Sopenharmony_ci{
71288c2ecf20Sopenharmony_ci	int idx = -1;
71298c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host = NULL;
71308c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host2;
71318c2ecf20Sopenharmony_ci
71328c2ecf20Sopenharmony_ci	spin_lock(&sdebug_host_list_lock);
71338c2ecf20Sopenharmony_ci	if (!list_empty(&sdebug_host_list)) {
71348c2ecf20Sopenharmony_ci		sdbg_host = list_entry(sdebug_host_list.prev,
71358c2ecf20Sopenharmony_ci				       struct sdebug_host_info, host_list);
71368c2ecf20Sopenharmony_ci		idx = sdbg_host->si_idx;
71378c2ecf20Sopenharmony_ci	}
71388c2ecf20Sopenharmony_ci	if (!the_end && idx >= 0) {
71398c2ecf20Sopenharmony_ci		bool unique = true;
71408c2ecf20Sopenharmony_ci
71418c2ecf20Sopenharmony_ci		list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) {
71428c2ecf20Sopenharmony_ci			if (sdbg_host2 == sdbg_host)
71438c2ecf20Sopenharmony_ci				continue;
71448c2ecf20Sopenharmony_ci			if (idx == sdbg_host2->si_idx) {
71458c2ecf20Sopenharmony_ci				unique = false;
71468c2ecf20Sopenharmony_ci				break;
71478c2ecf20Sopenharmony_ci			}
71488c2ecf20Sopenharmony_ci		}
71498c2ecf20Sopenharmony_ci		if (unique) {
71508c2ecf20Sopenharmony_ci			xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE);
71518c2ecf20Sopenharmony_ci			if (idx == sdeb_most_recent_idx)
71528c2ecf20Sopenharmony_ci				--sdeb_most_recent_idx;
71538c2ecf20Sopenharmony_ci		}
71548c2ecf20Sopenharmony_ci	}
71558c2ecf20Sopenharmony_ci	if (sdbg_host)
71568c2ecf20Sopenharmony_ci		list_del(&sdbg_host->host_list);
71578c2ecf20Sopenharmony_ci	spin_unlock(&sdebug_host_list_lock);
71588c2ecf20Sopenharmony_ci
71598c2ecf20Sopenharmony_ci	if (!sdbg_host)
71608c2ecf20Sopenharmony_ci		return;
71618c2ecf20Sopenharmony_ci
71628c2ecf20Sopenharmony_ci	device_unregister(&sdbg_host->dev);
71638c2ecf20Sopenharmony_ci	--sdebug_num_hosts;
71648c2ecf20Sopenharmony_ci}
71658c2ecf20Sopenharmony_ci
71668c2ecf20Sopenharmony_cistatic int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
71678c2ecf20Sopenharmony_ci{
71688c2ecf20Sopenharmony_ci	int num_in_q = 0;
71698c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
71708c2ecf20Sopenharmony_ci
71718c2ecf20Sopenharmony_ci	block_unblock_all_queues(true);
71728c2ecf20Sopenharmony_ci	devip = (struct sdebug_dev_info *)sdev->hostdata;
71738c2ecf20Sopenharmony_ci	if (NULL == devip) {
71748c2ecf20Sopenharmony_ci		block_unblock_all_queues(false);
71758c2ecf20Sopenharmony_ci		return	-ENODEV;
71768c2ecf20Sopenharmony_ci	}
71778c2ecf20Sopenharmony_ci	num_in_q = atomic_read(&devip->num_in_q);
71788c2ecf20Sopenharmony_ci
71798c2ecf20Sopenharmony_ci	if (qdepth < 1)
71808c2ecf20Sopenharmony_ci		qdepth = 1;
71818c2ecf20Sopenharmony_ci	/* allow to exceed max host qc_arr elements for testing */
71828c2ecf20Sopenharmony_ci	if (qdepth > SDEBUG_CANQUEUE + 10)
71838c2ecf20Sopenharmony_ci		qdepth = SDEBUG_CANQUEUE + 10;
71848c2ecf20Sopenharmony_ci	scsi_change_queue_depth(sdev, qdepth);
71858c2ecf20Sopenharmony_ci
71868c2ecf20Sopenharmony_ci	if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
71878c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
71888c2ecf20Sopenharmony_ci			    __func__, qdepth, num_in_q);
71898c2ecf20Sopenharmony_ci	}
71908c2ecf20Sopenharmony_ci	block_unblock_all_queues(false);
71918c2ecf20Sopenharmony_ci	return sdev->queue_depth;
71928c2ecf20Sopenharmony_ci}
71938c2ecf20Sopenharmony_ci
71948c2ecf20Sopenharmony_cistatic bool fake_timeout(struct scsi_cmnd *scp)
71958c2ecf20Sopenharmony_ci{
71968c2ecf20Sopenharmony_ci	if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
71978c2ecf20Sopenharmony_ci		if (sdebug_every_nth < -1)
71988c2ecf20Sopenharmony_ci			sdebug_every_nth = -1;
71998c2ecf20Sopenharmony_ci		if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
72008c2ecf20Sopenharmony_ci			return true; /* ignore command causing timeout */
72018c2ecf20Sopenharmony_ci		else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
72028c2ecf20Sopenharmony_ci			 scsi_medium_access_command(scp))
72038c2ecf20Sopenharmony_ci			return true; /* time out reads and writes */
72048c2ecf20Sopenharmony_ci	}
72058c2ecf20Sopenharmony_ci	return false;
72068c2ecf20Sopenharmony_ci}
72078c2ecf20Sopenharmony_ci
72088c2ecf20Sopenharmony_ci/* Response to TUR or media access command when device stopped */
72098c2ecf20Sopenharmony_cistatic int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
72108c2ecf20Sopenharmony_ci{
72118c2ecf20Sopenharmony_ci	int stopped_state;
72128c2ecf20Sopenharmony_ci	u64 diff_ns = 0;
72138c2ecf20Sopenharmony_ci	ktime_t now_ts = ktime_get_boottime();
72148c2ecf20Sopenharmony_ci	struct scsi_device *sdp = scp->device;
72158c2ecf20Sopenharmony_ci
72168c2ecf20Sopenharmony_ci	stopped_state = atomic_read(&devip->stopped);
72178c2ecf20Sopenharmony_ci	if (stopped_state == 2) {
72188c2ecf20Sopenharmony_ci		if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) {
72198c2ecf20Sopenharmony_ci			diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts));
72208c2ecf20Sopenharmony_ci			if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) {
72218c2ecf20Sopenharmony_ci				/* tur_ms_to_ready timer extinguished */
72228c2ecf20Sopenharmony_ci				atomic_set(&devip->stopped, 0);
72238c2ecf20Sopenharmony_ci				return 0;
72248c2ecf20Sopenharmony_ci			}
72258c2ecf20Sopenharmony_ci		}
72268c2ecf20Sopenharmony_ci		mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1);
72278c2ecf20Sopenharmony_ci		if (sdebug_verbose)
72288c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, sdp,
72298c2ecf20Sopenharmony_ci				    "%s: Not ready: in process of becoming ready\n", my_name);
72308c2ecf20Sopenharmony_ci		if (scp->cmnd[0] == TEST_UNIT_READY) {
72318c2ecf20Sopenharmony_ci			u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000;
72328c2ecf20Sopenharmony_ci
72338c2ecf20Sopenharmony_ci			if (diff_ns <= tur_nanosecs_to_ready)
72348c2ecf20Sopenharmony_ci				diff_ns = tur_nanosecs_to_ready - diff_ns;
72358c2ecf20Sopenharmony_ci			else
72368c2ecf20Sopenharmony_ci				diff_ns = tur_nanosecs_to_ready;
72378c2ecf20Sopenharmony_ci			/* As per 20-061r2 approved for spc6 by T10 on 20200716 */
72388c2ecf20Sopenharmony_ci			do_div(diff_ns, 1000000);	/* diff_ns becomes milliseconds */
72398c2ecf20Sopenharmony_ci			scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE,
72408c2ecf20Sopenharmony_ci						   diff_ns);
72418c2ecf20Sopenharmony_ci			return check_condition_result;
72428c2ecf20Sopenharmony_ci		}
72438c2ecf20Sopenharmony_ci	}
72448c2ecf20Sopenharmony_ci	mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
72458c2ecf20Sopenharmony_ci	if (sdebug_verbose)
72468c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n",
72478c2ecf20Sopenharmony_ci			    my_name);
72488c2ecf20Sopenharmony_ci	return check_condition_result;
72498c2ecf20Sopenharmony_ci}
72508c2ecf20Sopenharmony_ci
72518c2ecf20Sopenharmony_cistatic int scsi_debug_queuecommand(struct Scsi_Host *shost,
72528c2ecf20Sopenharmony_ci				   struct scsi_cmnd *scp)
72538c2ecf20Sopenharmony_ci{
72548c2ecf20Sopenharmony_ci	u8 sdeb_i;
72558c2ecf20Sopenharmony_ci	struct scsi_device *sdp = scp->device;
72568c2ecf20Sopenharmony_ci	const struct opcode_info_t *oip;
72578c2ecf20Sopenharmony_ci	const struct opcode_info_t *r_oip;
72588c2ecf20Sopenharmony_ci	struct sdebug_dev_info *devip;
72598c2ecf20Sopenharmony_ci	u8 *cmd = scp->cmnd;
72608c2ecf20Sopenharmony_ci	int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
72618c2ecf20Sopenharmony_ci	int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
72628c2ecf20Sopenharmony_ci	int k, na;
72638c2ecf20Sopenharmony_ci	int errsts = 0;
72648c2ecf20Sopenharmony_ci	u64 lun_index = sdp->lun & 0x3FFF;
72658c2ecf20Sopenharmony_ci	u32 flags;
72668c2ecf20Sopenharmony_ci	u16 sa;
72678c2ecf20Sopenharmony_ci	u8 opcode = cmd[0];
72688c2ecf20Sopenharmony_ci	bool has_wlun_rl;
72698c2ecf20Sopenharmony_ci	bool inject_now;
72708c2ecf20Sopenharmony_ci
72718c2ecf20Sopenharmony_ci	scsi_set_resid(scp, 0);
72728c2ecf20Sopenharmony_ci	if (sdebug_statistics) {
72738c2ecf20Sopenharmony_ci		atomic_inc(&sdebug_cmnd_count);
72748c2ecf20Sopenharmony_ci		inject_now = inject_on_this_cmd();
72758c2ecf20Sopenharmony_ci	} else {
72768c2ecf20Sopenharmony_ci		inject_now = false;
72778c2ecf20Sopenharmony_ci	}
72788c2ecf20Sopenharmony_ci	if (unlikely(sdebug_verbose &&
72798c2ecf20Sopenharmony_ci		     !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
72808c2ecf20Sopenharmony_ci		char b[120];
72818c2ecf20Sopenharmony_ci		int n, len, sb;
72828c2ecf20Sopenharmony_ci
72838c2ecf20Sopenharmony_ci		len = scp->cmd_len;
72848c2ecf20Sopenharmony_ci		sb = (int)sizeof(b);
72858c2ecf20Sopenharmony_ci		if (len > 32)
72868c2ecf20Sopenharmony_ci			strcpy(b, "too long, over 32 bytes");
72878c2ecf20Sopenharmony_ci		else {
72888c2ecf20Sopenharmony_ci			for (k = 0, n = 0; k < len && n < sb; ++k)
72898c2ecf20Sopenharmony_ci				n += scnprintf(b + n, sb - n, "%02x ",
72908c2ecf20Sopenharmony_ci					       (u32)cmd[k]);
72918c2ecf20Sopenharmony_ci		}
72928c2ecf20Sopenharmony_ci		sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
72938c2ecf20Sopenharmony_ci			    blk_mq_unique_tag(scp->request), b);
72948c2ecf20Sopenharmony_ci	}
72958c2ecf20Sopenharmony_ci	if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY)))
72968c2ecf20Sopenharmony_ci		return SCSI_MLQUEUE_HOST_BUSY;
72978c2ecf20Sopenharmony_ci	has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
72988c2ecf20Sopenharmony_ci	if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl))
72998c2ecf20Sopenharmony_ci		goto err_out;
73008c2ecf20Sopenharmony_ci
73018c2ecf20Sopenharmony_ci	sdeb_i = opcode_ind_arr[opcode];	/* fully mapped */
73028c2ecf20Sopenharmony_ci	oip = &opcode_info_arr[sdeb_i];		/* safe if table consistent */
73038c2ecf20Sopenharmony_ci	devip = (struct sdebug_dev_info *)sdp->hostdata;
73048c2ecf20Sopenharmony_ci	if (unlikely(!devip)) {
73058c2ecf20Sopenharmony_ci		devip = find_build_dev_info(sdp);
73068c2ecf20Sopenharmony_ci		if (NULL == devip)
73078c2ecf20Sopenharmony_ci			goto err_out;
73088c2ecf20Sopenharmony_ci	}
73098c2ecf20Sopenharmony_ci	if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending)))
73108c2ecf20Sopenharmony_ci		atomic_set(&sdeb_inject_pending, 1);
73118c2ecf20Sopenharmony_ci
73128c2ecf20Sopenharmony_ci	na = oip->num_attached;
73138c2ecf20Sopenharmony_ci	r_pfp = oip->pfp;
73148c2ecf20Sopenharmony_ci	if (na) {	/* multiple commands with this opcode */
73158c2ecf20Sopenharmony_ci		r_oip = oip;
73168c2ecf20Sopenharmony_ci		if (FF_SA & r_oip->flags) {
73178c2ecf20Sopenharmony_ci			if (F_SA_LOW & oip->flags)
73188c2ecf20Sopenharmony_ci				sa = 0x1f & cmd[1];
73198c2ecf20Sopenharmony_ci			else
73208c2ecf20Sopenharmony_ci				sa = get_unaligned_be16(cmd + 8);
73218c2ecf20Sopenharmony_ci			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
73228c2ecf20Sopenharmony_ci				if (opcode == oip->opcode && sa == oip->sa)
73238c2ecf20Sopenharmony_ci					break;
73248c2ecf20Sopenharmony_ci			}
73258c2ecf20Sopenharmony_ci		} else {   /* since no service action only check opcode */
73268c2ecf20Sopenharmony_ci			for (k = 0; k <= na; oip = r_oip->arrp + k++) {
73278c2ecf20Sopenharmony_ci				if (opcode == oip->opcode)
73288c2ecf20Sopenharmony_ci					break;
73298c2ecf20Sopenharmony_ci			}
73308c2ecf20Sopenharmony_ci		}
73318c2ecf20Sopenharmony_ci		if (k > na) {
73328c2ecf20Sopenharmony_ci			if (F_SA_LOW & r_oip->flags)
73338c2ecf20Sopenharmony_ci				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
73348c2ecf20Sopenharmony_ci			else if (F_SA_HIGH & r_oip->flags)
73358c2ecf20Sopenharmony_ci				mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
73368c2ecf20Sopenharmony_ci			else
73378c2ecf20Sopenharmony_ci				mk_sense_invalid_opcode(scp);
73388c2ecf20Sopenharmony_ci			goto check_cond;
73398c2ecf20Sopenharmony_ci		}
73408c2ecf20Sopenharmony_ci	}	/* else (when na==0) we assume the oip is a match */
73418c2ecf20Sopenharmony_ci	flags = oip->flags;
73428c2ecf20Sopenharmony_ci	if (unlikely(F_INV_OP & flags)) {
73438c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
73448c2ecf20Sopenharmony_ci		goto check_cond;
73458c2ecf20Sopenharmony_ci	}
73468c2ecf20Sopenharmony_ci	if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
73478c2ecf20Sopenharmony_ci		if (sdebug_verbose)
73488c2ecf20Sopenharmony_ci			sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
73498c2ecf20Sopenharmony_ci				    my_name, opcode, " supported for wlun");
73508c2ecf20Sopenharmony_ci		mk_sense_invalid_opcode(scp);
73518c2ecf20Sopenharmony_ci		goto check_cond;
73528c2ecf20Sopenharmony_ci	}
73538c2ecf20Sopenharmony_ci	if (unlikely(sdebug_strict)) {	/* check cdb against mask */
73548c2ecf20Sopenharmony_ci		u8 rem;
73558c2ecf20Sopenharmony_ci		int j;
73568c2ecf20Sopenharmony_ci
73578c2ecf20Sopenharmony_ci		for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
73588c2ecf20Sopenharmony_ci			rem = ~oip->len_mask[k] & cmd[k];
73598c2ecf20Sopenharmony_ci			if (rem) {
73608c2ecf20Sopenharmony_ci				for (j = 7; j >= 0; --j, rem <<= 1) {
73618c2ecf20Sopenharmony_ci					if (0x80 & rem)
73628c2ecf20Sopenharmony_ci						break;
73638c2ecf20Sopenharmony_ci				}
73648c2ecf20Sopenharmony_ci				mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
73658c2ecf20Sopenharmony_ci				goto check_cond;
73668c2ecf20Sopenharmony_ci			}
73678c2ecf20Sopenharmony_ci		}
73688c2ecf20Sopenharmony_ci	}
73698c2ecf20Sopenharmony_ci	if (unlikely(!(F_SKIP_UA & flags) &&
73708c2ecf20Sopenharmony_ci		     find_first_bit(devip->uas_bm,
73718c2ecf20Sopenharmony_ci				    SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
73728c2ecf20Sopenharmony_ci		errsts = make_ua(scp, devip);
73738c2ecf20Sopenharmony_ci		if (errsts)
73748c2ecf20Sopenharmony_ci			goto check_cond;
73758c2ecf20Sopenharmony_ci	}
73768c2ecf20Sopenharmony_ci	if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) &&
73778c2ecf20Sopenharmony_ci		     atomic_read(&devip->stopped))) {
73788c2ecf20Sopenharmony_ci		errsts = resp_not_ready(scp, devip);
73798c2ecf20Sopenharmony_ci		if (errsts)
73808c2ecf20Sopenharmony_ci			goto fini;
73818c2ecf20Sopenharmony_ci	}
73828c2ecf20Sopenharmony_ci	if (sdebug_fake_rw && (F_FAKE_RW & flags))
73838c2ecf20Sopenharmony_ci		goto fini;
73848c2ecf20Sopenharmony_ci	if (unlikely(sdebug_every_nth)) {
73858c2ecf20Sopenharmony_ci		if (fake_timeout(scp))
73868c2ecf20Sopenharmony_ci			return 0;	/* ignore command: make trouble */
73878c2ecf20Sopenharmony_ci	}
73888c2ecf20Sopenharmony_ci	if (likely(oip->pfp))
73898c2ecf20Sopenharmony_ci		pfp = oip->pfp;	/* calls a resp_* function */
73908c2ecf20Sopenharmony_ci	else
73918c2ecf20Sopenharmony_ci		pfp = r_pfp;    /* if leaf function ptr NULL, try the root's */
73928c2ecf20Sopenharmony_ci
73938c2ecf20Sopenharmony_cifini:
73948c2ecf20Sopenharmony_ci	if (F_DELAY_OVERR & flags)	/* cmds like INQUIRY respond asap */
73958c2ecf20Sopenharmony_ci		return schedule_resp(scp, devip, errsts, pfp, 0, 0);
73968c2ecf20Sopenharmony_ci	else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
73978c2ecf20Sopenharmony_ci					    sdebug_ndelay > 10000)) {
73988c2ecf20Sopenharmony_ci		/*
73998c2ecf20Sopenharmony_ci		 * Skip long delays if ndelay <= 10 microseconds. Otherwise
74008c2ecf20Sopenharmony_ci		 * for Start Stop Unit (SSU) want at least 1 second delay and
74018c2ecf20Sopenharmony_ci		 * if sdebug_jdelay>1 want a long delay of that many seconds.
74028c2ecf20Sopenharmony_ci		 * For Synchronize Cache want 1/20 of SSU's delay.
74038c2ecf20Sopenharmony_ci		 */
74048c2ecf20Sopenharmony_ci		int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
74058c2ecf20Sopenharmony_ci		int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
74068c2ecf20Sopenharmony_ci
74078c2ecf20Sopenharmony_ci		jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
74088c2ecf20Sopenharmony_ci		return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
74098c2ecf20Sopenharmony_ci	} else
74108c2ecf20Sopenharmony_ci		return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
74118c2ecf20Sopenharmony_ci				     sdebug_ndelay);
74128c2ecf20Sopenharmony_cicheck_cond:
74138c2ecf20Sopenharmony_ci	return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
74148c2ecf20Sopenharmony_cierr_out:
74158c2ecf20Sopenharmony_ci	return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
74168c2ecf20Sopenharmony_ci}
74178c2ecf20Sopenharmony_ci
74188c2ecf20Sopenharmony_cistatic struct scsi_host_template sdebug_driver_template = {
74198c2ecf20Sopenharmony_ci	.show_info =		scsi_debug_show_info,
74208c2ecf20Sopenharmony_ci	.write_info =		scsi_debug_write_info,
74218c2ecf20Sopenharmony_ci	.proc_name =		sdebug_proc_name,
74228c2ecf20Sopenharmony_ci	.name =			"SCSI DEBUG",
74238c2ecf20Sopenharmony_ci	.info =			scsi_debug_info,
74248c2ecf20Sopenharmony_ci	.slave_alloc =		scsi_debug_slave_alloc,
74258c2ecf20Sopenharmony_ci	.slave_configure =	scsi_debug_slave_configure,
74268c2ecf20Sopenharmony_ci	.slave_destroy =	scsi_debug_slave_destroy,
74278c2ecf20Sopenharmony_ci	.ioctl =		scsi_debug_ioctl,
74288c2ecf20Sopenharmony_ci	.queuecommand =		scsi_debug_queuecommand,
74298c2ecf20Sopenharmony_ci	.change_queue_depth =	sdebug_change_qdepth,
74308c2ecf20Sopenharmony_ci	.eh_abort_handler =	scsi_debug_abort,
74318c2ecf20Sopenharmony_ci	.eh_device_reset_handler = scsi_debug_device_reset,
74328c2ecf20Sopenharmony_ci	.eh_target_reset_handler = scsi_debug_target_reset,
74338c2ecf20Sopenharmony_ci	.eh_bus_reset_handler = scsi_debug_bus_reset,
74348c2ecf20Sopenharmony_ci	.eh_host_reset_handler = scsi_debug_host_reset,
74358c2ecf20Sopenharmony_ci	.can_queue =		SDEBUG_CANQUEUE,
74368c2ecf20Sopenharmony_ci	.this_id =		7,
74378c2ecf20Sopenharmony_ci	.sg_tablesize =		SG_MAX_SEGMENTS,
74388c2ecf20Sopenharmony_ci	.cmd_per_lun =		DEF_CMD_PER_LUN,
74398c2ecf20Sopenharmony_ci	.max_sectors =		-1U,
74408c2ecf20Sopenharmony_ci	.max_segment_size =	-1U,
74418c2ecf20Sopenharmony_ci	.module =		THIS_MODULE,
74428c2ecf20Sopenharmony_ci	.track_queue_depth =	1,
74438c2ecf20Sopenharmony_ci};
74448c2ecf20Sopenharmony_ci
74458c2ecf20Sopenharmony_cistatic int sdebug_driver_probe(struct device *dev)
74468c2ecf20Sopenharmony_ci{
74478c2ecf20Sopenharmony_ci	int error = 0;
74488c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
74498c2ecf20Sopenharmony_ci	struct Scsi_Host *hpnt;
74508c2ecf20Sopenharmony_ci	int hprot;
74518c2ecf20Sopenharmony_ci
74528c2ecf20Sopenharmony_ci	sdbg_host = to_sdebug_host(dev);
74538c2ecf20Sopenharmony_ci
74548c2ecf20Sopenharmony_ci	sdebug_driver_template.can_queue = sdebug_max_queue;
74558c2ecf20Sopenharmony_ci	if (!sdebug_clustering)
74568c2ecf20Sopenharmony_ci		sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
74578c2ecf20Sopenharmony_ci
74588c2ecf20Sopenharmony_ci	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
74598c2ecf20Sopenharmony_ci	if (NULL == hpnt) {
74608c2ecf20Sopenharmony_ci		pr_err("scsi_host_alloc failed\n");
74618c2ecf20Sopenharmony_ci		error = -ENODEV;
74628c2ecf20Sopenharmony_ci		return error;
74638c2ecf20Sopenharmony_ci	}
74648c2ecf20Sopenharmony_ci	if (submit_queues > nr_cpu_ids) {
74658c2ecf20Sopenharmony_ci		pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
74668c2ecf20Sopenharmony_ci			my_name, submit_queues, nr_cpu_ids);
74678c2ecf20Sopenharmony_ci		submit_queues = nr_cpu_ids;
74688c2ecf20Sopenharmony_ci	}
74698c2ecf20Sopenharmony_ci	/*
74708c2ecf20Sopenharmony_ci	 * Decide whether to tell scsi subsystem that we want mq. The
74718c2ecf20Sopenharmony_ci	 * following should give the same answer for each host.
74728c2ecf20Sopenharmony_ci	 */
74738c2ecf20Sopenharmony_ci	hpnt->nr_hw_queues = submit_queues;
74748c2ecf20Sopenharmony_ci	if (sdebug_host_max_queue)
74758c2ecf20Sopenharmony_ci		hpnt->host_tagset = 1;
74768c2ecf20Sopenharmony_ci
74778c2ecf20Sopenharmony_ci	sdbg_host->shost = hpnt;
74788c2ecf20Sopenharmony_ci	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
74798c2ecf20Sopenharmony_ci	if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
74808c2ecf20Sopenharmony_ci		hpnt->max_id = sdebug_num_tgts + 1;
74818c2ecf20Sopenharmony_ci	else
74828c2ecf20Sopenharmony_ci		hpnt->max_id = sdebug_num_tgts;
74838c2ecf20Sopenharmony_ci	/* = sdebug_max_luns; */
74848c2ecf20Sopenharmony_ci	hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
74858c2ecf20Sopenharmony_ci
74868c2ecf20Sopenharmony_ci	hprot = 0;
74878c2ecf20Sopenharmony_ci
74888c2ecf20Sopenharmony_ci	switch (sdebug_dif) {
74898c2ecf20Sopenharmony_ci
74908c2ecf20Sopenharmony_ci	case T10_PI_TYPE1_PROTECTION:
74918c2ecf20Sopenharmony_ci		hprot = SHOST_DIF_TYPE1_PROTECTION;
74928c2ecf20Sopenharmony_ci		if (sdebug_dix)
74938c2ecf20Sopenharmony_ci			hprot |= SHOST_DIX_TYPE1_PROTECTION;
74948c2ecf20Sopenharmony_ci		break;
74958c2ecf20Sopenharmony_ci
74968c2ecf20Sopenharmony_ci	case T10_PI_TYPE2_PROTECTION:
74978c2ecf20Sopenharmony_ci		hprot = SHOST_DIF_TYPE2_PROTECTION;
74988c2ecf20Sopenharmony_ci		if (sdebug_dix)
74998c2ecf20Sopenharmony_ci			hprot |= SHOST_DIX_TYPE2_PROTECTION;
75008c2ecf20Sopenharmony_ci		break;
75018c2ecf20Sopenharmony_ci
75028c2ecf20Sopenharmony_ci	case T10_PI_TYPE3_PROTECTION:
75038c2ecf20Sopenharmony_ci		hprot = SHOST_DIF_TYPE3_PROTECTION;
75048c2ecf20Sopenharmony_ci		if (sdebug_dix)
75058c2ecf20Sopenharmony_ci			hprot |= SHOST_DIX_TYPE3_PROTECTION;
75068c2ecf20Sopenharmony_ci		break;
75078c2ecf20Sopenharmony_ci
75088c2ecf20Sopenharmony_ci	default:
75098c2ecf20Sopenharmony_ci		if (sdebug_dix)
75108c2ecf20Sopenharmony_ci			hprot |= SHOST_DIX_TYPE0_PROTECTION;
75118c2ecf20Sopenharmony_ci		break;
75128c2ecf20Sopenharmony_ci	}
75138c2ecf20Sopenharmony_ci
75148c2ecf20Sopenharmony_ci	scsi_host_set_prot(hpnt, hprot);
75158c2ecf20Sopenharmony_ci
75168c2ecf20Sopenharmony_ci	if (have_dif_prot || sdebug_dix)
75178c2ecf20Sopenharmony_ci		pr_info("host protection%s%s%s%s%s%s%s\n",
75188c2ecf20Sopenharmony_ci			(hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
75198c2ecf20Sopenharmony_ci			(hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
75208c2ecf20Sopenharmony_ci			(hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
75218c2ecf20Sopenharmony_ci			(hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
75228c2ecf20Sopenharmony_ci			(hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
75238c2ecf20Sopenharmony_ci			(hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
75248c2ecf20Sopenharmony_ci			(hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
75258c2ecf20Sopenharmony_ci
75268c2ecf20Sopenharmony_ci	if (sdebug_guard == 1)
75278c2ecf20Sopenharmony_ci		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
75288c2ecf20Sopenharmony_ci	else
75298c2ecf20Sopenharmony_ci		scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
75308c2ecf20Sopenharmony_ci
75318c2ecf20Sopenharmony_ci	sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
75328c2ecf20Sopenharmony_ci	sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
75338c2ecf20Sopenharmony_ci	if (sdebug_every_nth)	/* need stats counters for every_nth */
75348c2ecf20Sopenharmony_ci		sdebug_statistics = true;
75358c2ecf20Sopenharmony_ci	error = scsi_add_host(hpnt, &sdbg_host->dev);
75368c2ecf20Sopenharmony_ci	if (error) {
75378c2ecf20Sopenharmony_ci		pr_err("scsi_add_host failed\n");
75388c2ecf20Sopenharmony_ci		error = -ENODEV;
75398c2ecf20Sopenharmony_ci		scsi_host_put(hpnt);
75408c2ecf20Sopenharmony_ci	} else {
75418c2ecf20Sopenharmony_ci		scsi_scan_host(hpnt);
75428c2ecf20Sopenharmony_ci	}
75438c2ecf20Sopenharmony_ci
75448c2ecf20Sopenharmony_ci	return error;
75458c2ecf20Sopenharmony_ci}
75468c2ecf20Sopenharmony_ci
75478c2ecf20Sopenharmony_cistatic int sdebug_driver_remove(struct device *dev)
75488c2ecf20Sopenharmony_ci{
75498c2ecf20Sopenharmony_ci	struct sdebug_host_info *sdbg_host;
75508c2ecf20Sopenharmony_ci	struct sdebug_dev_info *sdbg_devinfo, *tmp;
75518c2ecf20Sopenharmony_ci
75528c2ecf20Sopenharmony_ci	sdbg_host = to_sdebug_host(dev);
75538c2ecf20Sopenharmony_ci
75548c2ecf20Sopenharmony_ci	if (!sdbg_host) {
75558c2ecf20Sopenharmony_ci		pr_err("Unable to locate host info\n");
75568c2ecf20Sopenharmony_ci		return -ENODEV;
75578c2ecf20Sopenharmony_ci	}
75588c2ecf20Sopenharmony_ci
75598c2ecf20Sopenharmony_ci	scsi_remove_host(sdbg_host->shost);
75608c2ecf20Sopenharmony_ci
75618c2ecf20Sopenharmony_ci	list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
75628c2ecf20Sopenharmony_ci				 dev_list) {
75638c2ecf20Sopenharmony_ci		list_del(&sdbg_devinfo->dev_list);
75648c2ecf20Sopenharmony_ci		kfree(sdbg_devinfo->zstate);
75658c2ecf20Sopenharmony_ci		kfree(sdbg_devinfo);
75668c2ecf20Sopenharmony_ci	}
75678c2ecf20Sopenharmony_ci
75688c2ecf20Sopenharmony_ci	scsi_host_put(sdbg_host->shost);
75698c2ecf20Sopenharmony_ci	return 0;
75708c2ecf20Sopenharmony_ci}
75718c2ecf20Sopenharmony_ci
75728c2ecf20Sopenharmony_cistatic int pseudo_lld_bus_match(struct device *dev,
75738c2ecf20Sopenharmony_ci				struct device_driver *dev_driver)
75748c2ecf20Sopenharmony_ci{
75758c2ecf20Sopenharmony_ci	return 1;
75768c2ecf20Sopenharmony_ci}
75778c2ecf20Sopenharmony_ci
75788c2ecf20Sopenharmony_cistatic struct bus_type pseudo_lld_bus = {
75798c2ecf20Sopenharmony_ci	.name = "pseudo",
75808c2ecf20Sopenharmony_ci	.match = pseudo_lld_bus_match,
75818c2ecf20Sopenharmony_ci	.probe = sdebug_driver_probe,
75828c2ecf20Sopenharmony_ci	.remove = sdebug_driver_remove,
75838c2ecf20Sopenharmony_ci	.drv_groups = sdebug_drv_groups,
75848c2ecf20Sopenharmony_ci};
7585