blob: 8480e4849e29efff7ca8f22864c6696cd4030368 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05009 * Copyright (C) 2001 - 2017 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Douglas Gilbert773642d2016-04-25 12:16:28 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040016 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Tomas Winklerc12879702015-07-28 16:54:20 +030020
21#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040027#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/types.h>
30#include <linux/string.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <linux/init.h>
34#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/vmalloc.h>
36#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020037#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050039#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040040#include <linux/spinlock.h>
41#include <linux/interrupt.h>
42#include <linux/atomic.h>
43#include <linux/hrtimer.h>
Douglas Gilbert09ba24c2016-05-06 00:40:28 -040044#include <linux/uuid.h>
Christoph Hellwig6ebf1052016-09-11 19:35:39 +020045#include <linux/t10-pi.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050046
47#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090048
Martin K. Petersen44d92692009-10-15 14:45:27 -040049#include <asm/unaligned.h>
50
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090051#include <scsi/scsi.h>
52#include <scsi/scsi_cmnd.h>
53#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <scsi/scsi_host.h>
55#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090056#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040057#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040058#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Martin K. Petersenc6a44282009-01-04 03:08:19 -050060#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Douglas Gilbert773642d2016-04-25 12:16:28 -040063/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbert9b760fd2017-12-05 00:05:49 -050064#define SDEBUG_VERSION "0187" /* format to fit INQUIRY revision field */
65static const char *sdebug_version_date = "20171202";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040066
67#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define NO_ADDITIONAL_SENSE 0x0
71#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050072#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040074#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050076#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040078#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040079#define UA_RESET_ASC 0x29
80#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050081#define TARGET_CHANGED_ASC 0x3f
82#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050083#define INSUFF_RES_ASC 0x55
84#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040085#define POWER_ON_RESET_ASCQ 0x0
86#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
87#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050088#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050090#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define THRESHOLD_EXCEEDED 0x5d
92#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050093#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050094#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
95#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Douglas Gilbert481b5e52017-12-23 12:48:14 -050096#define WRITE_ERROR_ASC 0xc
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050098/* Additional Sense Code Qualifier (ASCQ) */
99#define ACK_NAK_TO 0x3
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/* Default values for driver parameters */
102#define DEF_NUM_HOST 1
103#define DEF_NUM_TGTS 1
104#define DEF_MAX_LUNS 1
105/* With these defaults, this driver will make 1 host with 1 target
106 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
107 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500108#define DEF_ATO 1
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500109#define DEF_CDB_LEN 10
Douglas Gilbertc2206092016-04-25 12:16:31 -0400110#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500112#define DEF_DIF 0
113#define DEF_DIX 0
114#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500116#define DEF_FAKE_RW 0
117#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400118#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_LBPU 0
120#define DEF_LBPWS 0
121#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600122#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500123#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400124#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500125#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#define DEF_NUM_PARTS 0
127#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500128#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500129#define DEF_PHYSBLK_EXP 0
Lukas Herbolt86e68282017-01-26 10:00:37 +0100130#define DEF_OPT_XFERLEN_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400131#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200132#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400133#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500134#define DEF_SECTOR_SIZE 512
135#define DEF_UNMAP_ALIGNMENT 0
136#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400137#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
138#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500139#define DEF_VIRTUAL_GB 0
140#define DEF_VPD_USE_HOSTNO 1
141#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500142#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400143#define DEF_STATISTICS false
144#define DEF_SUBMIT_QUEUES 1
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400145#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400146#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400148#define SDEBUG_LUN_0_VAL 0
149
Douglas Gilbert773642d2016-04-25 12:16:28 -0400150/* bit mask values for sdebug_opts */
151#define SDEBUG_OPT_NOISE 1
152#define SDEBUG_OPT_MEDIUM_ERR 2
153#define SDEBUG_OPT_TIMEOUT 4
154#define SDEBUG_OPT_RECOVERED_ERR 8
155#define SDEBUG_OPT_TRANSPORT_ERR 16
156#define SDEBUG_OPT_DIF_ERR 32
157#define SDEBUG_OPT_DIX_ERR 64
158#define SDEBUG_OPT_MAC_TIMEOUT 128
159#define SDEBUG_OPT_SHORT_TRANSFER 0x100
160#define SDEBUG_OPT_Q_NOISE 0x200
161#define SDEBUG_OPT_ALL_TSF 0x400
162#define SDEBUG_OPT_RARE_TSF 0x800
163#define SDEBUG_OPT_N_WCE 0x1000
164#define SDEBUG_OPT_RESET_NOISE 0x2000
165#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800166#define SDEBUG_OPT_HOST_BUSY 0x8000
Douglas Gilbert773642d2016-04-25 12:16:28 -0400167#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
168 SDEBUG_OPT_RESET_NOISE)
169#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
170 SDEBUG_OPT_TRANSPORT_ERR | \
171 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800172 SDEBUG_OPT_SHORT_TRANSFER | \
173 SDEBUG_OPT_HOST_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400175 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400177 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500178 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400179 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 *
181 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400182 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400184 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500185 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400186 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
187 * This will continue on every subsequent command until some other action
188 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
189 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 */
191
Douglas Gilbertfd321192016-04-25 12:16:33 -0400192/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400193 * priority order. In the subset implemented here lower numbers have higher
194 * priority. The UA numbers should be a sequence starting from 0 with
195 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
196#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
197#define SDEBUG_UA_BUS_RESET 1
198#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500199#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500200#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500201#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
202#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
203#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400204
Douglas Gilbert773642d2016-04-25 12:16:28 -0400205/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 * sector on read commands: */
207#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500208#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
211 * or "peripheral device" addressing (value 0) */
212#define SAM2_LUN_ADDRESS_METHOD 0
213
Douglas Gilbertc4837392016-05-06 00:40:26 -0400214/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215 * (for response) per submit queue at one time. Can be reduced by max_queue
216 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219 * but cannot exceed SDEBUG_CANQUEUE .
220 */
221#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
222#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400223#define DEF_CMD_PER_LUN 255
224
Douglas Gilbertfd321192016-04-25 12:16:33 -0400225#define F_D_IN 1
226#define F_D_OUT 2
227#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
228#define F_D_UNKN 8
229#define F_RL_WLUN_OK 0x10
230#define F_SKIP_UA 0x20
231#define F_DELAY_OVERR 0x40
232#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
233#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
234#define F_INV_OP 0x200
235#define F_FAKE_RW 0x400
236#define F_M_ACCESS 0x800 /* media access */
237
238#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500239#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400240#define FF_SA (F_SA_HIGH | F_SA_LOW)
241
242#define SDEBUG_MAX_PARTS 4
243
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400244#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400245
246
247struct sdebug_dev_info {
248 struct list_head dev_list;
249 unsigned int channel;
250 unsigned int target;
251 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200252 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400253 struct sdebug_host_info *sdbg_host;
254 unsigned long uas_bm[1];
255 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400256 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400257 bool used;
258};
259
260struct sdebug_host_info {
261 struct list_head host_list;
262 struct Scsi_Host *shost;
263 struct device dev;
264 struct list_head dev_info_list;
265};
266
267#define to_sdebug_host(d) \
268 container_of(d, struct sdebug_host_info, dev)
269
Douglas Gilbert10bde982018-01-10 16:57:31 -0500270enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
271 SDEB_DEFER_WQ = 2};
272
Douglas Gilbertfd321192016-04-25 12:16:33 -0400273struct sdebug_defer {
274 struct hrtimer hrt;
275 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400276 int sqa_idx; /* index of sdebug_queue array */
277 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
278 int issuing_cpu;
Douglas Gilbert10bde982018-01-10 16:57:31 -0500279 bool init_hrt;
280 bool init_wq;
281 enum sdeb_defer_type defer_t;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400282};
283
284struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400285 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
286 * instance indicates this slot is in use.
287 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400288 struct sdebug_defer *sd_dp;
289 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400290 unsigned int inj_recovered:1;
291 unsigned int inj_transport:1;
292 unsigned int inj_dif:1;
293 unsigned int inj_dix:1;
294 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800295 unsigned int inj_host_busy:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400296};
297
Douglas Gilbertc4837392016-05-06 00:40:26 -0400298struct sdebug_queue {
299 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
300 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
301 spinlock_t qc_lock;
302 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400303};
304
Douglas Gilbertc4837392016-05-06 00:40:26 -0400305static atomic_t sdebug_cmnd_count; /* number of incoming commands */
306static atomic_t sdebug_completions; /* count of deferred completions */
307static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
308static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
309
Douglas Gilbertfd321192016-04-25 12:16:33 -0400310struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400311 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
312 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400313 u8 opcode; /* if num_attached > 0, preferred */
314 u16 sa; /* service action */
315 u32 flags; /* OR-ed set of SDEB_F_* */
316 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
317 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500318 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
319 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400320};
321
322/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500323enum sdeb_opcode_index {
324 SDEB_I_INVALID_OPCODE = 0,
325 SDEB_I_INQUIRY = 1,
326 SDEB_I_REPORT_LUNS = 2,
327 SDEB_I_REQUEST_SENSE = 3,
328 SDEB_I_TEST_UNIT_READY = 4,
329 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
330 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
331 SDEB_I_LOG_SENSE = 7,
332 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
333 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
334 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
335 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500336 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
337 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500338 SDEB_I_MAINT_IN = 14,
339 SDEB_I_MAINT_OUT = 15,
340 SDEB_I_VERIFY = 16, /* 10 only */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500341 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500342 SDEB_I_RESERVE = 18, /* 6, 10 */
343 SDEB_I_RELEASE = 19, /* 6, 10 */
344 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
345 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
346 SDEB_I_ATA_PT = 22, /* 12, 16 */
347 SDEB_I_SEND_DIAG = 23,
348 SDEB_I_UNMAP = 24,
349 SDEB_I_XDWRITEREAD = 25, /* 10 only */
350 SDEB_I_WRITE_BUFFER = 26,
351 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
352 SDEB_I_SYNC_CACHE = 28, /* 10 only */
353 SDEB_I_COMP_WRITE = 29,
Douglas Gilbert9a051012017-12-23 12:48:10 -0500354 SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500355};
356
Douglas Gilbertc4837392016-05-06 00:40:26 -0400357
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500358static const unsigned char opcode_ind_arr[256] = {
359/* 0x0; 0x0->0x1f: 6 byte cdbs */
360 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
361 0, 0, 0, 0,
362 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
363 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
364 SDEB_I_RELEASE,
365 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
366 SDEB_I_ALLOW_REMOVAL, 0,
367/* 0x20; 0x20->0x3f: 10 byte cdbs */
368 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
369 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
370 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
371 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
372/* 0x40; 0x40->0x5f: 10 byte cdbs */
373 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
374 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
375 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
376 SDEB_I_RELEASE,
377 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400378/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381 0, SDEB_I_VARIABLE_LEN,
382/* 0x80; 0x80->0x9f: 16 byte cdbs */
383 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
384 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
385 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500386 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500387/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
388 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
389 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500390 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
391 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500392 0, 0, 0, 0, 0, 0, 0, 0,
393 0, 0, 0, 0, 0, 0, 0, 0,
394/* 0xc0; 0xc0->0xff: vendor specific */
395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399};
400
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500401static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
402static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
403static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
404static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
405static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
406static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
407static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
408static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
409static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500410static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500411static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
412static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
413static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
414static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
415static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500416static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
417static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500418static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
419static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
420static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500421static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500422static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500423
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500424/*
425 * The following are overflow arrays for cdbs that "hit" the same index in
426 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
427 * should be placed in opcode_info_arr[], the others should be placed here.
428 */
429static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500430 {0, 0x1a, 0, F_D_IN, NULL, NULL,
431 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
432};
433
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500434static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500435 {0, 0x15, 0, F_D_OUT, NULL, NULL,
436 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
437};
438
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500439static const struct opcode_info_t read_iarr[] = {
440 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500441 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500442 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500443 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500444 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500445 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500446 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500447 0xc7, 0, 0, 0, 0} },
448};
449
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500450static const struct opcode_info_t write_iarr[] = {
451 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
452 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
453 0, 0, 0, 0, 0, 0} },
454 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
455 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
456 0, 0, 0} },
457 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
458 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
459 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500460};
461
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500462static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500463 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
464 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500465 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500466};
467
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500468static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
469 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500470 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500471 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500472 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
473 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
474 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500475};
476
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500477static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500478 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500479 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500480 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500481 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500482 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500483 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500484};
485
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500486static const struct opcode_info_t write_same_iarr[] = {
487 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500488 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500489 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500490};
491
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500492static const struct opcode_info_t reserve_iarr[] = {
493 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500494 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
495};
496
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500497static const struct opcode_info_t release_iarr[] = {
498 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500499 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
500};
501
502
503/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
504 * plus the terminating elements for logic that scans this table such as
505 * REPORT SUPPORTED OPERATION CODES. */
506static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
507/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500508 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500509 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500510 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500511 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
512 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
513 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500514 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500515 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
516 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
517 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
518 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500519/* 5 */
520 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
521 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
522 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
523 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
524 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
525 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
526 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500527 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
528 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500529 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500530 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
531 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500532 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
533 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
534 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500535/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500536 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
537 resp_write_dt0, write_iarr, /* WRITE(16) */
538 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
539 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* WRITE(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500540 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
541 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500542 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
543 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
544 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
545 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500546 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
547 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
548 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500549 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
550 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
551 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
552 0xff, 0, 0xc7, 0, 0, 0, 0} },
553/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500554 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
555 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500556 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500557 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
558 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500559 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
560 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
561 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
562 0xff, 0xff} },
563 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
564 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500565 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
566 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500567 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
568 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500569 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
570 0} },
571/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500572 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
573 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500574 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
575 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
576 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
577 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
578 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
579 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500580 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500581 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500582/* 25 */
583 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500584 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500585 0, 0, 0, 0, 0, 0} }, /* XDWRITEREAD(10) */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500586 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
587 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
588 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500589 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
590 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
591 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
592 0, 0, 0, 0, 0} },
593 {0, 0x35, 0, F_DELAY_OVERR | FF_MEDIA_IO, NULL, NULL, /* SYNC_CACHE */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500594 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500595 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500596 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500597 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500598 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500599
600/* 30 */
601 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
602 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
603};
604
Douglas Gilbert773642d2016-04-25 12:16:28 -0400605static int sdebug_add_host = DEF_NUM_HOST;
606static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500607static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400608static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400609static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
610static int sdebug_dif = DEF_DIF;
611static int sdebug_dix = DEF_DIX;
612static int sdebug_dsense = DEF_D_SENSE;
613static int sdebug_every_nth = DEF_EVERY_NTH;
614static int sdebug_fake_rw = DEF_FAKE_RW;
615static unsigned int sdebug_guard = DEF_GUARD;
616static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
617static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400618static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Laurence Obermand9da8912018-02-03 13:38:35 -0500619static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
620static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400621static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400622static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400623static int sdebug_no_lun_0 = DEF_NO_LUN_0;
624static int sdebug_no_uld;
625static int sdebug_num_parts = DEF_NUM_PARTS;
626static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
627static int sdebug_opt_blks = DEF_OPT_BLKS;
628static int sdebug_opts = DEF_OPTS;
629static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100630static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400631static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400632static int sdebug_scsi_level = DEF_SCSI_LEVEL;
633static int sdebug_sector_size = DEF_SECTOR_SIZE;
634static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
635static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
636static unsigned int sdebug_lbpu = DEF_LBPU;
637static unsigned int sdebug_lbpws = DEF_LBPWS;
638static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
639static unsigned int sdebug_lbprz = DEF_LBPRZ;
640static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
641static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
642static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
643static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
644static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400645static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400646static bool sdebug_removable = DEF_REMOVABLE;
647static bool sdebug_clustering;
648static bool sdebug_host_lock = DEF_HOST_LOCK;
649static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500650static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400651static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400652static bool have_dif_prot;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400653static bool sdebug_statistics = DEF_STATISTICS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400655static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656static sector_t sdebug_capacity; /* in sectors */
657
658/* old BIOS stuff, kernel may get rid of them but some mode sense pages
659 may still need them */
660static int sdebug_heads; /* heads per disk */
661static int sdebug_cylinders_per; /* cylinders per surface */
662static int sdebug_sectors_per; /* sectors per cylinder */
663
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664static LIST_HEAD(sdebug_host_list);
665static DEFINE_SPINLOCK(sdebug_host_list_lock);
666
Douglas Gilbertfd321192016-04-25 12:16:33 -0400667static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200668static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400669static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Martin K. Petersen44d92692009-10-15 14:45:27 -0400671static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400672static int num_aborts;
673static int num_dev_resets;
674static int num_target_resets;
675static int num_bus_resets;
676static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500677static int dix_writes;
678static int dix_reads;
679static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Douglas Gilbertc4837392016-05-06 00:40:26 -0400681static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
682static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684static DEFINE_RWLOCK(atomic_rw);
685
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400686static char sdebug_proc_name[] = MY_NAME;
687static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689static struct bus_type pseudo_lld_bus;
690
691static struct device_driver sdebug_driverfs_driver = {
692 .name = sdebug_proc_name,
693 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694};
695
696static const int check_condition_result =
697 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
698
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500699static const int illegal_condition_result =
700 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
701
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400702static const int device_qfull_result =
703 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
704
Douglas Gilbertfd321192016-04-25 12:16:33 -0400705
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400706/* Only do the extra work involved in logical block provisioning if one or
707 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
708 * real reads and writes (i.e. not skipping them for speed).
709 */
710static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400711{
712 return 0 == sdebug_fake_rw &&
713 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
714}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400715
Akinobu Mita14faa942013-09-18 21:27:24 +0900716static void *fake_store(unsigned long long lba)
717{
718 lba = do_div(lba, sdebug_store_sectors);
719
Douglas Gilbert773642d2016-04-25 12:16:28 -0400720 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900721}
722
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200723static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900724{
Arnd Bergmann49413112015-11-20 17:38:28 +0100725 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900726
727 return dif_storep + sector;
728}
729
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900730static void sdebug_max_tgts_luns(void)
731{
732 struct sdebug_host_info *sdbg_host;
733 struct Scsi_Host *hpnt;
734
735 spin_lock(&sdebug_host_list_lock);
736 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
737 hpnt = sdbg_host->shost;
738 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400739 (sdebug_num_tgts > hpnt->this_id))
740 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900741 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400742 hpnt->max_id = sdebug_num_tgts;
743 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300744 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900745 }
746 spin_unlock(&sdebug_host_list_lock);
747}
748
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500749enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
750
751/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400752static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
753 enum sdeb_cmd_data c_d,
754 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500755{
756 unsigned char *sbuff;
757 u8 sks[4];
758 int sl, asc;
759
760 sbuff = scp->sense_buffer;
761 if (!sbuff) {
762 sdev_printk(KERN_ERR, scp->device,
763 "%s: sense_buffer is NULL\n", __func__);
764 return;
765 }
766 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
767 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400768 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500769 memset(sks, 0, sizeof(sks));
770 sks[0] = 0x80;
771 if (c_d)
772 sks[0] |= 0x40;
773 if (in_bit >= 0) {
774 sks[0] |= 0x8;
775 sks[0] |= 0x7 & in_bit;
776 }
777 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400778 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500779 sl = sbuff[7] + 8;
780 sbuff[7] = sl;
781 sbuff[sl] = 0x2;
782 sbuff[sl + 1] = 0x6;
783 memcpy(sbuff + sl + 4, sks, 3);
784 } else
785 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400786 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500787 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
788 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
789 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
790}
791
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400792static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900793{
794 unsigned char *sbuff;
795
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400796 sbuff = scp->sense_buffer;
797 if (!sbuff) {
798 sdev_printk(KERN_ERR, scp->device,
799 "%s: sense_buffer is NULL\n", __func__);
800 return;
801 }
802 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900803
Douglas Gilbert773642d2016-04-25 12:16:28 -0400804 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900805
Douglas Gilbert773642d2016-04-25 12:16:28 -0400806 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400807 sdev_printk(KERN_INFO, scp->device,
808 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
809 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900810}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Douglas Gilbertfd321192016-04-25 12:16:33 -0400812static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500813{
814 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
815}
816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
818{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400819 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400820 if (0x1261 == cmd)
821 sdev_printk(KERN_INFO, dev,
822 "%s: BLKFLSBUF [0x1261]\n", __func__);
823 else if (0x5331 == cmd)
824 sdev_printk(KERN_INFO, dev,
825 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
826 __func__);
827 else
828 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
829 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
831 return -EINVAL;
832 /* return -ENOTTY; // correct return but upsets fdisk */
833}
834
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500835static void config_cdb_len(struct scsi_device *sdev)
836{
837 switch (sdebug_cdb_len) {
838 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
839 sdev->use_10_for_rw = false;
840 sdev->use_16_for_rw = false;
841 sdev->use_10_for_ms = false;
842 break;
843 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
844 sdev->use_10_for_rw = true;
845 sdev->use_16_for_rw = false;
846 sdev->use_10_for_ms = false;
847 break;
848 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
849 sdev->use_10_for_rw = true;
850 sdev->use_16_for_rw = false;
851 sdev->use_10_for_ms = true;
852 break;
853 case 16:
854 sdev->use_10_for_rw = false;
855 sdev->use_16_for_rw = true;
856 sdev->use_10_for_ms = true;
857 break;
858 case 32: /* No knobs to suggest this so same as 16 for now */
859 sdev->use_10_for_rw = false;
860 sdev->use_16_for_rw = true;
861 sdev->use_10_for_ms = true;
862 break;
863 default:
864 pr_warn("unexpected cdb_len=%d, force to 10\n",
865 sdebug_cdb_len);
866 sdev->use_10_for_rw = true;
867 sdev->use_16_for_rw = false;
868 sdev->use_10_for_ms = false;
869 sdebug_cdb_len = 10;
870 break;
871 }
872}
873
874static void all_config_cdb_len(void)
875{
876 struct sdebug_host_info *sdbg_host;
877 struct Scsi_Host *shost;
878 struct scsi_device *sdev;
879
880 spin_lock(&sdebug_host_list_lock);
881 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
882 shost = sdbg_host->shost;
883 shost_for_each_device(sdev, shost) {
884 config_cdb_len(sdev);
885 }
886 }
887 spin_unlock(&sdebug_host_list_lock);
888}
889
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500890static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
891{
892 struct sdebug_host_info *sdhp;
893 struct sdebug_dev_info *dp;
894
895 spin_lock(&sdebug_host_list_lock);
896 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
897 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
898 if ((devip->sdbg_host == dp->sdbg_host) &&
899 (devip->target == dp->target))
900 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
901 }
902 }
903 spin_unlock(&sdebug_host_list_lock);
904}
905
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400906static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400908 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400909
910 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
911 if (k != SDEBUG_NUM_UAS) {
912 const char *cp = NULL;
913
914 switch (k) {
915 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400916 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
917 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400918 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400919 cp = "power on reset";
920 break;
921 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400922 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
923 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400924 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400925 cp = "bus reset";
926 break;
927 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400928 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
929 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400930 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400931 cp = "mode parameters changed";
932 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500933 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400934 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
935 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400936 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500937 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500938 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500939 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400940 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400941 TARGET_CHANGED_ASC,
942 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400943 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500944 cp = "microcode has been changed";
945 break;
946 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400947 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500948 TARGET_CHANGED_ASC,
949 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400950 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500951 cp = "microcode has been changed without reset";
952 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500953 case SDEBUG_UA_LUNS_CHANGED:
954 /*
955 * SPC-3 behavior is to report a UNIT ATTENTION with
956 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
957 * on the target, until a REPORT LUNS command is
958 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400959 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500960 * values as struct scsi_device->scsi_level.
961 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400962 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500963 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400964 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500965 TARGET_CHANGED_ASC,
966 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400967 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500968 cp = "reported luns data has changed";
969 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400970 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400971 pr_warn("unexpected unit attention code=%d\n", k);
972 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400973 cp = "unknown";
974 break;
975 }
976 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400977 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400978 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400979 "%s reports: Unit attention: %s\n",
980 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return check_condition_result;
982 }
983 return 0;
984}
985
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400986/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900987static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 int arr_len)
989{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900990 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900991 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900993 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900995 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400996 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900997
998 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
999 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -07001000 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001001
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 return 0;
1003}
1004
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001005/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1006 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1007 * calls, not required to write in ascending offset order. Assumes resid
1008 * set to scsi_bufflen() prior to any calls.
1009 */
1010static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1011 int arr_len, unsigned int off_dst)
1012{
1013 int act_len, n;
1014 struct scsi_data_buffer *sdb = scsi_in(scp);
1015 off_t skip = off_dst;
1016
1017 if (sdb->length <= off_dst)
1018 return 0;
1019 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1020 return DID_ERROR << 16;
1021
1022 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1023 arr, arr_len, skip);
1024 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1025 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1026 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1027 sdb->resid = min(sdb->resid, n);
1028 return 0;
1029}
1030
1031/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1032 * 'arr' or -1 if error.
1033 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001034static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1035 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001037 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001039 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001041
1042 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043}
1044
1045
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001046static char sdebug_inq_vendor_id[9] = "Linux ";
1047static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001048static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001049/* Use some locally assigned NAAs for SAS addresses. */
1050static const u64 naa3_comp_a = 0x3222222000000000ULL;
1051static const u64 naa3_comp_b = 0x3333333000000000ULL;
1052static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001054/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001055static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1056 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001057 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001058 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001060 int num, port_a;
1061 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001063 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 /* T10 vendor identifier field format (faked) */
1065 arr[0] = 0x2; /* ASCII */
1066 arr[1] = 0x1;
1067 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001068 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1069 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1071 num = 8 + 16 + dev_id_str_len;
1072 arr[3] = num;
1073 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001074 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001075 if (sdebug_uuid_ctl) {
1076 /* Locally assigned UUID */
1077 arr[num++] = 0x1; /* binary (not necessarily sas) */
1078 arr[num++] = 0xa; /* PIV=0, lu, naa */
1079 arr[num++] = 0x0;
1080 arr[num++] = 0x12;
1081 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1082 arr[num++] = 0x0;
1083 memcpy(arr + num, lu_name, 16);
1084 num += 16;
1085 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001086 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001087 arr[num++] = 0x1; /* binary (not necessarily sas) */
1088 arr[num++] = 0x3; /* PIV=0, lu, naa */
1089 arr[num++] = 0x0;
1090 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001091 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001092 num += 8;
1093 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001094 /* Target relative port number */
1095 arr[num++] = 0x61; /* proto=sas, binary */
1096 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1097 arr[num++] = 0x0; /* reserved */
1098 arr[num++] = 0x4; /* length */
1099 arr[num++] = 0x0; /* reserved */
1100 arr[num++] = 0x0; /* reserved */
1101 arr[num++] = 0x0;
1102 arr[num++] = 0x1; /* relative port A */
1103 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001104 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001105 arr[num++] = 0x61; /* proto=sas, binary */
1106 arr[num++] = 0x93; /* piv=1, target port, naa */
1107 arr[num++] = 0x0;
1108 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001109 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001110 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001111 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001112 arr[num++] = 0x61; /* proto=sas, binary */
1113 arr[num++] = 0x95; /* piv=1, target port group id */
1114 arr[num++] = 0x0;
1115 arr[num++] = 0x4;
1116 arr[num++] = 0;
1117 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001118 put_unaligned_be16(port_group_id, arr + num);
1119 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001120 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001121 arr[num++] = 0x61; /* proto=sas, binary */
1122 arr[num++] = 0xa3; /* piv=1, target device, naa */
1123 arr[num++] = 0x0;
1124 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001125 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001126 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001127 /* SCSI name string: Target device identifier */
1128 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1129 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1130 arr[num++] = 0x0;
1131 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001132 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001133 num += 12;
1134 snprintf(b, sizeof(b), "%08X", target_dev_id);
1135 memcpy(arr + num, b, 8);
1136 num += 8;
1137 memset(arr + num, 0, 4);
1138 num += 4;
1139 return num;
1140}
1141
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001142static unsigned char vpd84_data[] = {
1143/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1144 0x22,0x22,0x22,0x0,0xbb,0x1,
1145 0x22,0x22,0x22,0x0,0xbb,0x2,
1146};
1147
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001148/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001149static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001150{
1151 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1152 return sizeof(vpd84_data);
1153}
1154
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001155/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001156static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001157{
1158 int num = 0;
1159 const char * na1 = "https://www.kernel.org/config";
1160 const char * na2 = "http://www.kernel.org/log";
1161 int plen, olen;
1162
1163 arr[num++] = 0x1; /* lu, storage config */
1164 arr[num++] = 0x0; /* reserved */
1165 arr[num++] = 0x0;
1166 olen = strlen(na1);
1167 plen = olen + 1;
1168 if (plen % 4)
1169 plen = ((plen / 4) + 1) * 4;
1170 arr[num++] = plen; /* length, null termianted, padded */
1171 memcpy(arr + num, na1, olen);
1172 memset(arr + num + olen, 0, plen - olen);
1173 num += plen;
1174
1175 arr[num++] = 0x4; /* lu, logging */
1176 arr[num++] = 0x0; /* reserved */
1177 arr[num++] = 0x0;
1178 olen = strlen(na2);
1179 plen = olen + 1;
1180 if (plen % 4)
1181 plen = ((plen / 4) + 1) * 4;
1182 arr[num++] = plen; /* length, null terminated, padded */
1183 memcpy(arr + num, na2, olen);
1184 memset(arr + num + olen, 0, plen - olen);
1185 num += plen;
1186
1187 return num;
1188}
1189
1190/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001191static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001192{
1193 int num = 0;
1194 int port_a, port_b;
1195
1196 port_a = target_dev_id + 1;
1197 port_b = port_a + 1;
1198 arr[num++] = 0x0; /* reserved */
1199 arr[num++] = 0x0; /* reserved */
1200 arr[num++] = 0x0;
1201 arr[num++] = 0x1; /* relative port 1 (primary) */
1202 memset(arr + num, 0, 6);
1203 num += 6;
1204 arr[num++] = 0x0;
1205 arr[num++] = 12; /* length tp descriptor */
1206 /* naa-5 target port identifier (A) */
1207 arr[num++] = 0x61; /* proto=sas, binary */
1208 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1209 arr[num++] = 0x0; /* reserved */
1210 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001211 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001212 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001213 arr[num++] = 0x0; /* reserved */
1214 arr[num++] = 0x0; /* reserved */
1215 arr[num++] = 0x0;
1216 arr[num++] = 0x2; /* relative port 2 (secondary) */
1217 memset(arr + num, 0, 6);
1218 num += 6;
1219 arr[num++] = 0x0;
1220 arr[num++] = 12; /* length tp descriptor */
1221 /* naa-5 target port identifier (B) */
1222 arr[num++] = 0x61; /* proto=sas, binary */
1223 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1224 arr[num++] = 0x0; /* reserved */
1225 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001226 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001227 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001228
1229 return num;
1230}
1231
1232
1233static unsigned char vpd89_data[] = {
1234/* from 4th byte */ 0,0,0,0,
1235'l','i','n','u','x',' ',' ',' ',
1236'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1237'1','2','3','4',
12380x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12390xec,0,0,0,
12400x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12410,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12420x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12430x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12440x53,0x41,
12450x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12460x20,0x20,
12470x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12480x10,0x80,
12490,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12500x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12510x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12520,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12530x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12540x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12550,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12570,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12590x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12600,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12610xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12620,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
12630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12640,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12690,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12730,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12740,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1275};
1276
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001277/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001278static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001279{
1280 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1281 return sizeof(vpd89_data);
1282}
1283
1284
1285static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001286 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1287 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1288 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1289 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001290};
1291
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001292/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001293static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001294{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001295 unsigned int gran;
1296
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001297 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001298
1299 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001300 if (sdebug_opt_xferlen_exp != 0 &&
1301 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1302 gran = 1 << sdebug_opt_xferlen_exp;
1303 else
1304 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001305 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001306
1307 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001308 if (sdebug_store_sectors > 0x400)
1309 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001310
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001311 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001312 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001313
Douglas Gilbert773642d2016-04-25 12:16:28 -04001314 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001315 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001316 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001317
1318 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001319 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001320 }
1321
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001322 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001323 if (sdebug_unmap_alignment) {
1324 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001325 arr[28] |= 0x80; /* UGAVALID */
1326 }
1327
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001328 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001329 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001330
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001331 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001332 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001333
1334 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001335
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001336 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337}
1338
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001339/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001340static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001341{
1342 memset(arr, 0, 0x3c);
1343 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001344 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1345 arr[2] = 0;
1346 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001347
1348 return 0x3c;
1349}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001351/* Logical block provisioning VPD page (SBC-4) */
1352static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001353{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001354 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001355 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001356 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001357 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001358 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001359 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001360 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001361 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001362 if (sdebug_lbprz && scsi_debug_lbp())
1363 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1364 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1365 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1366 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001367 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001368}
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001371#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001373static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
1375 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001376 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001377 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001378 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001379 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Douglas Gilbert773642d2016-04-25 12:16:28 -04001381 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001382 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1383 if (! arr)
1384 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001385 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001386 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001387 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001388 pq_pdt = TYPE_WLUN; /* present, wlun */
1389 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1390 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001391 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001392 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 arr[0] = pq_pdt;
1394 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001395 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001396 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 return check_condition_result;
1398 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001399 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001400 char lu_id_str[6];
1401 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001403 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1404 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001405 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001406 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001407 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001408 (devip->target * 1000) + devip->lun);
1409 target_dev_id = ((host_no + 1) * 2000) +
1410 (devip->target * 1000) - 3;
1411 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001413 arr[1] = cmd[2]; /*sanity */
1414 n = 4;
1415 arr[n++] = 0x0; /* this page */
1416 arr[n++] = 0x80; /* unit serial number */
1417 arr[n++] = 0x83; /* device identification */
1418 arr[n++] = 0x84; /* software interface ident. */
1419 arr[n++] = 0x85; /* management network addresses */
1420 arr[n++] = 0x86; /* extended inquiry */
1421 arr[n++] = 0x87; /* mode page policy */
1422 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001423 if (is_disk) { /* SBC only */
1424 arr[n++] = 0x89; /* ATA information */
1425 arr[n++] = 0xb0; /* Block limits */
1426 arr[n++] = 0xb1; /* Block characteristics */
1427 arr[n++] = 0xb2; /* Logical Block Prov */
1428 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001429 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001431 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001433 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001435 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001436 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1437 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001438 lu_id_str, len,
1439 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001440 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1441 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001442 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001443 } else if (0x85 == cmd[2]) { /* Management network addresses */
1444 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001445 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001446 } else if (0x86 == cmd[2]) { /* extended inquiry */
1447 arr[1] = cmd[2]; /*sanity */
1448 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001449 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001450 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001451 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001452 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1453 else
1454 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001455 arr[5] = 0x7; /* head of q, ordered + simple q's */
1456 } else if (0x87 == cmd[2]) { /* mode page policy */
1457 arr[1] = cmd[2]; /*sanity */
1458 arr[3] = 0x8; /* number of following entries */
1459 arr[4] = 0x2; /* disconnect-reconnect mp */
1460 arr[6] = 0x80; /* mlus, shared */
1461 arr[8] = 0x18; /* protocol specific lu */
1462 arr[10] = 0x82; /* mlus, per initiator port */
1463 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1464 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001465 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1466 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001467 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001468 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001469 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001470 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001471 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001472 arr[3] = inquiry_vpd_b0(&arr[4]);
1473 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001474 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001475 arr[3] = inquiry_vpd_b1(&arr[4]);
1476 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001477 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001478 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001480 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001481 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 return check_condition_result;
1483 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001484 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001485 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001486 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001487 kfree(arr);
1488 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 }
1490 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001491 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1492 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 arr[3] = 2; /* response_data_format==2 */
1494 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001495 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001496 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001497 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001498 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001500 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001501 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1502 memcpy(&arr[16], sdebug_inq_product_id, 16);
1503 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001504 /* Use Vendor Specific area to place driver date in ASCII hex */
1505 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001507 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1508 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001509 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001510 if (is_disk) { /* SBC-4 no version claimed */
1511 put_unaligned_be16(0x600, arr + n);
1512 n += 2;
1513 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1514 put_unaligned_be16(0x525, arr + n);
1515 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001517 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001518 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001520 kfree(arr);
1521 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522}
1523
Douglas Gilbertfd321192016-04-25 12:16:33 -04001524static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1525 0, 0, 0x0, 0x0};
1526
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527static int resp_requests(struct scsi_cmnd * scp,
1528 struct sdebug_dev_info * devip)
1529{
1530 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001531 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001532 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001533 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 int len = 18;
1535
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001536 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001537 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001538 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001539 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001540 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001541 arr[0] = 0x72;
1542 arr[1] = 0x0; /* NO_SENSE in sense_key */
1543 arr[2] = THRESHOLD_EXCEEDED;
1544 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001545 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001546 } else {
1547 arr[0] = 0x70;
1548 arr[2] = 0x0; /* NO_SENSE in sense_key */
1549 arr[7] = 0xa; /* 18 byte sense buffer */
1550 arr[12] = THRESHOLD_EXCEEDED;
1551 arr[13] = 0xff; /* TEST set and MRIE==6 */
1552 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001553 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001554 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001555 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001556 ; /* have sense and formats match */
1557 else if (arr[0] <= 0x70) {
1558 if (dsense) {
1559 memset(arr, 0, 8);
1560 arr[0] = 0x72;
1561 len = 8;
1562 } else {
1563 memset(arr, 0, 18);
1564 arr[0] = 0x70;
1565 arr[7] = 0xa;
1566 }
1567 } else if (dsense) {
1568 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001569 arr[0] = 0x72;
1570 arr[1] = sbuff[2]; /* sense key */
1571 arr[2] = sbuff[12]; /* asc */
1572 arr[3] = sbuff[13]; /* ascq */
1573 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001574 } else {
1575 memset(arr, 0, 18);
1576 arr[0] = 0x70;
1577 arr[2] = sbuff[1];
1578 arr[7] = 0xa;
1579 arr[12] = sbuff[1];
1580 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001581 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001582
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001583 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001584 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 return fill_from_dev_buffer(scp, arr, len);
1586}
1587
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001588static int resp_start_stop(struct scsi_cmnd * scp,
1589 struct sdebug_dev_info * devip)
1590{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001591 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001592 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001593
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001594 power_cond = (cmd[4] & 0xf0) >> 4;
1595 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001596 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001597 return check_condition_result;
1598 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001599 stop = !(cmd[4] & 1);
1600 atomic_xchg(&devip->stopped, stop);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001601 return 0;
1602}
1603
FUJITA Tomonori28898872008-03-30 00:59:55 +09001604static sector_t get_sdebug_capacity(void)
1605{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001606 static const unsigned int gibibyte = 1073741824;
1607
1608 if (sdebug_virtual_gb > 0)
1609 return (sector_t)sdebug_virtual_gb *
1610 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001611 else
1612 return sdebug_store_sectors;
1613}
1614
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615#define SDEBUG_READCAP_ARR_SZ 8
1616static int resp_readcap(struct scsi_cmnd * scp,
1617 struct sdebug_dev_info * devip)
1618{
1619 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001620 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001622 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001623 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001625 if (sdebug_capacity < 0xffffffff) {
1626 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001627 put_unaligned_be32(capac, arr + 0);
1628 } else
1629 put_unaligned_be32(0xffffffff, arr + 0);
1630 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1632}
1633
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001634#define SDEBUG_READCAP16_ARR_SZ 32
1635static int resp_readcap16(struct scsi_cmnd * scp,
1636 struct sdebug_dev_info * devip)
1637{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001638 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001639 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001640 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001641
Douglas Gilbert773642d2016-04-25 12:16:28 -04001642 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001643 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001644 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001645 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001646 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1647 put_unaligned_be32(sdebug_sector_size, arr + 8);
1648 arr[13] = sdebug_physblk_exp & 0xf;
1649 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001650
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001651 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001652 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001653 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1654 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1655 * in the wider field maps to 0 in this field.
1656 */
1657 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1658 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001659 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001660
Douglas Gilbert773642d2016-04-25 12:16:28 -04001661 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001662
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001663 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001664 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001665 arr[12] |= 1; /* PROT_EN */
1666 }
1667
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001668 return fill_from_dev_buffer(scp, arr,
1669 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1670}
1671
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001672#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1673
1674static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1675 struct sdebug_dev_info * devip)
1676{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001677 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001678 unsigned char * arr;
1679 int host_no = devip->sdbg_host->shost->host_no;
1680 int n, ret, alen, rlen;
1681 int port_group_a, port_group_b, port_a, port_b;
1682
Douglas Gilbert773642d2016-04-25 12:16:28 -04001683 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001684 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1685 if (! arr)
1686 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001687 /*
1688 * EVPD page 0x88 states we have two ports, one
1689 * real and a fake port with no device connected.
1690 * So we create two port groups with one port each
1691 * and set the group with port B to unavailable.
1692 */
1693 port_a = 0x1; /* relative port A */
1694 port_b = 0x2; /* relative port B */
1695 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001696 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001697 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001698 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001699
1700 /*
1701 * The asymmetric access state is cycled according to the host_id.
1702 */
1703 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001704 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001705 arr[n++] = host_no % 3; /* Asymm access state */
1706 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001707 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001708 arr[n++] = 0x0; /* Active/Optimized path */
1709 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001710 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001711 put_unaligned_be16(port_group_a, arr + n);
1712 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001713 arr[n++] = 0; /* Reserved */
1714 arr[n++] = 0; /* Status code */
1715 arr[n++] = 0; /* Vendor unique */
1716 arr[n++] = 0x1; /* One port per group */
1717 arr[n++] = 0; /* Reserved */
1718 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001719 put_unaligned_be16(port_a, arr + n);
1720 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001721 arr[n++] = 3; /* Port unavailable */
1722 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001723 put_unaligned_be16(port_group_b, arr + n);
1724 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001725 arr[n++] = 0; /* Reserved */
1726 arr[n++] = 0; /* Status code */
1727 arr[n++] = 0; /* Vendor unique */
1728 arr[n++] = 0x1; /* One port per group */
1729 arr[n++] = 0; /* Reserved */
1730 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001731 put_unaligned_be16(port_b, arr + n);
1732 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001733
1734 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001735 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001736
1737 /*
1738 * Return the smallest value of either
1739 * - The allocated length
1740 * - The constructed command length
1741 * - The maximum array size
1742 */
1743 rlen = min(alen,n);
1744 ret = fill_from_dev_buffer(scp, arr,
1745 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1746 kfree(arr);
1747 return ret;
1748}
1749
Douglas Gilbertfd321192016-04-25 12:16:33 -04001750static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1751 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001752{
1753 bool rctd;
1754 u8 reporting_opts, req_opcode, sdeb_i, supp;
1755 u16 req_sa, u;
1756 u32 alloc_len, a_len;
1757 int k, offset, len, errsts, count, bump, na;
1758 const struct opcode_info_t *oip;
1759 const struct opcode_info_t *r_oip;
1760 u8 *arr;
1761 u8 *cmd = scp->cmnd;
1762
1763 rctd = !!(cmd[2] & 0x80);
1764 reporting_opts = cmd[2] & 0x7;
1765 req_opcode = cmd[3];
1766 req_sa = get_unaligned_be16(cmd + 4);
1767 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001768 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001769 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1770 return check_condition_result;
1771 }
1772 if (alloc_len > 8192)
1773 a_len = 8192;
1774 else
1775 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001776 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001777 if (NULL == arr) {
1778 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1779 INSUFF_RES_ASCQ);
1780 return check_condition_result;
1781 }
1782 switch (reporting_opts) {
1783 case 0: /* all commands */
1784 /* count number of commands */
1785 for (count = 0, oip = opcode_info_arr;
1786 oip->num_attached != 0xff; ++oip) {
1787 if (F_INV_OP & oip->flags)
1788 continue;
1789 count += (oip->num_attached + 1);
1790 }
1791 bump = rctd ? 20 : 8;
1792 put_unaligned_be32(count * bump, arr);
1793 for (offset = 4, oip = opcode_info_arr;
1794 oip->num_attached != 0xff && offset < a_len; ++oip) {
1795 if (F_INV_OP & oip->flags)
1796 continue;
1797 na = oip->num_attached;
1798 arr[offset] = oip->opcode;
1799 put_unaligned_be16(oip->sa, arr + offset + 2);
1800 if (rctd)
1801 arr[offset + 5] |= 0x2;
1802 if (FF_SA & oip->flags)
1803 arr[offset + 5] |= 0x1;
1804 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1805 if (rctd)
1806 put_unaligned_be16(0xa, arr + offset + 8);
1807 r_oip = oip;
1808 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1809 if (F_INV_OP & oip->flags)
1810 continue;
1811 offset += bump;
1812 arr[offset] = oip->opcode;
1813 put_unaligned_be16(oip->sa, arr + offset + 2);
1814 if (rctd)
1815 arr[offset + 5] |= 0x2;
1816 if (FF_SA & oip->flags)
1817 arr[offset + 5] |= 0x1;
1818 put_unaligned_be16(oip->len_mask[0],
1819 arr + offset + 6);
1820 if (rctd)
1821 put_unaligned_be16(0xa,
1822 arr + offset + 8);
1823 }
1824 oip = r_oip;
1825 offset += bump;
1826 }
1827 break;
1828 case 1: /* one command: opcode only */
1829 case 2: /* one command: opcode plus service action */
1830 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1831 sdeb_i = opcode_ind_arr[req_opcode];
1832 oip = &opcode_info_arr[sdeb_i];
1833 if (F_INV_OP & oip->flags) {
1834 supp = 1;
1835 offset = 4;
1836 } else {
1837 if (1 == reporting_opts) {
1838 if (FF_SA & oip->flags) {
1839 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1840 2, 2);
1841 kfree(arr);
1842 return check_condition_result;
1843 }
1844 req_sa = 0;
1845 } else if (2 == reporting_opts &&
1846 0 == (FF_SA & oip->flags)) {
1847 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1848 kfree(arr); /* point at requested sa */
1849 return check_condition_result;
1850 }
1851 if (0 == (FF_SA & oip->flags) &&
1852 req_opcode == oip->opcode)
1853 supp = 3;
1854 else if (0 == (FF_SA & oip->flags)) {
1855 na = oip->num_attached;
1856 for (k = 0, oip = oip->arrp; k < na;
1857 ++k, ++oip) {
1858 if (req_opcode == oip->opcode)
1859 break;
1860 }
1861 supp = (k >= na) ? 1 : 3;
1862 } else if (req_sa != oip->sa) {
1863 na = oip->num_attached;
1864 for (k = 0, oip = oip->arrp; k < na;
1865 ++k, ++oip) {
1866 if (req_sa == oip->sa)
1867 break;
1868 }
1869 supp = (k >= na) ? 1 : 3;
1870 } else
1871 supp = 3;
1872 if (3 == supp) {
1873 u = oip->len_mask[0];
1874 put_unaligned_be16(u, arr + 2);
1875 arr[4] = oip->opcode;
1876 for (k = 1; k < u; ++k)
1877 arr[4 + k] = (k < 16) ?
1878 oip->len_mask[k] : 0xff;
1879 offset = 4 + u;
1880 } else
1881 offset = 4;
1882 }
1883 arr[1] = (rctd ? 0x80 : 0) | supp;
1884 if (rctd) {
1885 put_unaligned_be16(0xa, arr + offset);
1886 offset += 12;
1887 }
1888 break;
1889 default:
1890 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1891 kfree(arr);
1892 return check_condition_result;
1893 }
1894 offset = (offset < a_len) ? offset : a_len;
1895 len = (offset < alloc_len) ? offset : alloc_len;
1896 errsts = fill_from_dev_buffer(scp, arr, len);
1897 kfree(arr);
1898 return errsts;
1899}
1900
Douglas Gilbertfd321192016-04-25 12:16:33 -04001901static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1902 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001903{
1904 bool repd;
1905 u32 alloc_len, len;
1906 u8 arr[16];
1907 u8 *cmd = scp->cmnd;
1908
1909 memset(arr, 0, sizeof(arr));
1910 repd = !!(cmd[2] & 0x80);
1911 alloc_len = get_unaligned_be32(cmd + 6);
1912 if (alloc_len < 4) {
1913 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1914 return check_condition_result;
1915 }
1916 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1917 arr[1] = 0x1; /* ITNRS */
1918 if (repd) {
1919 arr[3] = 0xc;
1920 len = 16;
1921 } else
1922 len = 4;
1923
1924 len = (len < alloc_len) ? len : alloc_len;
1925 return fill_from_dev_buffer(scp, arr, len);
1926}
1927
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928/* <<Following mode page info copied from ST318451LW>> */
1929
1930static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1931{ /* Read-Write Error Recovery page for mode_sense */
1932 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1933 5, 0, 0xff, 0xff};
1934
1935 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1936 if (1 == pcontrol)
1937 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1938 return sizeof(err_recov_pg);
1939}
1940
1941static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1942{ /* Disconnect-Reconnect page for mode_sense */
1943 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1944 0, 0, 0, 0, 0, 0, 0, 0};
1945
1946 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1947 if (1 == pcontrol)
1948 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1949 return sizeof(disconnect_pg);
1950}
1951
1952static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1953{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001954 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1955 0, 0, 0, 0, 0, 0, 0, 0,
1956 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Martin K. Petersen597136a2008-06-05 00:12:59 -04001958 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001959 put_unaligned_be16(sdebug_sectors_per, p + 10);
1960 put_unaligned_be16(sdebug_sector_size, p + 12);
1961 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001962 p[20] |= 0x20; /* should agree with INQUIRY */
1963 if (1 == pcontrol)
1964 memset(p + 2, 0, sizeof(format_pg) - 2);
1965 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966}
1967
Douglas Gilbertfd321192016-04-25 12:16:33 -04001968static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1969 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1970 0, 0, 0, 0};
1971
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1973{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001974 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1975 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1976 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1978
Douglas Gilbert773642d2016-04-25 12:16:28 -04001979 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001980 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 memcpy(p, caching_pg, sizeof(caching_pg));
1982 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001983 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1984 else if (2 == pcontrol)
1985 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 return sizeof(caching_pg);
1987}
1988
Douglas Gilbertfd321192016-04-25 12:16:33 -04001989static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1990 0, 0, 0x2, 0x4b};
1991
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1993{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001994 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05001995 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001996 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 0, 0, 0x2, 0x4b};
1998
Douglas Gilbert773642d2016-04-25 12:16:28 -04001999 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002001 else
2002 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002003
Douglas Gilbert773642d2016-04-25 12:16:28 -04002004 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002005 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2008 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002009 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2010 else if (2 == pcontrol)
2011 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 return sizeof(ctrl_m_pg);
2013}
2014
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002015
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
2017{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002018 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2019 0, 0, 0x0, 0x0};
2020 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2021 0, 0, 0x0, 0x0};
2022
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2024 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002025 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2026 else if (2 == pcontrol)
2027 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 return sizeof(iec_m_pg);
2029}
2030
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002031static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
2032{ /* SAS SSP mode page - short format for mode_sense */
2033 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2034 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2035
2036 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2037 if (1 == pcontrol)
2038 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2039 return sizeof(sas_sf_m_pg);
2040}
2041
2042
2043static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
2044 int target_dev_id)
2045{ /* SAS phy control and discover mode page for mode_sense */
2046 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2047 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002048 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2049 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002050 0x2, 0, 0, 0, 0, 0, 0, 0,
2051 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2052 0, 0, 0, 0, 0, 0, 0, 0,
2053 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002054 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2055 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002056 0x3, 0, 0, 0, 0, 0, 0, 0,
2057 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2058 0, 0, 0, 0, 0, 0, 0, 0,
2059 };
2060 int port_a, port_b;
2061
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002062 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2063 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2064 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2065 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002066 port_a = target_dev_id + 1;
2067 port_b = port_a + 1;
2068 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002069 put_unaligned_be32(port_a, p + 20);
2070 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002071 if (1 == pcontrol)
2072 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2073 return sizeof(sas_pcd_m_pg);
2074}
2075
2076static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
2077{ /* SAS SSP shared protocol specific port mode subpage */
2078 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2079 0, 0, 0, 0, 0, 0, 0, 0,
2080 };
2081
2082 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2083 if (1 == pcontrol)
2084 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2085 return sizeof(sas_sha_m_pg);
2086}
2087
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088#define SDEBUG_MAX_MSENSE_SZ 256
2089
Douglas Gilbertfd321192016-04-25 12:16:33 -04002090static int resp_mode_sense(struct scsi_cmnd *scp,
2091 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092{
Douglas Gilbert23183912006-09-16 20:30:47 -04002093 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002095 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002096 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 unsigned char * ap;
2098 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002099 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002100 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002102 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 pcontrol = (cmd[2] & 0xc0) >> 6;
2104 pcode = cmd[2] & 0x3f;
2105 subpcode = cmd[3];
2106 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002107 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2108 is_disk = (sdebug_ptype == TYPE_DISK);
2109 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002110 bd_len = llbaa ? 16 : 8;
2111 else
2112 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002113 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2115 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002116 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 return check_condition_result;
2118 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002119 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2120 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002121 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002122 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002123 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002124 else
2125 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 if (msense_6) {
2127 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002128 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 offset = 4;
2130 } else {
2131 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002132 if (16 == bd_len)
2133 arr[4] = 0x1; /* set LONGLBA bit */
2134 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 offset = 8;
2136 }
2137 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002138 if ((bd_len > 0) && (!sdebug_capacity))
2139 sdebug_capacity = get_sdebug_capacity();
2140
Douglas Gilbert23183912006-09-16 20:30:47 -04002141 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002142 if (sdebug_capacity > 0xfffffffe)
2143 put_unaligned_be32(0xffffffff, ap + 0);
2144 else
2145 put_unaligned_be32(sdebug_capacity, ap + 0);
2146 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002147 offset += bd_len;
2148 ap = arr + offset;
2149 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002150 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2151 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002152 offset += bd_len;
2153 ap = arr + offset;
2154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002156 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2157 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002158 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 return check_condition_result;
2160 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002161 bad_pcode = false;
2162
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 switch (pcode) {
2164 case 0x1: /* Read-Write error recovery page, direct access */
2165 len = resp_err_recov_pg(ap, pcontrol, target);
2166 offset += len;
2167 break;
2168 case 0x2: /* Disconnect-Reconnect page, all devices */
2169 len = resp_disconnect_pg(ap, pcontrol, target);
2170 offset += len;
2171 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002172 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002173 if (is_disk) {
2174 len = resp_format_pg(ap, pcontrol, target);
2175 offset += len;
2176 } else
2177 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002178 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002180 if (is_disk) {
2181 len = resp_caching_pg(ap, pcontrol, target);
2182 offset += len;
2183 } else
2184 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 break;
2186 case 0xa: /* Control Mode page, all devices */
2187 len = resp_ctrl_m_pg(ap, pcontrol, target);
2188 offset += len;
2189 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002190 case 0x19: /* if spc==1 then sas phy, control+discover */
2191 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002192 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002193 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002194 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002195 len = 0;
2196 if ((0x0 == subpcode) || (0xff == subpcode))
2197 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2198 if ((0x1 == subpcode) || (0xff == subpcode))
2199 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2200 target_dev_id);
2201 if ((0x2 == subpcode) || (0xff == subpcode))
2202 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2203 offset += len;
2204 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 case 0x1c: /* Informational Exceptions Mode page, all devices */
2206 len = resp_iec_m_pg(ap, pcontrol, target);
2207 offset += len;
2208 break;
2209 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002210 if ((0 == subpcode) || (0xff == subpcode)) {
2211 len = resp_err_recov_pg(ap, pcontrol, target);
2212 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002213 if (is_disk) {
2214 len += resp_format_pg(ap + len, pcontrol,
2215 target);
2216 len += resp_caching_pg(ap + len, pcontrol,
2217 target);
2218 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002219 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2220 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2221 if (0xff == subpcode) {
2222 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2223 target, target_dev_id);
2224 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2225 }
2226 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002227 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002228 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002229 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002230 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 break;
2233 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002234 bad_pcode = true;
2235 break;
2236 }
2237 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002238 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 return check_condition_result;
2240 }
2241 if (msense_6)
2242 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002243 else
2244 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2246}
2247
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002248#define SDEBUG_MAX_MSELECT_SZ 512
2249
Douglas Gilbertfd321192016-04-25 12:16:33 -04002250static int resp_mode_select(struct scsi_cmnd *scp,
2251 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002252{
2253 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002254 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002255 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002256 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002257 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002258
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002259 memset(arr, 0, sizeof(arr));
2260 pf = cmd[1] & 0x10;
2261 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002262 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002263 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002264 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002265 return check_condition_result;
2266 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002267 res = fetch_to_dev_buffer(scp, arr, param_len);
2268 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002269 return DID_ERROR << 16;
2270 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002271 sdev_printk(KERN_INFO, scp->device,
2272 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2273 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002274 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2275 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002276 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002277 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002278 return check_condition_result;
2279 }
2280 off = bd_len + (mselect6 ? 4 : 8);
2281 mpage = arr[off] & 0x3f;
2282 ps = !!(arr[off] & 0x80);
2283 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002284 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002285 return check_condition_result;
2286 }
2287 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002288 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002289 (arr[off + 1] + 2);
2290 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002291 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002292 PARAMETER_LIST_LENGTH_ERR, 0);
2293 return check_condition_result;
2294 }
2295 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002296 case 0x8: /* Caching Mode page */
2297 if (caching_pg[1] == arr[off + 1]) {
2298 memcpy(caching_pg + 2, arr + off + 2,
2299 sizeof(caching_pg) - 2);
2300 goto set_mode_changed_ua;
2301 }
2302 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002303 case 0xa: /* Control Mode page */
2304 if (ctrl_m_pg[1] == arr[off + 1]) {
2305 memcpy(ctrl_m_pg + 2, arr + off + 2,
2306 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002307 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002308 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002309 }
2310 break;
2311 case 0x1c: /* Informational Exceptions Mode page */
2312 if (iec_m_pg[1] == arr[off + 1]) {
2313 memcpy(iec_m_pg + 2, arr + off + 2,
2314 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002315 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002316 }
2317 break;
2318 default:
2319 break;
2320 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002321 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002322 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002323set_mode_changed_ua:
2324 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2325 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002326}
2327
2328static int resp_temp_l_pg(unsigned char * arr)
2329{
2330 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2331 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2332 };
2333
Douglas Gilbert9a051012017-12-23 12:48:10 -05002334 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2335 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002336}
2337
2338static int resp_ie_l_pg(unsigned char * arr)
2339{
2340 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2341 };
2342
Douglas Gilbert9a051012017-12-23 12:48:10 -05002343 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002344 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2345 arr[4] = THRESHOLD_EXCEEDED;
2346 arr[5] = 0xff;
2347 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002348 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002349}
2350
2351#define SDEBUG_MAX_LSENSE_SZ 512
2352
Douglas Gilbert9a051012017-12-23 12:48:10 -05002353static int resp_log_sense(struct scsi_cmnd *scp,
2354 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002355{
Bart Van Asscheab172412017-08-25 13:46:42 -07002356 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002357 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002358 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002359
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002360 memset(arr, 0, sizeof(arr));
2361 ppc = cmd[1] & 0x2;
2362 sp = cmd[1] & 0x1;
2363 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002364 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002365 return check_condition_result;
2366 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002367 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002368 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002369 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002370 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002371 if (0 == subpcode) {
2372 switch (pcode) {
2373 case 0x0: /* Supported log pages log page */
2374 n = 4;
2375 arr[n++] = 0x0; /* this page */
2376 arr[n++] = 0xd; /* Temperature */
2377 arr[n++] = 0x2f; /* Informational exceptions */
2378 arr[3] = n - 4;
2379 break;
2380 case 0xd: /* Temperature log page */
2381 arr[3] = resp_temp_l_pg(arr + 4);
2382 break;
2383 case 0x2f: /* Informational exceptions log page */
2384 arr[3] = resp_ie_l_pg(arr + 4);
2385 break;
2386 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002387 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002388 return check_condition_result;
2389 }
2390 } else if (0xff == subpcode) {
2391 arr[0] |= 0x40;
2392 arr[1] = subpcode;
2393 switch (pcode) {
2394 case 0x0: /* Supported log pages and subpages log page */
2395 n = 4;
2396 arr[n++] = 0x0;
2397 arr[n++] = 0x0; /* 0,0 page */
2398 arr[n++] = 0x0;
2399 arr[n++] = 0xff; /* this page */
2400 arr[n++] = 0xd;
2401 arr[n++] = 0x0; /* Temperature */
2402 arr[n++] = 0x2f;
2403 arr[n++] = 0x0; /* Informational exceptions */
2404 arr[3] = n - 4;
2405 break;
2406 case 0xd: /* Temperature subpages */
2407 n = 4;
2408 arr[n++] = 0xd;
2409 arr[n++] = 0x0; /* Temperature */
2410 arr[3] = n - 4;
2411 break;
2412 case 0x2f: /* Informational exceptions subpages */
2413 n = 4;
2414 arr[n++] = 0x2f;
2415 arr[n++] = 0x0; /* Informational exceptions */
2416 arr[3] = n - 4;
2417 break;
2418 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002419 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002420 return check_condition_result;
2421 }
2422 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002423 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002424 return check_condition_result;
2425 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002426 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002427 return fill_from_dev_buffer(scp, arr,
2428 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2429}
2430
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002431static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002432 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002434 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002435 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 return check_condition_result;
2437 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002438 /* transfer length excessive (tie in to block limits VPD page) */
2439 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002440 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002441 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002442 return check_condition_result;
2443 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002444 return 0;
2445}
2446
Akinobu Mitaa4517512013-07-08 16:01:57 -07002447/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002448static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2449 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002450{
2451 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002452 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002453 struct scsi_data_buffer *sdb;
2454 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002455
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002456 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002457 sdb = scsi_out(scmd);
2458 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002459 } else {
2460 sdb = scsi_in(scmd);
2461 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002462 }
2463
2464 if (!sdb->length)
2465 return 0;
2466 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2467 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002468
2469 block = do_div(lba, sdebug_store_sectors);
2470 if (block + num > sdebug_store_sectors)
2471 rest = block + num - sdebug_store_sectors;
2472
Dave Gordon386ecb12015-06-30 14:58:57 -07002473 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002474 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002475 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002476 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002477 return ret;
2478
2479 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002480 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002481 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002482 sg_skip + ((num - rest) * sdebug_sector_size),
2483 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002484 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002485
2486 return ret;
2487}
2488
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002489/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2490 * arr into fake_store(lba,num) and return true. If comparison fails then
2491 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002492static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002493{
2494 bool res;
2495 u64 block, rest = 0;
2496 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002497 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002498
2499 block = do_div(lba, store_blks);
2500 if (block + num > store_blks)
2501 rest = block + num - store_blks;
2502
2503 res = !memcmp(fake_storep + (block * lb_size), arr,
2504 (num - rest) * lb_size);
2505 if (!res)
2506 return res;
2507 if (rest)
2508 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2509 rest * lb_size);
2510 if (!res)
2511 return res;
2512 arr += num * lb_size;
2513 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2514 if (rest)
2515 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2516 rest * lb_size);
2517 return res;
2518}
2519
Akinobu Mita51d648a2013-09-18 21:27:28 +09002520static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002521{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002522 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002523
Douglas Gilbert773642d2016-04-25 12:16:28 -04002524 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002525 csum = (__force __be16)ip_compute_csum(buf, len);
2526 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002527 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002528
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002529 return csum;
2530}
2531
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002532static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002533 sector_t sector, u32 ei_lba)
2534{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002535 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002536
2537 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002538 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002539 (unsigned long)sector,
2540 be16_to_cpu(sdt->guard_tag),
2541 be16_to_cpu(csum));
2542 return 0x01;
2543 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002544 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002545 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002546 pr_err("REF check failed on sector %lu\n",
2547 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002548 return 0x03;
2549 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002550 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002551 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002552 pr_err("REF check failed on sector %lu\n",
2553 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002554 return 0x03;
2555 }
2556 return 0;
2557}
2558
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002559static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002560 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002561{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002562 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002563 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002564 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002565 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002566
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002567 /* Bytes of protection data to copy into sgl */
2568 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002569
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002570 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2571 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2572 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2573
2574 while (sg_miter_next(&miter) && resid > 0) {
2575 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002576 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002577 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002578
2579 if (dif_store_end < start + len)
2580 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002581
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002582 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002583
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002584 if (read)
2585 memcpy(paddr, start, len - rest);
2586 else
2587 memcpy(start, paddr, len - rest);
2588
2589 if (rest) {
2590 if (read)
2591 memcpy(paddr + len - rest, dif_storep, rest);
2592 else
2593 memcpy(dif_storep, paddr + len - rest, rest);
2594 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002595
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002596 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002597 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002598 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002599 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002600}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002601
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002602static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2603 unsigned int sectors, u32 ei_lba)
2604{
2605 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002606 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002607 sector_t sector;
2608
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002609 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002610 int ret;
2611
2612 sector = start_sec + i;
2613 sdt = dif_store(sector);
2614
Akinobu Mita51d648a2013-09-18 21:27:28 +09002615 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002616 continue;
2617
2618 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2619 if (ret) {
2620 dif_errors++;
2621 return ret;
2622 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002623 }
2624
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002625 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002626 dix_reads++;
2627
2628 return 0;
2629}
2630
Douglas Gilbertfd321192016-04-25 12:16:33 -04002631static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002632{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002633 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002634 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002635 u64 lba;
2636 u32 num;
2637 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002638 unsigned long iflags;
2639 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002640 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002641
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002642 switch (cmd[0]) {
2643 case READ_16:
2644 ei_lba = 0;
2645 lba = get_unaligned_be64(cmd + 2);
2646 num = get_unaligned_be32(cmd + 10);
2647 check_prot = true;
2648 break;
2649 case READ_10:
2650 ei_lba = 0;
2651 lba = get_unaligned_be32(cmd + 2);
2652 num = get_unaligned_be16(cmd + 7);
2653 check_prot = true;
2654 break;
2655 case READ_6:
2656 ei_lba = 0;
2657 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2658 (u32)(cmd[1] & 0x1f) << 16;
2659 num = (0 == cmd[4]) ? 256 : cmd[4];
2660 check_prot = true;
2661 break;
2662 case READ_12:
2663 ei_lba = 0;
2664 lba = get_unaligned_be32(cmd + 2);
2665 num = get_unaligned_be32(cmd + 6);
2666 check_prot = true;
2667 break;
2668 case XDWRITEREAD_10:
2669 ei_lba = 0;
2670 lba = get_unaligned_be32(cmd + 2);
2671 num = get_unaligned_be16(cmd + 7);
2672 check_prot = false;
2673 break;
2674 default: /* assume READ(32) */
2675 lba = get_unaligned_be64(cmd + 12);
2676 ei_lba = get_unaligned_be32(cmd + 20);
2677 num = get_unaligned_be32(cmd + 28);
2678 check_prot = false;
2679 break;
2680 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002681 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002682 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002683 (cmd[1] & 0xe0)) {
2684 mk_sense_invalid_opcode(scp);
2685 return check_condition_result;
2686 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002687 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2688 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002689 (cmd[1] & 0xe0) == 0)
2690 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2691 "to DIF device\n");
2692 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002693 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002694 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002695
Douglas Gilbertc4837392016-05-06 00:40:26 -04002696 if (sqcp) {
2697 if (sqcp->inj_short)
2698 num /= 2;
2699 }
2700 } else
2701 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002702
2703 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002704 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002705 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2706 return check_condition_result;
2707 }
2708 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002709 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002710 /* needs work to find which cdb byte 'num' comes from */
2711 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2712 return check_condition_result;
2713 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002714
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002715 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05002716 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2717 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002718 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002719 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002720 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002721 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2722 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002723 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2724 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002725 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002726 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002727 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 return check_condition_result;
2729 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002730
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002731 read_lock_irqsave(&atomic_rw, iflags);
2732
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002733 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002734 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002735 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002736
2737 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002738 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002739 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002740 return illegal_condition_result;
2741 }
2742 }
2743
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002744 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002746 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002747 return DID_ERROR << 16;
2748
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002749 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002750
Douglas Gilbertc4837392016-05-06 00:40:26 -04002751 if (unlikely(sqcp)) {
2752 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002753 mk_sense_buffer(scp, RECOVERED_ERROR,
2754 THRESHOLD_EXCEEDED, 0);
2755 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002756 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002757 mk_sense_buffer(scp, ABORTED_COMMAND,
2758 TRANSPORT_PROBLEM, ACK_NAK_TO);
2759 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002760 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002761 /* Logical block guard check failed */
2762 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2763 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002764 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002765 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2766 return illegal_condition_result;
2767 }
2768 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002769 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770}
2771
Tomas Winkler58a86352015-07-28 16:54:23 +03002772static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002773{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002774 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002775
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002776 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002777 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002778 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002779
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002780 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002781 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002782
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002783 if (c >= 0x20 && c < 0x7e)
2784 n += scnprintf(b + n, sizeof(b) - n,
2785 " %c ", buf[i+j]);
2786 else
2787 n += scnprintf(b + n, sizeof(b) - n,
2788 "%02x ", buf[i+j]);
2789 }
2790 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002791 }
2792}
2793
2794static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002795 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002796{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002797 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002798 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002799 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002800 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002801 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002802 int dpage_offset;
2803 struct sg_mapping_iter diter;
2804 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002805
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002806 BUG_ON(scsi_sg_count(SCpnt) == 0);
2807 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2808
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002809 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2810 scsi_prot_sg_count(SCpnt),
2811 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2812 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2813 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002814
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002815 /* For each protection page */
2816 while (sg_miter_next(&piter)) {
2817 dpage_offset = 0;
2818 if (WARN_ON(!sg_miter_next(&diter))) {
2819 ret = 0x01;
2820 goto out;
2821 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002822
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002823 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002824 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002825 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002826 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002827 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002828 if (dpage_offset >= diter.length) {
2829 if (WARN_ON(!sg_miter_next(&diter))) {
2830 ret = 0x01;
2831 goto out;
2832 }
2833 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002834 }
2835
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002836 sdt = piter.addr + ppage_offset;
2837 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002838
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002839 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002840 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002841 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002842 goto out;
2843 }
2844
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002845 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002846 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002847 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002848 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002849 diter.consumed = dpage_offset;
2850 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002851 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002852 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002853
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002854 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002855 dix_writes++;
2856
2857 return 0;
2858
2859out:
2860 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002861 sg_miter_stop(&diter);
2862 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002863 return ret;
2864}
2865
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002866static unsigned long lba_to_map_index(sector_t lba)
2867{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002868 if (sdebug_unmap_alignment)
2869 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2870 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002871 return lba;
2872}
2873
2874static sector_t map_index_to_lba(unsigned long index)
2875{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002876 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002877
Douglas Gilbert773642d2016-04-25 12:16:28 -04002878 if (sdebug_unmap_alignment)
2879 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002880 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002881}
2882
Martin K. Petersen44d92692009-10-15 14:45:27 -04002883static unsigned int map_state(sector_t lba, unsigned int *num)
2884{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002885 sector_t end;
2886 unsigned int mapped;
2887 unsigned long index;
2888 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002889
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002890 index = lba_to_map_index(lba);
2891 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002892
2893 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002894 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002895 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002896 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002897
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002898 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002899 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002900 return mapped;
2901}
2902
2903static void map_region(sector_t lba, unsigned int len)
2904{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002905 sector_t end = lba + len;
2906
Martin K. Petersen44d92692009-10-15 14:45:27 -04002907 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002908 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002909
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002910 if (index < map_size)
2911 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002912
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002913 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002914 }
2915}
2916
2917static void unmap_region(sector_t lba, unsigned int len)
2918{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002919 sector_t end = lba + len;
2920
Martin K. Petersen44d92692009-10-15 14:45:27 -04002921 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002922 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002923
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002924 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002925 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002926 index < map_size) {
2927 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002928 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002929 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002930 lba * sdebug_sector_size,
2931 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002932 sdebug_sector_size *
2933 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002934 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002935 if (dif_storep) {
2936 memset(dif_storep + lba, 0xff,
2937 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002938 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002939 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002940 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002941 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002942 }
2943}
2944
Douglas Gilbertfd321192016-04-25 12:16:33 -04002945static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002947 u8 *cmd = scp->cmnd;
2948 u64 lba;
2949 u32 num;
2950 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002952 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002953 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002955 switch (cmd[0]) {
2956 case WRITE_16:
2957 ei_lba = 0;
2958 lba = get_unaligned_be64(cmd + 2);
2959 num = get_unaligned_be32(cmd + 10);
2960 check_prot = true;
2961 break;
2962 case WRITE_10:
2963 ei_lba = 0;
2964 lba = get_unaligned_be32(cmd + 2);
2965 num = get_unaligned_be16(cmd + 7);
2966 check_prot = true;
2967 break;
2968 case WRITE_6:
2969 ei_lba = 0;
2970 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2971 (u32)(cmd[1] & 0x1f) << 16;
2972 num = (0 == cmd[4]) ? 256 : cmd[4];
2973 check_prot = true;
2974 break;
2975 case WRITE_12:
2976 ei_lba = 0;
2977 lba = get_unaligned_be32(cmd + 2);
2978 num = get_unaligned_be32(cmd + 6);
2979 check_prot = true;
2980 break;
2981 case 0x53: /* XDWRITEREAD(10) */
2982 ei_lba = 0;
2983 lba = get_unaligned_be32(cmd + 2);
2984 num = get_unaligned_be16(cmd + 7);
2985 check_prot = false;
2986 break;
2987 default: /* assume WRITE(32) */
2988 lba = get_unaligned_be64(cmd + 12);
2989 ei_lba = get_unaligned_be32(cmd + 20);
2990 num = get_unaligned_be32(cmd + 28);
2991 check_prot = false;
2992 break;
2993 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002994 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002995 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002996 (cmd[1] & 0xe0)) {
2997 mk_sense_invalid_opcode(scp);
2998 return check_condition_result;
2999 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003000 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3001 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003002 (cmd[1] & 0xe0) == 0)
3003 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3004 "to DIF device\n");
3005 }
3006
3007 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003008 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003009 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3010 return check_condition_result;
3011 }
3012 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003013 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003014 /* needs work to find which cdb byte 'num' comes from */
3015 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3016 return check_condition_result;
3017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003019 write_lock_irqsave(&atomic_rw, iflags);
3020
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003021 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003022 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003023 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003024
3025 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003026 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003027 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003028 return illegal_condition_result;
3029 }
3030 }
3031
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003032 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003033 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003034 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003036 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003037 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003038 else if (unlikely(sdebug_verbose &&
3039 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003040 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003041 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003042 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003043
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003044 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003045 struct sdebug_queued_cmd *sqcp =
3046 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003047
Douglas Gilbertc4837392016-05-06 00:40:26 -04003048 if (sqcp) {
3049 if (sqcp->inj_recovered) {
3050 mk_sense_buffer(scp, RECOVERED_ERROR,
3051 THRESHOLD_EXCEEDED, 0);
3052 return check_condition_result;
3053 } else if (sqcp->inj_dif) {
3054 /* Logical block guard check failed */
3055 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3056 return illegal_condition_result;
3057 } else if (sqcp->inj_dix) {
3058 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3059 return illegal_condition_result;
3060 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003061 }
3062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 return 0;
3064}
3065
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003066/*
3067 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3068 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3069 */
3070static int resp_write_scat(struct scsi_cmnd *scp,
3071 struct sdebug_dev_info *devip)
3072{
3073 u8 *cmd = scp->cmnd;
3074 u8 *lrdp = NULL;
3075 u8 *up;
3076 u8 wrprotect;
3077 u16 lbdof, num_lrd, k;
3078 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3079 u32 lb_size = sdebug_sector_size;
3080 u32 ei_lba;
3081 u64 lba;
3082 unsigned long iflags;
3083 int ret, res;
3084 bool is_16;
3085 static const u32 lrd_size = 32; /* + parameter list header size */
3086
3087 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3088 is_16 = false;
3089 wrprotect = (cmd[10] >> 5) & 0x7;
3090 lbdof = get_unaligned_be16(cmd + 12);
3091 num_lrd = get_unaligned_be16(cmd + 16);
3092 bt_len = get_unaligned_be32(cmd + 28);
3093 } else { /* that leaves WRITE SCATTERED(16) */
3094 is_16 = true;
3095 wrprotect = (cmd[2] >> 5) & 0x7;
3096 lbdof = get_unaligned_be16(cmd + 4);
3097 num_lrd = get_unaligned_be16(cmd + 8);
3098 bt_len = get_unaligned_be32(cmd + 10);
3099 if (unlikely(have_dif_prot)) {
3100 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3101 wrprotect) {
3102 mk_sense_invalid_opcode(scp);
3103 return illegal_condition_result;
3104 }
3105 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3106 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3107 wrprotect == 0)
3108 sdev_printk(KERN_ERR, scp->device,
3109 "Unprotected WR to DIF device\n");
3110 }
3111 }
3112 if ((num_lrd == 0) || (bt_len == 0))
3113 return 0; /* T10 says these do-nothings are not errors */
3114 if (lbdof == 0) {
3115 if (sdebug_verbose)
3116 sdev_printk(KERN_INFO, scp->device,
3117 "%s: %s: LB Data Offset field bad\n",
3118 my_name, __func__);
3119 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3120 return illegal_condition_result;
3121 }
3122 lbdof_blen = lbdof * lb_size;
3123 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3124 if (sdebug_verbose)
3125 sdev_printk(KERN_INFO, scp->device,
3126 "%s: %s: LBA range descriptors don't fit\n",
3127 my_name, __func__);
3128 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3129 return illegal_condition_result;
3130 }
3131 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3132 if (lrdp == NULL)
3133 return SCSI_MLQUEUE_HOST_BUSY;
3134 if (sdebug_verbose)
3135 sdev_printk(KERN_INFO, scp->device,
3136 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3137 my_name, __func__, lbdof_blen);
3138 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3139 if (res == -1) {
3140 ret = DID_ERROR << 16;
3141 goto err_out;
3142 }
3143
3144 write_lock_irqsave(&atomic_rw, iflags);
3145 sg_off = lbdof_blen;
3146 /* Spec says Buffer xfer Length field in number of LBs in dout */
3147 cum_lb = 0;
3148 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3149 lba = get_unaligned_be64(up + 0);
3150 num = get_unaligned_be32(up + 8);
3151 if (sdebug_verbose)
3152 sdev_printk(KERN_INFO, scp->device,
3153 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3154 my_name, __func__, k, lba, num, sg_off);
3155 if (num == 0)
3156 continue;
3157 ret = check_device_access_params(scp, lba, num);
3158 if (ret)
3159 goto err_out_unlock;
3160 num_by = num * lb_size;
3161 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3162
3163 if ((cum_lb + num) > bt_len) {
3164 if (sdebug_verbose)
3165 sdev_printk(KERN_INFO, scp->device,
3166 "%s: %s: sum of blocks > data provided\n",
3167 my_name, __func__);
3168 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3169 0);
3170 ret = illegal_condition_result;
3171 goto err_out_unlock;
3172 }
3173
3174 /* DIX + T10 DIF */
3175 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3176 int prot_ret = prot_verify_write(scp, lba, num,
3177 ei_lba);
3178
3179 if (prot_ret) {
3180 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3181 prot_ret);
3182 ret = illegal_condition_result;
3183 goto err_out_unlock;
3184 }
3185 }
3186
3187 ret = do_device_access(scp, sg_off, lba, num, true);
3188 if (unlikely(scsi_debug_lbp()))
3189 map_region(lba, num);
3190 if (unlikely(-1 == ret)) {
3191 ret = DID_ERROR << 16;
3192 goto err_out_unlock;
3193 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3194 sdev_printk(KERN_INFO, scp->device,
3195 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3196 my_name, num_by, ret);
3197
3198 if (unlikely(sdebug_any_injecting_opt)) {
3199 struct sdebug_queued_cmd *sqcp =
3200 (struct sdebug_queued_cmd *)scp->host_scribble;
3201
3202 if (sqcp) {
3203 if (sqcp->inj_recovered) {
3204 mk_sense_buffer(scp, RECOVERED_ERROR,
3205 THRESHOLD_EXCEEDED, 0);
3206 ret = illegal_condition_result;
3207 goto err_out_unlock;
3208 } else if (sqcp->inj_dif) {
3209 /* Logical block guard check failed */
3210 mk_sense_buffer(scp, ABORTED_COMMAND,
3211 0x10, 1);
3212 ret = illegal_condition_result;
3213 goto err_out_unlock;
3214 } else if (sqcp->inj_dix) {
3215 mk_sense_buffer(scp, ILLEGAL_REQUEST,
3216 0x10, 1);
3217 ret = illegal_condition_result;
3218 goto err_out_unlock;
3219 }
3220 }
3221 }
3222 sg_off += num_by;
3223 cum_lb += num;
3224 }
3225 ret = 0;
3226err_out_unlock:
3227 write_unlock_irqrestore(&atomic_rw, iflags);
3228err_out:
3229 kfree(lrdp);
3230 return ret;
3231}
3232
Douglas Gilbertfd321192016-04-25 12:16:33 -04003233static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3234 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003235{
3236 unsigned long iflags;
3237 unsigned long long i;
3238 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003239 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003240
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003241 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003242 if (ret)
3243 return ret;
3244
3245 write_lock_irqsave(&atomic_rw, iflags);
3246
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003247 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003248 unmap_region(lba, num);
3249 goto out;
3250 }
3251
Douglas Gilbert773642d2016-04-25 12:16:28 -04003252 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003253 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3254 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003255 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003256 ret = 0;
3257 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003258 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3259 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003260
3261 if (-1 == ret) {
3262 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003263 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003264 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003265 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003266 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003267 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003268 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003269
3270 /* Copy first sector to remaining blocks */
3271 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003272 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3273 fake_storep + lba_off,
3274 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003275
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003276 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003277 map_region(lba, num);
3278out:
3279 write_unlock_irqrestore(&atomic_rw, iflags);
3280
3281 return 0;
3282}
3283
Douglas Gilbertfd321192016-04-25 12:16:33 -04003284static int resp_write_same_10(struct scsi_cmnd *scp,
3285 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003286{
3287 u8 *cmd = scp->cmnd;
3288 u32 lba;
3289 u16 num;
3290 u32 ei_lba = 0;
3291 bool unmap = false;
3292
3293 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003294 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003295 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3296 return check_condition_result;
3297 } else
3298 unmap = true;
3299 }
3300 lba = get_unaligned_be32(cmd + 2);
3301 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003302 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003303 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3304 return check_condition_result;
3305 }
3306 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3307}
3308
Douglas Gilbertfd321192016-04-25 12:16:33 -04003309static int resp_write_same_16(struct scsi_cmnd *scp,
3310 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003311{
3312 u8 *cmd = scp->cmnd;
3313 u64 lba;
3314 u32 num;
3315 u32 ei_lba = 0;
3316 bool unmap = false;
3317 bool ndob = false;
3318
3319 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003320 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003321 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3322 return check_condition_result;
3323 } else
3324 unmap = true;
3325 }
3326 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3327 ndob = true;
3328 lba = get_unaligned_be64(cmd + 2);
3329 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003330 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003331 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3332 return check_condition_result;
3333 }
3334 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3335}
3336
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003337/* Note the mode field is in the same position as the (lower) service action
3338 * field. For the Report supported operation codes command, SPC-4 suggests
3339 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003340static int resp_write_buffer(struct scsi_cmnd *scp,
3341 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003342{
3343 u8 *cmd = scp->cmnd;
3344 struct scsi_device *sdp = scp->device;
3345 struct sdebug_dev_info *dp;
3346 u8 mode;
3347
3348 mode = cmd[1] & 0x1f;
3349 switch (mode) {
3350 case 0x4: /* download microcode (MC) and activate (ACT) */
3351 /* set UAs on this device only */
3352 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3353 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3354 break;
3355 case 0x5: /* download MC, save and ACT */
3356 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3357 break;
3358 case 0x6: /* download MC with offsets and ACT */
3359 /* set UAs on most devices (LUs) in this target */
3360 list_for_each_entry(dp,
3361 &devip->sdbg_host->dev_info_list,
3362 dev_list)
3363 if (dp->target == sdp->id) {
3364 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3365 if (devip != dp)
3366 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3367 dp->uas_bm);
3368 }
3369 break;
3370 case 0x7: /* download MC with offsets, save, and ACT */
3371 /* set UA on all devices (LUs) in this target */
3372 list_for_each_entry(dp,
3373 &devip->sdbg_host->dev_info_list,
3374 dev_list)
3375 if (dp->target == sdp->id)
3376 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3377 dp->uas_bm);
3378 break;
3379 default:
3380 /* do nothing for this command for other mode values */
3381 break;
3382 }
3383 return 0;
3384}
3385
Douglas Gilbertfd321192016-04-25 12:16:33 -04003386static int resp_comp_write(struct scsi_cmnd *scp,
3387 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003388{
3389 u8 *cmd = scp->cmnd;
3390 u8 *arr;
3391 u8 *fake_storep_hold;
3392 u64 lba;
3393 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003394 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003395 u8 num;
3396 unsigned long iflags;
3397 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003398 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003399
Douglas Gilbertd467d312014-11-26 12:33:48 -05003400 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003401 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3402 if (0 == num)
3403 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003404 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003405 (cmd[1] & 0xe0)) {
3406 mk_sense_invalid_opcode(scp);
3407 return check_condition_result;
3408 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003409 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3410 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003411 (cmd[1] & 0xe0) == 0)
3412 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3413 "to DIF device\n");
3414
3415 /* inline check_device_access_params() */
3416 if (lba + num > sdebug_capacity) {
3417 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3418 return check_condition_result;
3419 }
3420 /* transfer length excessive (tie in to block limits VPD page) */
3421 if (num > sdebug_store_sectors) {
3422 /* needs work to find which cdb byte 'num' comes from */
3423 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3424 return check_condition_result;
3425 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003426 dnum = 2 * num;
3427 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3428 if (NULL == arr) {
3429 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3430 INSUFF_RES_ASCQ);
3431 return check_condition_result;
3432 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003433
3434 write_lock_irqsave(&atomic_rw, iflags);
3435
3436 /* trick do_device_access() to fetch both compare and write buffers
3437 * from data-in into arr. Safe (atomic) since write_lock held. */
3438 fake_storep_hold = fake_storep;
3439 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003440 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003441 fake_storep = fake_storep_hold;
3442 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003443 retval = DID_ERROR << 16;
3444 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003445 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003446 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3447 "indicated=%u, IO sent=%d bytes\n", my_name,
3448 dnum * lb_size, ret);
3449 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003450 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003451 retval = check_condition_result;
3452 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003453 }
3454 if (scsi_debug_lbp())
3455 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003456cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003457 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003458 kfree(arr);
3459 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003460}
3461
Martin K. Petersen44d92692009-10-15 14:45:27 -04003462struct unmap_block_desc {
3463 __be64 lba;
3464 __be32 blocks;
3465 __be32 __reserved;
3466};
3467
Douglas Gilbertfd321192016-04-25 12:16:33 -04003468static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003469{
3470 unsigned char *buf;
3471 struct unmap_block_desc *desc;
3472 unsigned int i, payload_len, descriptors;
3473 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003474 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003475
Martin K. Petersen44d92692009-10-15 14:45:27 -04003476
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003477 if (!scsi_debug_lbp())
3478 return 0; /* fib and say its done */
3479 payload_len = get_unaligned_be16(scp->cmnd + 7);
3480 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003481
3482 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003483 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003484 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003485 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003486 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003487
Douglas Gilbertb333a812016-04-25 12:16:30 -04003488 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003489 if (!buf) {
3490 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3491 INSUFF_RES_ASCQ);
3492 return check_condition_result;
3493 }
3494
3495 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003496
3497 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3498 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3499
3500 desc = (void *)&buf[8];
3501
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003502 write_lock_irqsave(&atomic_rw, iflags);
3503
Martin K. Petersen44d92692009-10-15 14:45:27 -04003504 for (i = 0 ; i < descriptors ; i++) {
3505 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3506 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3507
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003508 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003509 if (ret)
3510 goto out;
3511
3512 unmap_region(lba, num);
3513 }
3514
3515 ret = 0;
3516
3517out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003518 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003519 kfree(buf);
3520
3521 return ret;
3522}
3523
3524#define SDEBUG_GET_LBA_STATUS_LEN 32
3525
Douglas Gilbertfd321192016-04-25 12:16:33 -04003526static int resp_get_lba_status(struct scsi_cmnd *scp,
3527 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003528{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003529 u8 *cmd = scp->cmnd;
3530 u64 lba;
3531 u32 alloc_len, mapped, num;
3532 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003533 int ret;
3534
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003535 lba = get_unaligned_be64(cmd + 2);
3536 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003537
3538 if (alloc_len < 24)
3539 return 0;
3540
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003541 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003542 if (ret)
3543 return ret;
3544
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003545 if (scsi_debug_lbp())
3546 mapped = map_state(lba, &num);
3547 else {
3548 mapped = 1;
3549 /* following just in case virtual_gb changed */
3550 sdebug_capacity = get_sdebug_capacity();
3551 if (sdebug_capacity - lba <= 0xffffffff)
3552 num = sdebug_capacity - lba;
3553 else
3554 num = 0xffffffff;
3555 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003556
3557 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003558 put_unaligned_be32(20, arr); /* Parameter Data Length */
3559 put_unaligned_be64(lba, arr + 8); /* LBA */
3560 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3561 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003562
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003563 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003564}
3565
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003566#define RL_BUCKET_ELEMS 8
3567
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003568/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3569 * (W-LUN), the normal Linux scanning logic does not associate it with a
3570 * device (e.g. /dev/sg7). The following magic will make that association:
3571 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3572 * where <n> is a host number. If there are multiple targets in a host then
3573 * the above will associate a W-LUN to each target. To only get a W-LUN
3574 * for target 2, then use "echo '- 2 49409' > scan" .
3575 */
3576static int resp_report_luns(struct scsi_cmnd *scp,
3577 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003579 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003580 unsigned int alloc_len;
3581 unsigned char select_report;
3582 u64 lun;
3583 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003584 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003585 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3586 unsigned int wlun_cnt; /* report luns W-LUN count */
3587 unsigned int tlun_cnt; /* total LUN count */
3588 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003589 int k, j, n, res;
3590 unsigned int off_rsp = 0;
3591 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003593 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003594
3595 select_report = cmd[2];
3596 alloc_len = get_unaligned_be32(cmd + 6);
3597
3598 if (alloc_len < 4) {
3599 pr_err("alloc len too small %d\n", alloc_len);
3600 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 return check_condition_result;
3602 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003603
3604 switch (select_report) {
3605 case 0: /* all LUNs apart from W-LUNs */
3606 lun_cnt = sdebug_max_luns;
3607 wlun_cnt = 0;
3608 break;
3609 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003610 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003611 wlun_cnt = 1;
3612 break;
3613 case 2: /* all LUNs */
3614 lun_cnt = sdebug_max_luns;
3615 wlun_cnt = 1;
3616 break;
3617 case 0x10: /* only administrative LUs */
3618 case 0x11: /* see SPC-5 */
3619 case 0x12: /* only subsiduary LUs owned by referenced LU */
3620 default:
3621 pr_debug("select report invalid %d\n", select_report);
3622 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3623 return check_condition_result;
3624 }
3625
3626 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003627 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003628
3629 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003630 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3631 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003632 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3633 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3634
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003635 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003636 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003637 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3638 memset(arr, 0, sizeof(arr));
3639 lun_p = (struct scsi_lun *)&arr[0];
3640 if (k == 0) {
3641 put_unaligned_be32(rlen, &arr[0]);
3642 ++lun_p;
3643 j = 1;
3644 }
3645 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3646 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3647 break;
3648 int_to_scsilun(lun++, lun_p);
3649 }
3650 if (j < RL_BUCKET_ELEMS)
3651 break;
3652 n = j * sz_lun;
3653 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3654 if (res)
3655 return res;
3656 off_rsp += n;
3657 }
3658 if (wlun_cnt) {
3659 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3660 ++j;
3661 }
3662 if (j > 0)
3663 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003664 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665}
3666
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003667static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3668 unsigned int num, struct sdebug_dev_info *devip)
3669{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003670 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003671 unsigned char *kaddr, *buf;
3672 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003673 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003674 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003675
3676 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003677 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003678 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003679 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3680 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003681 return check_condition_result;
3682 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003683
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003684 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003685
3686 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003687 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3688 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003689
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003690 while (sg_miter_next(&miter)) {
3691 kaddr = miter.addr;
3692 for (j = 0; j < miter.length; j++)
3693 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003694
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003695 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003696 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003697 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003698 kfree(buf);
3699
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003700 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003701}
3702
Douglas Gilbertfd321192016-04-25 12:16:33 -04003703static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3704 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003705{
3706 u8 *cmd = scp->cmnd;
3707 u64 lba;
3708 u32 num;
3709 int errsts;
3710
3711 if (!scsi_bidi_cmnd(scp)) {
3712 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3713 INSUFF_RES_ASCQ);
3714 return check_condition_result;
3715 }
3716 errsts = resp_read_dt0(scp, devip);
3717 if (errsts)
3718 return errsts;
3719 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3720 errsts = resp_write_dt0(scp, devip);
3721 if (errsts)
3722 return errsts;
3723 }
3724 lba = get_unaligned_be32(cmd + 2);
3725 num = get_unaligned_be16(cmd + 7);
3726 return resp_xdwriteread(scp, lba, num, devip);
3727}
3728
Douglas Gilbertc4837392016-05-06 00:40:26 -04003729static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3730{
Bart Van Assche458df782018-01-26 08:52:19 -08003731 u32 tag = blk_mq_unique_tag(cmnd->request);
3732 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003733
Bart Van Assche458df782018-01-26 08:52:19 -08003734 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3735 if (WARN_ON_ONCE(hwq >= submit_queues))
3736 hwq = 0;
3737 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003738}
3739
3740/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003741static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003743 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003744 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003746 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003747 struct sdebug_queued_cmd *sqcp;
3748 struct scsi_cmnd *scp;
3749 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
Douglas Gilbert10bde982018-01-10 16:57:31 -05003751 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003752 qc_idx = sd_dp->qc_idx;
3753 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3754 if (sdebug_statistics) {
3755 atomic_inc(&sdebug_completions);
3756 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3757 atomic_inc(&sdebug_miss_cpus);
3758 }
3759 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3760 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 return;
3762 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003763 spin_lock_irqsave(&sqp->qc_lock, iflags);
3764 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003765 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003766 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003767 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3768 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3769 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 return;
3771 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003772 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003773 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003774 atomic_dec(&devip->num_in_q);
3775 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003776 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003777 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003778 retiring = 1;
3779
3780 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003781 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3782 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003783 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003784 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003786
3787 if (unlikely(retiring)) { /* user has reduced max_queue */
3788 int k, retval;
3789
3790 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003791 if (qc_idx >= retval) {
3792 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003793 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003794 return;
3795 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003796 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003797 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003798 atomic_set(&retired_max_queue, 0);
3799 else
3800 atomic_set(&retired_max_queue, k + 1);
3801 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003802 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003803 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804}
3805
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003806/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003807static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003808{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003809 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3810 hrt);
3811 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003812 return HRTIMER_NORESTART;
3813}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
Douglas Gilberta10bc122016-04-25 12:16:32 -04003815/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003816static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003817{
3818 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3819 ew.work);
3820 sdebug_q_cmd_complete(sd_dp);
3821}
3822
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003823static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003824static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003825
Douglas Gilbertfd321192016-04-25 12:16:33 -04003826static struct sdebug_dev_info *sdebug_device_create(
3827 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003828{
3829 struct sdebug_dev_info *devip;
3830
3831 devip = kzalloc(sizeof(*devip), flags);
3832 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003833 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003834 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003835 else if (sdebug_uuid_ctl == 2) {
3836 if (got_shared_uuid)
3837 devip->lu_name = shared_uuid;
3838 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003839 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003840 got_shared_uuid = true;
3841 devip->lu_name = shared_uuid;
3842 }
3843 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003844 devip->sdbg_host = sdbg_host;
3845 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3846 }
3847 return devip;
3848}
3849
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003850static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003852 struct sdebug_host_info *sdbg_host;
3853 struct sdebug_dev_info *open_devip = NULL;
3854 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003856 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3857 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003858 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3862 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003863 (devip->target == sdev->id) &&
3864 (devip->lun == sdev->lun))
3865 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 else {
3867 if ((!devip->used) && (!open_devip))
3868 open_devip = devip;
3869 }
3870 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003871 if (!open_devip) { /* try and make a new one */
3872 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3873 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003874 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 return NULL;
3876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003878
3879 open_devip->channel = sdev->channel;
3880 open_devip->target = sdev->id;
3881 open_devip->lun = sdev->lun;
3882 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003883 atomic_set(&open_devip->num_in_q, 0);
3884 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003885 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003886 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887}
3888
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003889static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003891 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003892 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003893 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003894 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003895 return 0;
3896}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003898static int scsi_debug_slave_configure(struct scsi_device *sdp)
3899{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003900 struct sdebug_dev_info *devip =
3901 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003902
Douglas Gilbert773642d2016-04-25 12:16:28 -04003903 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003904 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003905 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003906 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3907 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3908 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003909 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003910 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003911 return 1; /* no resources, will be marked offline */
3912 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003913 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003914 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003915 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003916 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003917 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003918 return 0;
3919}
3920
3921static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3922{
3923 struct sdebug_dev_info *devip =
3924 (struct sdebug_dev_info *)sdp->hostdata;
3925
Douglas Gilbert773642d2016-04-25 12:16:28 -04003926 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003927 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003928 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3929 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003930 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003931 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003932 sdp->hostdata = NULL;
3933 }
3934}
3935
Douglas Gilbert10bde982018-01-10 16:57:31 -05003936static void stop_qc_helper(struct sdebug_defer *sd_dp,
3937 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003938{
3939 if (!sd_dp)
3940 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003941 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003942 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003943 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003944 cancel_work_sync(&sd_dp->ew.work);
3945}
3946
Douglas Gilberta10bc122016-04-25 12:16:32 -04003947/* If @cmnd found deletes its timer or work queue and returns true; else
3948 returns false */
3949static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003950{
3951 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003952 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003953 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003954 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003955 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003956 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003957 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003958
Douglas Gilbertc4837392016-05-06 00:40:26 -04003959 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3960 spin_lock_irqsave(&sqp->qc_lock, iflags);
3961 qmax = sdebug_max_queue;
3962 r_qmax = atomic_read(&retired_max_queue);
3963 if (r_qmax > qmax)
3964 qmax = r_qmax;
3965 for (k = 0; k < qmax; ++k) {
3966 if (test_bit(k, sqp->in_use_bm)) {
3967 sqcp = &sqp->qc_arr[k];
3968 if (cmnd != sqcp->a_cmnd)
3969 continue;
3970 /* found */
3971 devip = (struct sdebug_dev_info *)
3972 cmnd->device->hostdata;
3973 if (devip)
3974 atomic_dec(&devip->num_in_q);
3975 sqcp->a_cmnd = NULL;
3976 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003977 if (sd_dp) {
3978 l_defer_t = sd_dp->defer_t;
3979 sd_dp->defer_t = SDEB_DEFER_NONE;
3980 } else
3981 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003982 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003983 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003984 clear_bit(k, sqp->in_use_bm);
3985 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003986 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003987 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003988 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003989 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003990 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003991}
3992
Douglas Gilberta10bc122016-04-25 12:16:32 -04003993/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003994static void stop_all_queued(void)
3995{
3996 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003997 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003998 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003999 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004000 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004001 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004002 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004003
Douglas Gilbertc4837392016-05-06 00:40:26 -04004004 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4005 spin_lock_irqsave(&sqp->qc_lock, iflags);
4006 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4007 if (test_bit(k, sqp->in_use_bm)) {
4008 sqcp = &sqp->qc_arr[k];
4009 if (sqcp->a_cmnd == NULL)
4010 continue;
4011 devip = (struct sdebug_dev_info *)
4012 sqcp->a_cmnd->device->hostdata;
4013 if (devip)
4014 atomic_dec(&devip->num_in_q);
4015 sqcp->a_cmnd = NULL;
4016 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004017 if (sd_dp) {
4018 l_defer_t = sd_dp->defer_t;
4019 sd_dp->defer_t = SDEB_DEFER_NONE;
4020 } else
4021 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004022 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004023 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004024 clear_bit(k, sqp->in_use_bm);
4025 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004026 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004027 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004028 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030}
4031
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004032/* Free queued command memory on heap */
4033static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004035 int j, k;
4036 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004037 struct sdebug_queued_cmd *sqcp;
4038
Douglas Gilbertc4837392016-05-06 00:40:26 -04004039 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4040 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4041 sqcp = &sqp->qc_arr[k];
4042 kfree(sqcp->sd_dp);
4043 sqcp->sd_dp = NULL;
4044 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046}
4047
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004048static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004050 bool ok;
4051
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004052 ++num_aborts;
4053 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004054 ok = stop_queued_cmnd(SCpnt);
4055 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4056 sdev_printk(KERN_INFO, SCpnt->device,
4057 "%s: command%s found\n", __func__,
4058 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004060 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061}
4062
4063static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
4064{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004066 if (SCpnt && SCpnt->device) {
4067 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004068 struct sdebug_dev_info *devip =
4069 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004070
Douglas Gilbert773642d2016-04-25 12:16:28 -04004071 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004072 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004074 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 }
4076 return SUCCESS;
4077}
4078
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004079static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4080{
4081 struct sdebug_host_info *sdbg_host;
4082 struct sdebug_dev_info *devip;
4083 struct scsi_device *sdp;
4084 struct Scsi_Host *hp;
4085 int k = 0;
4086
4087 ++num_target_resets;
4088 if (!SCpnt)
4089 goto lie;
4090 sdp = SCpnt->device;
4091 if (!sdp)
4092 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004093 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004094 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4095 hp = sdp->host;
4096 if (!hp)
4097 goto lie;
4098 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4099 if (sdbg_host) {
4100 list_for_each_entry(devip,
4101 &sdbg_host->dev_info_list,
4102 dev_list)
4103 if (devip->target == sdp->id) {
4104 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4105 ++k;
4106 }
4107 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004108 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004109 sdev_printk(KERN_INFO, sdp,
4110 "%s: %d device(s) found in target\n", __func__, k);
4111lie:
4112 return SUCCESS;
4113}
4114
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
4116{
4117 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004118 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004119 struct scsi_device *sdp;
4120 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004121 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004124 if (!(SCpnt && SCpnt->device))
4125 goto lie;
4126 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004127 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004128 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4129 hp = sdp->host;
4130 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004131 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004133 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05004134 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004135 dev_list) {
4136 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4137 ++k;
4138 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 }
4140 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004141 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004142 sdev_printk(KERN_INFO, sdp,
4143 "%s: %d device(s) found in host\n", __func__, k);
4144lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 return SUCCESS;
4146}
4147
4148static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
4149{
4150 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004151 struct sdebug_dev_info *devip;
4152 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004155 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004156 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05004157 spin_lock(&sdebug_host_list_lock);
4158 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004159 list_for_each_entry(devip, &sdbg_host->dev_info_list,
4160 dev_list) {
4161 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4162 ++k;
4163 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05004164 }
4165 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004167 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004168 sdev_printk(KERN_INFO, SCpnt->device,
4169 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 return SUCCESS;
4171}
4172
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09004173static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004174 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175{
4176 struct partition * pp;
4177 int starts[SDEBUG_MAX_PARTS + 2];
4178 int sectors_per_part, num_sectors, k;
4179 int heads_by_sects, start_sec, end_sec;
4180
4181 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004182 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004184 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4185 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03004186 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004188 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004190 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004192 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004193 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4195 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004196 starts[sdebug_num_parts] = num_sectors;
4197 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198
4199 ramp[510] = 0x55; /* magic partition markings */
4200 ramp[511] = 0xAA;
4201 pp = (struct partition *)(ramp + 0x1be);
4202 for (k = 0; starts[k + 1]; ++k, ++pp) {
4203 start_sec = starts[k];
4204 end_sec = starts[k + 1] - 1;
4205 pp->boot_ind = 0;
4206
4207 pp->cyl = start_sec / heads_by_sects;
4208 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4209 / sdebug_sectors_per;
4210 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4211
4212 pp->end_cyl = end_sec / heads_by_sects;
4213 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4214 / sdebug_sectors_per;
4215 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4216
Akinobu Mita150c3542013-08-26 22:08:40 +09004217 pp->start_sect = cpu_to_le32(start_sec);
4218 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 pp->sys_ind = 0x83; /* plain Linux partition */
4220 }
4221}
4222
Douglas Gilbertc4837392016-05-06 00:40:26 -04004223static void block_unblock_all_queues(bool block)
4224{
4225 int j;
4226 struct sdebug_queue *sqp;
4227
4228 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4229 atomic_set(&sqp->blocked, (int)block);
4230}
4231
4232/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4233 * commands will be processed normally before triggers occur.
4234 */
4235static void tweak_cmnd_count(void)
4236{
4237 int count, modulo;
4238
4239 modulo = abs(sdebug_every_nth);
4240 if (modulo < 2)
4241 return;
4242 block_unblock_all_queues(true);
4243 count = atomic_read(&sdebug_cmnd_count);
4244 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4245 block_unblock_all_queues(false);
4246}
4247
4248static void clear_queue_stats(void)
4249{
4250 atomic_set(&sdebug_cmnd_count, 0);
4251 atomic_set(&sdebug_completions, 0);
4252 atomic_set(&sdebug_miss_cpus, 0);
4253 atomic_set(&sdebug_a_tsf, 0);
4254}
4255
4256static void setup_inject(struct sdebug_queue *sqp,
4257 struct sdebug_queued_cmd *sqcp)
4258{
4259 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4260 return;
4261 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4262 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4263 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4264 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4265 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004266 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004267}
4268
4269/* Complete the processing of the thread that queued a SCSI command to this
4270 * driver. It either completes the command by calling cmnd_done() or
4271 * schedules a hr timer or work queue then returns 0. Returns
4272 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4273 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004274static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Douglas Gilbert10bde982018-01-10 16:57:31 -05004275 int scsi_result, int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004277 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004278 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004279 struct sdebug_queue *sqp;
4280 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004281 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004282 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004284 if (unlikely(devip == NULL)) {
4285 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004286 scsi_result = DID_NO_CONNECT << 16;
4287 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004289 sdp = cmnd->device;
4290
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004291 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004292 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4293 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004294 if (delta_jiff == 0)
4295 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004297 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004298 sqp = get_queue(cmnd);
4299 spin_lock_irqsave(&sqp->qc_lock, iflags);
4300 if (unlikely(atomic_read(&sqp->blocked))) {
4301 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4302 return SCSI_MLQUEUE_HOST_BUSY;
4303 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004304 num_in_q = atomic_read(&devip->num_in_q);
4305 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004306 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004307 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004308 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004309 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004310 goto respond_in_thread;
4311 } else
4312 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004313 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004314 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4315 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004316 if ((num_in_q == (qdepth - 1)) &&
4317 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004318 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004319 atomic_set(&sdebug_a_tsf, 0);
4320 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004321 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004323 }
4324
Douglas Gilbertc4837392016-05-06 00:40:26 -04004325 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004326 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004327 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004328 if (scsi_result)
4329 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004330 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004331 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004332 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004333 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004334 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004335 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004336 (scsi_result ? "status: TASK SET FULL" :
4337 "report: host busy"));
4338 if (scsi_result)
4339 goto respond_in_thread;
4340 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004341 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004343 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004344 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004345 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004346 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004347 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004348 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004349 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004350 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4351 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4352 setup_inject(sqp, sqcp);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004353 if (sd_dp == NULL) {
4354 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4355 if (sd_dp == NULL)
4356 return SCSI_MLQUEUE_HOST_BUSY;
4357 }
4358 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004359 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004360
Douglas Gilbertb333a812016-04-25 12:16:30 -04004361 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004362 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004363 } else
Douglas Gilbert10bde982018-01-10 16:57:31 -05004364 kt = ndelay;
4365 if (!sd_dp->init_hrt) {
4366 sd_dp->init_hrt = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004367 sqcp->sd_dp = sd_dp;
4368 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004369 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004370 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004371 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4372 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004373 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004374 if (sdebug_statistics)
4375 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004376 sd_dp->defer_t = SDEB_DEFER_HRT;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004377 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4378 } else { /* jdelay < 0, use work queue */
Douglas Gilbert10bde982018-01-10 16:57:31 -05004379 if (!sd_dp->init_wq) {
4380 sd_dp->init_wq = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004381 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004382 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4383 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004384 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004385 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004386 if (sdebug_statistics)
4387 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004388 sd_dp->defer_t = SDEB_DEFER_WQ;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004389 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004390 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004391 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4392 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004393 sdev_printk(KERN_INFO, sdp,
4394 "%s: num_in_q=%d +1, %s%s\n", __func__,
4395 num_in_q, (inject ? "<inject> " : ""),
4396 "status: TASK SET FULL");
4397 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004398
4399respond_in_thread: /* call back to mid-layer using invocation thread */
4400 cmnd->result = scsi_result;
4401 cmnd->scsi_done(cmnd);
4402 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004404
Douglas Gilbert23183912006-09-16 20:30:47 -04004405/* Note: The following macros create attribute files in the
4406 /sys/module/scsi_debug/parameters directory. Unfortunately this
4407 driver is unaware of a change and cannot trigger auxiliary actions
4408 as it can when the corresponding attribute in the
4409 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4410 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004411module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4412module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004413module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004414module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004415module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004416module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4417module_param_named(dif, sdebug_dif, int, S_IRUGO);
4418module_param_named(dix, sdebug_dix, int, S_IRUGO);
4419module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4420module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4421module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4422module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4423module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004424module_param_string(inq_vendor, sdebug_inq_vendor_id,
4425 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4426module_param_string(inq_product, sdebug_inq_product_id,
4427 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4428module_param_string(inq_rev, sdebug_inq_product_rev,
4429 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004430module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4431module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4432module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4433module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4434module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4435module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4436module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Laurence Obermand9da8912018-02-03 13:38:35 -05004437module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4438module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004439module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4440module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4441module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4442module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4443module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4444module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4445module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4446module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004447module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004448module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4449module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4450module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4451module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004452module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004453module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004454module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004455module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4456module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4457module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4458module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4459module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004460module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004461module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004462 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004463module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004464 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465
4466MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4467MODULE_DESCRIPTION("SCSI debug adapter driver");
4468MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004469MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470
4471MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004472MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004473MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004474MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004475MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004476MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004477MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4478MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004479MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004480MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004481MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004482MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004483MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004484MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4485MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004486MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4487 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004488MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4489MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4490MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004491MODULE_PARM_DESC(lbprz,
4492 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004493MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004494MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004495MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05004496MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4497MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004498MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004499MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004500MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004502MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004503MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004504MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004505MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004506MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004508MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004509MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004510MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004511MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004512MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004513MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004514MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4515MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004516MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4517MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004518MODULE_PARM_DESC(uuid_ctl,
4519 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004520MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004521MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4522MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004524#define SDEBUG_INFO_LEN 256
4525static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526
4527static const char * scsi_debug_info(struct Scsi_Host * shp)
4528{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004529 int k;
4530
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004531 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4532 my_name, SDEBUG_VERSION, sdebug_version_date);
4533 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004534 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004535 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4536 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4537 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4538 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 return sdebug_info;
4540}
4541
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004542/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004543static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4544 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545{
Al Viroc8ed5552013-03-31 01:46:06 -04004546 char arr[16];
4547 int opts;
4548 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549
Al Viroc8ed5552013-03-31 01:46:06 -04004550 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4551 return -EACCES;
4552 memcpy(arr, buffer, minLen);
4553 arr[minLen] = '\0';
4554 if (1 != sscanf(arr, "%d", &opts))
4555 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004556 sdebug_opts = opts;
4557 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4558 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4559 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004560 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004561 return length;
4562}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004564/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4565 * same for each scsi_debug host (if more than one). Some of the counters
4566 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004567static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4568{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004569 int f, j, l;
4570 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004571
Douglas Gilbertc4837392016-05-06 00:40:26 -04004572 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4573 SDEBUG_VERSION, sdebug_version_date);
4574 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4575 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4576 sdebug_opts, sdebug_every_nth);
4577 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4578 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4579 sdebug_sector_size, "bytes");
4580 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4581 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4582 num_aborts);
4583 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4584 num_dev_resets, num_target_resets, num_bus_resets,
4585 num_host_resets);
4586 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4587 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08004588 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4589 sdebug_statistics);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004590 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4591 atomic_read(&sdebug_cmnd_count),
4592 atomic_read(&sdebug_completions),
4593 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4594 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004595
Douglas Gilbertc4837392016-05-06 00:40:26 -04004596 seq_printf(m, "submit_queues=%d\n", submit_queues);
4597 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4598 seq_printf(m, " queue %d:\n", j);
4599 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4600 if (f != sdebug_max_queue) {
4601 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4602 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4603 "first,last bits", f, l);
4604 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004605 }
Al Viroc8ed5552013-03-31 01:46:06 -04004606 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607}
4608
Akinobu Mita82069372013-10-14 22:48:04 +09004609static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004611 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004613/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4614 * of delay is jiffies.
4615 */
Akinobu Mita82069372013-10-14 22:48:04 +09004616static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4617 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004619 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004621 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004622 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004623 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004624 int j, k;
4625 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004626
Douglas Gilbertc4837392016-05-06 00:40:26 -04004627 block_unblock_all_queues(true);
4628 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4629 ++j, ++sqp) {
4630 k = find_first_bit(sqp->in_use_bm,
4631 sdebug_max_queue);
4632 if (k != sdebug_max_queue) {
4633 res = -EBUSY; /* queued commands */
4634 break;
4635 }
4636 }
4637 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04004638 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004639 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004640 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004641 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004643 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 }
4645 return -EINVAL;
4646}
Akinobu Mita82069372013-10-14 22:48:04 +09004647static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004649static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4650{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004651 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004652}
4653/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004654/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004655static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004656 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004657{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004658 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004659
4660 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004661 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004662 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004663 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004664 int j, k;
4665 struct sdebug_queue *sqp;
4666
4667 block_unblock_all_queues(true);
4668 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4669 ++j, ++sqp) {
4670 k = find_first_bit(sqp->in_use_bm,
4671 sdebug_max_queue);
4672 if (k != sdebug_max_queue) {
4673 res = -EBUSY; /* queued commands */
4674 break;
4675 }
4676 }
4677 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004678 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004679 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4680 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004681 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004682 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004683 }
4684 return res;
4685 }
4686 return -EINVAL;
4687}
4688static DRIVER_ATTR_RW(ndelay);
4689
Akinobu Mita82069372013-10-14 22:48:04 +09004690static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004692 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693}
4694
Akinobu Mita82069372013-10-14 22:48:04 +09004695static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4696 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004698 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 char work[20];
4700
Douglas Gilbert9a051012017-12-23 12:48:10 -05004701 if (sscanf(buf, "%10s", work) == 1) {
4702 if (strncasecmp(work, "0x", 2) == 0) {
4703 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 goto opts_done;
4705 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004706 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 goto opts_done;
4708 }
4709 }
4710 return -EINVAL;
4711opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004712 sdebug_opts = opts;
4713 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4714 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004715 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 return count;
4717}
Akinobu Mita82069372013-10-14 22:48:04 +09004718static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719
Akinobu Mita82069372013-10-14 22:48:04 +09004720static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004722 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723}
Akinobu Mita82069372013-10-14 22:48:04 +09004724static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4725 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004727 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728
4729 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004730 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 return count;
4732 }
4733 return -EINVAL;
4734}
Akinobu Mita82069372013-10-14 22:48:04 +09004735static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736
Akinobu Mita82069372013-10-14 22:48:04 +09004737static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004739 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740}
Akinobu Mita82069372013-10-14 22:48:04 +09004741static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4742 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004744 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745
4746 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004747 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 return count;
4749 }
4750 return -EINVAL;
4751}
Akinobu Mita82069372013-10-14 22:48:04 +09004752static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753
Akinobu Mita82069372013-10-14 22:48:04 +09004754static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004755{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004756 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004757}
Akinobu Mita82069372013-10-14 22:48:04 +09004758static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4759 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004760{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004761 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004762
4763 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004764 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004765 sdebug_fake_rw = (sdebug_fake_rw > 0);
4766 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004767 if ((0 == n) && (NULL == fake_storep)) {
4768 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004769 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004770 1048576;
4771
4772 fake_storep = vmalloc(sz);
4773 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004774 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004775 return -ENOMEM;
4776 }
4777 memset(fake_storep, 0, sz);
4778 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004779 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004780 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004781 return count;
4782 }
4783 return -EINVAL;
4784}
Akinobu Mita82069372013-10-14 22:48:04 +09004785static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004786
Akinobu Mita82069372013-10-14 22:48:04 +09004787static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004788{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004789 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004790}
Akinobu Mita82069372013-10-14 22:48:04 +09004791static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4792 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004793{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004794 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004795
4796 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004797 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004798 return count;
4799 }
4800 return -EINVAL;
4801}
Akinobu Mita82069372013-10-14 22:48:04 +09004802static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004803
Akinobu Mita82069372013-10-14 22:48:04 +09004804static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004806 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807}
Akinobu Mita82069372013-10-14 22:48:04 +09004808static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4809 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004811 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812
4813 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004814 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 sdebug_max_tgts_luns();
4816 return count;
4817 }
4818 return -EINVAL;
4819}
Akinobu Mita82069372013-10-14 22:48:04 +09004820static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821
Akinobu Mita82069372013-10-14 22:48:04 +09004822static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004824 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825}
Akinobu Mita82069372013-10-14 22:48:04 +09004826static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827
Akinobu Mita82069372013-10-14 22:48:04 +09004828static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004830 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831}
Akinobu Mita82069372013-10-14 22:48:04 +09004832static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833
Akinobu Mita82069372013-10-14 22:48:04 +09004834static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004836 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837}
Akinobu Mita82069372013-10-14 22:48:04 +09004838static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4839 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004841 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842
4843 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004844 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004845 if (nth && !sdebug_statistics) {
4846 pr_info("every_nth needs statistics=1, set it\n");
4847 sdebug_statistics = true;
4848 }
4849 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 return count;
4851 }
4852 return -EINVAL;
4853}
Akinobu Mita82069372013-10-14 22:48:04 +09004854static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855
Akinobu Mita82069372013-10-14 22:48:04 +09004856static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004858 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859}
Akinobu Mita82069372013-10-14 22:48:04 +09004860static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4861 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004863 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004864 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865
4866 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004867 if (n > 256) {
4868 pr_warn("max_luns can be no more than 256\n");
4869 return -EINVAL;
4870 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004871 changed = (sdebug_max_luns != n);
4872 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004874 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004875 struct sdebug_host_info *sdhp;
4876 struct sdebug_dev_info *dp;
4877
4878 spin_lock(&sdebug_host_list_lock);
4879 list_for_each_entry(sdhp, &sdebug_host_list,
4880 host_list) {
4881 list_for_each_entry(dp, &sdhp->dev_info_list,
4882 dev_list) {
4883 set_bit(SDEBUG_UA_LUNS_CHANGED,
4884 dp->uas_bm);
4885 }
4886 }
4887 spin_unlock(&sdebug_host_list_lock);
4888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 return count;
4890 }
4891 return -EINVAL;
4892}
Akinobu Mita82069372013-10-14 22:48:04 +09004893static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894
Akinobu Mita82069372013-10-14 22:48:04 +09004895static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004896{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004897 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004898}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004899/* N.B. max_queue can be changed while there are queued commands. In flight
4900 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004901static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4902 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004903{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004904 int j, n, k, a;
4905 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004906
4907 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004908 (n <= SDEBUG_CANQUEUE)) {
4909 block_unblock_all_queues(true);
4910 k = 0;
4911 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4912 ++j, ++sqp) {
4913 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4914 if (a > k)
4915 k = a;
4916 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004917 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004918 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004919 atomic_set(&retired_max_queue, 0);
4920 else if (k >= n)
4921 atomic_set(&retired_max_queue, k + 1);
4922 else
4923 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004924 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004925 return count;
4926 }
4927 return -EINVAL;
4928}
Akinobu Mita82069372013-10-14 22:48:04 +09004929static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004930
Akinobu Mita82069372013-10-14 22:48:04 +09004931static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004932{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004933 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004934}
Akinobu Mita82069372013-10-14 22:48:04 +09004935static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004936
Akinobu Mita82069372013-10-14 22:48:04 +09004937static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004939 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940}
Akinobu Mita82069372013-10-14 22:48:04 +09004941static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942
Akinobu Mita82069372013-10-14 22:48:04 +09004943static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004944{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004945 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004946}
Akinobu Mita82069372013-10-14 22:48:04 +09004947static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4948 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004949{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004950 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004951 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004952
4953 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004954 changed = (sdebug_virtual_gb != n);
4955 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004956 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004957 if (changed) {
4958 struct sdebug_host_info *sdhp;
4959 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004960
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004961 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004962 list_for_each_entry(sdhp, &sdebug_host_list,
4963 host_list) {
4964 list_for_each_entry(dp, &sdhp->dev_info_list,
4965 dev_list) {
4966 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4967 dp->uas_bm);
4968 }
4969 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004970 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004971 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004972 return count;
4973 }
4974 return -EINVAL;
4975}
Akinobu Mita82069372013-10-14 22:48:04 +09004976static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004977
Akinobu Mita82069372013-10-14 22:48:04 +09004978static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004980 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981}
4982
Douglas Gilbertfd321192016-04-25 12:16:33 -04004983static int sdebug_add_adapter(void);
4984static void sdebug_remove_adapter(void);
4985
Akinobu Mita82069372013-10-14 22:48:04 +09004986static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4987 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004989 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004991 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 if (delta_hosts > 0) {
4994 do {
4995 sdebug_add_adapter();
4996 } while (--delta_hosts);
4997 } else if (delta_hosts < 0) {
4998 do {
4999 sdebug_remove_adapter();
5000 } while (++delta_hosts);
5001 }
5002 return count;
5003}
Akinobu Mita82069372013-10-14 22:48:04 +09005004static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005
Akinobu Mita82069372013-10-14 22:48:04 +09005006static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04005007{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005008 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005009}
Akinobu Mita82069372013-10-14 22:48:04 +09005010static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
5011 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04005012{
5013 int n;
5014
5015 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005016 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04005017 return count;
5018 }
5019 return -EINVAL;
5020}
Akinobu Mita82069372013-10-14 22:48:04 +09005021static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005022
Douglas Gilbertc4837392016-05-06 00:40:26 -04005023static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5024{
5025 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5026}
5027static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5028 size_t count)
5029{
5030 int n;
5031
5032 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5033 if (n > 0)
5034 sdebug_statistics = true;
5035 else {
5036 clear_queue_stats();
5037 sdebug_statistics = false;
5038 }
5039 return count;
5040 }
5041 return -EINVAL;
5042}
5043static DRIVER_ATTR_RW(statistics);
5044
Akinobu Mita82069372013-10-14 22:48:04 +09005045static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04005046{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005047 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005048}
Akinobu Mita82069372013-10-14 22:48:04 +09005049static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005050
Douglas Gilbertc4837392016-05-06 00:40:26 -04005051static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5052{
5053 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5054}
5055static DRIVER_ATTR_RO(submit_queues);
5056
Akinobu Mita82069372013-10-14 22:48:04 +09005057static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005058{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005059 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005060}
Akinobu Mita82069372013-10-14 22:48:04 +09005061static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005062
Akinobu Mita82069372013-10-14 22:48:04 +09005063static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005064{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005065 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005066}
Akinobu Mita82069372013-10-14 22:48:04 +09005067static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005068
Akinobu Mita82069372013-10-14 22:48:04 +09005069static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005070{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005071 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005072}
Akinobu Mita82069372013-10-14 22:48:04 +09005073static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005074
Akinobu Mita82069372013-10-14 22:48:04 +09005075static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005076{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005077 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005078}
Akinobu Mita82069372013-10-14 22:48:04 +09005079static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005080
Akinobu Mita82069372013-10-14 22:48:04 +09005081static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005082{
5083 ssize_t count;
5084
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005085 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04005086 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
5087 sdebug_store_sectors);
5088
Tejun Heoc7badc92015-02-13 14:37:51 -08005089 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5090 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005091 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08005092 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04005093
5094 return count;
5095}
Akinobu Mita82069372013-10-14 22:48:04 +09005096static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005097
Akinobu Mita82069372013-10-14 22:48:04 +09005098static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02005099{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005100 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02005101}
Akinobu Mita82069372013-10-14 22:48:04 +09005102static ssize_t removable_store(struct device_driver *ddp, const char *buf,
5103 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02005104{
5105 int n;
5106
5107 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005108 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02005109 return count;
5110 }
5111 return -EINVAL;
5112}
Akinobu Mita82069372013-10-14 22:48:04 +09005113static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02005114
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005115static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5116{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005117 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005118}
Douglas Gilbert185dd232016-04-25 12:16:29 -04005119/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005120static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5121 size_t count)
5122{
Douglas Gilbert185dd232016-04-25 12:16:29 -04005123 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005124
5125 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04005126 sdebug_host_lock = (n > 0);
5127 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005128 }
5129 return -EINVAL;
5130}
5131static DRIVER_ATTR_RW(host_lock);
5132
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005133static ssize_t strict_show(struct device_driver *ddp, char *buf)
5134{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005135 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005136}
5137static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5138 size_t count)
5139{
5140 int n;
5141
5142 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005143 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005144 return count;
5145 }
5146 return -EINVAL;
5147}
5148static DRIVER_ATTR_RW(strict);
5149
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005150static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
5151{
5152 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
5153}
5154static DRIVER_ATTR_RO(uuid_ctl);
5155
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005156static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
5157{
5158 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
5159}
5160static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
5161 size_t count)
5162{
5163 int ret, n;
5164
5165 ret = kstrtoint(buf, 0, &n);
5166 if (ret)
5167 return ret;
5168 sdebug_cdb_len = n;
5169 all_config_cdb_len();
5170 return count;
5171}
5172static DRIVER_ATTR_RW(cdb_len);
5173
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005174
Akinobu Mita82069372013-10-14 22:48:04 +09005175/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04005176 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
5177 files (over those found in the /sys/module/scsi_debug/parameters
5178 directory) is that auxiliary actions can be triggered when an attribute
5179 is changed. For example see: sdebug_add_host_store() above.
5180 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005181
Akinobu Mita82069372013-10-14 22:48:04 +09005182static struct attribute *sdebug_drv_attrs[] = {
5183 &driver_attr_delay.attr,
5184 &driver_attr_opts.attr,
5185 &driver_attr_ptype.attr,
5186 &driver_attr_dsense.attr,
5187 &driver_attr_fake_rw.attr,
5188 &driver_attr_no_lun_0.attr,
5189 &driver_attr_num_tgts.attr,
5190 &driver_attr_dev_size_mb.attr,
5191 &driver_attr_num_parts.attr,
5192 &driver_attr_every_nth.attr,
5193 &driver_attr_max_luns.attr,
5194 &driver_attr_max_queue.attr,
5195 &driver_attr_no_uld.attr,
5196 &driver_attr_scsi_level.attr,
5197 &driver_attr_virtual_gb.attr,
5198 &driver_attr_add_host.attr,
5199 &driver_attr_vpd_use_hostno.attr,
5200 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005201 &driver_attr_statistics.attr,
5202 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005203 &driver_attr_dix.attr,
5204 &driver_attr_dif.attr,
5205 &driver_attr_guard.attr,
5206 &driver_attr_ato.attr,
5207 &driver_attr_map.attr,
5208 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005209 &driver_attr_host_lock.attr,
5210 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005211 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005212 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005213 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005214 NULL,
5215};
5216ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005218static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005219
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220static int __init scsi_debug_init(void)
5221{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005222 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223 int host_to_add;
5224 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005225 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005227 atomic_set(&retired_max_queue, 0);
5228
Douglas Gilbert773642d2016-04-25 12:16:28 -04005229 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005230 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005231 sdebug_ndelay = 0;
5232 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005233 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005234
Douglas Gilbert773642d2016-04-25 12:16:28 -04005235 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04005236 case 512:
5237 case 1024:
5238 case 2048:
5239 case 4096:
5240 break;
5241 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005242 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005243 return -EINVAL;
5244 }
5245
Douglas Gilbert773642d2016-04-25 12:16:28 -04005246 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005247 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005248 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005249 case T10_PI_TYPE1_PROTECTION:
5250 case T10_PI_TYPE2_PROTECTION:
5251 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005252 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005253 break;
5254
5255 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005256 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005257 return -EINVAL;
5258 }
5259
Douglas Gilbert773642d2016-04-25 12:16:28 -04005260 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005261 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005262 return -EINVAL;
5263 }
5264
Douglas Gilbert773642d2016-04-25 12:16:28 -04005265 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005266 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005267 return -EINVAL;
5268 }
5269
Douglas Gilbert773642d2016-04-25 12:16:28 -04005270 if (sdebug_physblk_exp > 15) {
5271 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005272 return -EINVAL;
5273 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005274 if (sdebug_max_luns > 256) {
5275 pr_warn("max_luns can be no more than 256, use default\n");
5276 sdebug_max_luns = DEF_MAX_LUNS;
5277 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005278
Douglas Gilbert773642d2016-04-25 12:16:28 -04005279 if (sdebug_lowest_aligned > 0x3fff) {
5280 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005281 return -EINVAL;
5282 }
5283
Douglas Gilbertc4837392016-05-06 00:40:26 -04005284 if (submit_queues < 1) {
5285 pr_err("submit_queues must be 1 or more\n");
5286 return -EINVAL;
5287 }
5288 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5289 GFP_KERNEL);
5290 if (sdebug_q_arr == NULL)
5291 return -ENOMEM;
5292 for (k = 0; k < submit_queues; ++k)
5293 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5294
Douglas Gilbert773642d2016-04-25 12:16:28 -04005295 if (sdebug_dev_size_mb < 1)
5296 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5297 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5298 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005299 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300
5301 /* play around with geometry, don't waste too much on track 0 */
5302 sdebug_heads = 8;
5303 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005304 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005306 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005307 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5309 (sdebug_sectors_per * sdebug_heads);
5310 if (sdebug_cylinders_per >= 1024) {
5311 /* other LLDs do this; implies >= 1GB ram disk ... */
5312 sdebug_heads = 255;
5313 sdebug_sectors_per = 63;
5314 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5315 (sdebug_sectors_per * sdebug_heads);
5316 }
5317
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005318 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005319 fake_storep = vmalloc(sz);
5320 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005321 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005322 ret = -ENOMEM;
5323 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005324 }
5325 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005326 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005327 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329
Douglas Gilbert773642d2016-04-25 12:16:28 -04005330 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005331 int dif_size;
5332
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005333 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005334 dif_storep = vmalloc(dif_size);
5335
Tomas Winklerc12879702015-07-28 16:54:20 +03005336 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005337
5338 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005339 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005340 ret = -ENOMEM;
5341 goto free_vm;
5342 }
5343
5344 memset(dif_storep, 0xff, dif_size);
5345 }
5346
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005347 /* Logical Block Provisioning */
5348 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005349 sdebug_unmap_max_blocks =
5350 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005351
Douglas Gilbert773642d2016-04-25 12:16:28 -04005352 sdebug_unmap_max_desc =
5353 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005354
Douglas Gilbert773642d2016-04-25 12:16:28 -04005355 sdebug_unmap_granularity =
5356 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005357
Douglas Gilbert773642d2016-04-25 12:16:28 -04005358 if (sdebug_unmap_alignment &&
5359 sdebug_unmap_granularity <=
5360 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005361 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005362 ret = -EINVAL;
5363 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005364 }
5365
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005366 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5367 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005368
Tomas Winklerc12879702015-07-28 16:54:20 +03005369 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005370
5371 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005372 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005373 ret = -ENOMEM;
5374 goto free_vm;
5375 }
5376
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005377 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005378
5379 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005380 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005381 map_region(0, 2);
5382 }
5383
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005384 pseudo_primary = root_device_register("pseudo_0");
5385 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005386 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005387 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005388 goto free_vm;
5389 }
5390 ret = bus_register(&pseudo_lld_bus);
5391 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005392 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005393 goto dev_unreg;
5394 }
5395 ret = driver_register(&sdebug_driverfs_driver);
5396 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005397 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005398 goto bus_unreg;
5399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400
Douglas Gilbert773642d2016-04-25 12:16:28 -04005401 host_to_add = sdebug_add_host;
5402 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403
Douglas Gilbert9a051012017-12-23 12:48:10 -05005404 for (k = 0; k < host_to_add; k++) {
5405 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005406 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005407 break;
5408 }
5409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410
Douglas Gilbert773642d2016-04-25 12:16:28 -04005411 if (sdebug_verbose)
5412 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005413
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005415
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005416bus_unreg:
5417 bus_unregister(&pseudo_lld_bus);
5418dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005419 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005420free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005421 vfree(map_storep);
5422 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005423 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005424free_q_arr:
5425 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005426 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427}
5428
5429static void __exit scsi_debug_exit(void)
5430{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005431 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432
5433 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005434 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 for (; k; k--)
5436 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 driver_unregister(&sdebug_driverfs_driver);
5438 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005439 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005441 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005442 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005444 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445}
5446
5447device_initcall(scsi_debug_init);
5448module_exit(scsi_debug_exit);
5449
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450static void sdebug_release_adapter(struct device * dev)
5451{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005452 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453
5454 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005455 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456}
5457
5458static int sdebug_add_adapter(void)
5459{
5460 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005461 int error = 0;
5462 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005463 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
Douglas Gilbert9a051012017-12-23 12:48:10 -05005465 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5466 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005467 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005468 return -ENOMEM;
5469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470
Douglas Gilbert9a051012017-12-23 12:48:10 -05005471 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472
Douglas Gilbert773642d2016-04-25 12:16:28 -04005473 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005474 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005475 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5476 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005477 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005478 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005480 }
5481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482
Douglas Gilbert9a051012017-12-23 12:48:10 -05005483 spin_lock(&sdebug_host_list_lock);
5484 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5485 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486
Douglas Gilbert9a051012017-12-23 12:48:10 -05005487 sdbg_host->dev.bus = &pseudo_lld_bus;
5488 sdbg_host->dev.parent = pseudo_primary;
5489 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005490 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491
Douglas Gilbert9a051012017-12-23 12:48:10 -05005492 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493
Douglas Gilbert9a051012017-12-23 12:48:10 -05005494 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 goto clean;
5496
Douglas Gilbert773642d2016-04-25 12:16:28 -04005497 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005498 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499
5500clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005501 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5502 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 list_del(&sdbg_devinfo->dev_list);
5504 kfree(sdbg_devinfo);
5505 }
5506
5507 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005508 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509}
5510
5511static void sdebug_remove_adapter(void)
5512{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005513 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514
Douglas Gilbert9a051012017-12-23 12:48:10 -05005515 spin_lock(&sdebug_host_list_lock);
5516 if (!list_empty(&sdebug_host_list)) {
5517 sdbg_host = list_entry(sdebug_host_list.prev,
5518 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 list_del(&sdbg_host->host_list);
5520 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005521 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522
5523 if (!sdbg_host)
5524 return;
5525
Douglas Gilbert773642d2016-04-25 12:16:28 -04005526 device_unregister(&sdbg_host->dev);
5527 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528}
5529
Douglas Gilbertfd321192016-04-25 12:16:33 -04005530static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005531{
5532 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005533 struct sdebug_dev_info *devip;
5534
Douglas Gilbertc4837392016-05-06 00:40:26 -04005535 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005536 devip = (struct sdebug_dev_info *)sdev->hostdata;
5537 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005538 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005539 return -ENODEV;
5540 }
5541 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005542
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005543 if (qdepth < 1)
5544 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005545 /* allow to exceed max host qc_arr elements for testing */
5546 if (qdepth > SDEBUG_CANQUEUE + 10)
5547 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005548 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005549
Douglas Gilbert773642d2016-04-25 12:16:28 -04005550 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005551 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005552 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005553 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005554 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005555 return sdev->queue_depth;
5556}
5557
Douglas Gilbertc4837392016-05-06 00:40:26 -04005558static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005559{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005560 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005561 if (sdebug_every_nth < -1)
5562 sdebug_every_nth = -1;
5563 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005564 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005565 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005566 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005567 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005568 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005569 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005570}
5571
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005572static bool fake_host_busy(struct scsi_cmnd *scp)
5573{
5574 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5575 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5576}
5577
Douglas Gilbertfd321192016-04-25 12:16:33 -04005578static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5579 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005580{
5581 u8 sdeb_i;
5582 struct scsi_device *sdp = scp->device;
5583 const struct opcode_info_t *oip;
5584 const struct opcode_info_t *r_oip;
5585 struct sdebug_dev_info *devip;
5586 u8 *cmd = scp->cmnd;
5587 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5588 int k, na;
5589 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005590 u32 flags;
5591 u16 sa;
5592 u8 opcode = cmd[0];
5593 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005594
5595 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005596 if (sdebug_statistics)
5597 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005598 if (unlikely(sdebug_verbose &&
5599 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005600 char b[120];
5601 int n, len, sb;
5602
5603 len = scp->cmd_len;
5604 sb = (int)sizeof(b);
5605 if (len > 32)
5606 strcpy(b, "too long, over 32 bytes");
5607 else {
5608 for (k = 0, n = 0; k < len && n < sb; ++k)
5609 n += scnprintf(b + n, sb - n, "%02x ",
5610 (u32)cmd[k]);
5611 }
Bart Van Assche458df782018-01-26 08:52:19 -08005612 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5613 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005614 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005615 if (fake_host_busy(scp))
5616 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005617 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005618 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5619 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005620
5621 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5622 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5623 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005624 if (unlikely(!devip)) {
5625 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005626 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005627 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005628 }
5629 na = oip->num_attached;
5630 r_pfp = oip->pfp;
5631 if (na) { /* multiple commands with this opcode */
5632 r_oip = oip;
5633 if (FF_SA & r_oip->flags) {
5634 if (F_SA_LOW & oip->flags)
5635 sa = 0x1f & cmd[1];
5636 else
5637 sa = get_unaligned_be16(cmd + 8);
5638 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5639 if (opcode == oip->opcode && sa == oip->sa)
5640 break;
5641 }
5642 } else { /* since no service action only check opcode */
5643 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5644 if (opcode == oip->opcode)
5645 break;
5646 }
5647 }
5648 if (k > na) {
5649 if (F_SA_LOW & r_oip->flags)
5650 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5651 else if (F_SA_HIGH & r_oip->flags)
5652 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5653 else
5654 mk_sense_invalid_opcode(scp);
5655 goto check_cond;
5656 }
5657 } /* else (when na==0) we assume the oip is a match */
5658 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005659 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005660 mk_sense_invalid_opcode(scp);
5661 goto check_cond;
5662 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005663 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005664 if (sdebug_verbose)
5665 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5666 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005667 mk_sense_invalid_opcode(scp);
5668 goto check_cond;
5669 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005670 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005671 u8 rem;
5672 int j;
5673
5674 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5675 rem = ~oip->len_mask[k] & cmd[k];
5676 if (rem) {
5677 for (j = 7; j >= 0; --j, rem <<= 1) {
5678 if (0x80 & rem)
5679 break;
5680 }
5681 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5682 goto check_cond;
5683 }
5684 }
5685 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005686 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005687 find_first_bit(devip->uas_bm,
5688 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005689 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005690 if (errsts)
5691 goto check_cond;
5692 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005693 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005694 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005695 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005696 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5697 "%s\n", my_name, "initializing command "
5698 "required");
5699 errsts = check_condition_result;
5700 goto fini;
5701 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005702 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005703 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005704 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005705 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005706 return 0; /* ignore command: make trouble */
5707 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005708 if (likely(oip->pfp))
5709 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005710 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5711 errsts = r_pfp(scp, devip);
5712
5713fini:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005714 if (F_DELAY_OVERR & flags)
5715 return schedule_resp(scp, devip, errsts, 0, 0);
5716 else
5717 return schedule_resp(scp, devip, errsts, sdebug_jdelay,
5718 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005719check_cond:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005720 return schedule_resp(scp, devip, check_condition_result, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005721err_out:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005722 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005723}
5724
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005725static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005726 .show_info = scsi_debug_show_info,
5727 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005728 .proc_name = sdebug_proc_name,
5729 .name = "SCSI DEBUG",
5730 .info = scsi_debug_info,
5731 .slave_alloc = scsi_debug_slave_alloc,
5732 .slave_configure = scsi_debug_slave_configure,
5733 .slave_destroy = scsi_debug_slave_destroy,
5734 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005735 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005736 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005737 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005738 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005739 .eh_target_reset_handler = scsi_debug_target_reset,
5740 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005741 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005742 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005743 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005744 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005745 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005746 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005747 .use_clustering = DISABLE_CLUSTERING,
5748 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005749 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005750};
5751
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752static int sdebug_driver_probe(struct device * dev)
5753{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005754 int error = 0;
5755 struct sdebug_host_info *sdbg_host;
5756 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005757 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758
5759 sdbg_host = to_sdebug_host(dev);
5760
Douglas Gilbert773642d2016-04-25 12:16:28 -04005761 sdebug_driver_template.can_queue = sdebug_max_queue;
5762 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005763 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005764 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5765 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005766 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005767 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005769 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005770 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005771 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005772 my_name, submit_queues, nr_cpu_ids);
5773 submit_queues = nr_cpu_ids;
5774 }
5775 /* Decide whether to tell scsi subsystem that we want mq */
5776 /* Following should give the same answer for each host */
Bart Van Assche458df782018-01-26 08:52:19 -08005777 if (shost_use_blk_mq(hpnt))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005778 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779
Douglas Gilbert9a051012017-12-23 12:48:10 -05005780 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005782 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5783 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005785 hpnt->max_id = sdebug_num_tgts;
5786 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005787 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005789 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005790
Douglas Gilbert773642d2016-04-25 12:16:28 -04005791 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005792
Christoph Hellwig8475c812016-09-11 19:35:41 +02005793 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005794 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005795 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005796 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005797 break;
5798
Christoph Hellwig8475c812016-09-11 19:35:41 +02005799 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005800 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005801 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005802 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005803 break;
5804
Christoph Hellwig8475c812016-09-11 19:35:41 +02005805 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005806 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005807 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005808 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005809 break;
5810
5811 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005812 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005813 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005814 break;
5815 }
5816
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005817 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005818
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005819 if (have_dif_prot || sdebug_dix)
5820 pr_info("host protection%s%s%s%s%s%s%s\n",
5821 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5822 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5823 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5824 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5825 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5826 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5827 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005828
Douglas Gilbert773642d2016-04-25 12:16:28 -04005829 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005830 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5831 else
5832 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5833
Douglas Gilbert773642d2016-04-25 12:16:28 -04005834 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5835 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005836 if (sdebug_every_nth) /* need stats counters for every_nth */
5837 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005838 error = scsi_add_host(hpnt, &sdbg_host->dev);
5839 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005840 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005841 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005843 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844 scsi_scan_host(hpnt);
5845
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005846 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847}
5848
5849static int sdebug_driver_remove(struct device * dev)
5850{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005851 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005852 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853
5854 sdbg_host = to_sdebug_host(dev);
5855
5856 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005857 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 return -ENODEV;
5859 }
5860
Douglas Gilbert9a051012017-12-23 12:48:10 -05005861 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005863 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5864 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005865 list_del(&sdbg_devinfo->dev_list);
5866 kfree(sdbg_devinfo);
5867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868
Douglas Gilbert9a051012017-12-23 12:48:10 -05005869 scsi_host_put(sdbg_host->shost);
5870 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871}
5872
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005873static int pseudo_lld_bus_match(struct device *dev,
5874 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005876 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005878
5879static struct bus_type pseudo_lld_bus = {
5880 .name = "pseudo",
5881 .match = pseudo_lld_bus_match,
5882 .probe = sdebug_driver_probe,
5883 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005884 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005885};