blob: 24d7496cd9e23cfc2a97126fc22b5f4c25a253b0 [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 Gilbert80c49562018-02-09 21:36:39 -05009 * Copyright (C) 2001 - 2018 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 Gilbert80c49562018-02-09 21:36:39 -050064#define SDEBUG_VERSION "0188" /* format to fit INQUIRY revision field */
65static const char *sdebug_version_date = "20180128";
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 */
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400237#define F_SSU_DELAY 0x1000
238#define F_SYNC_DELAY 0x2000
Douglas Gilbertfd321192016-04-25 12:16:33 -0400239
240#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500241#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400242#define FF_SA (F_SA_HIGH | F_SA_LOW)
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400243#define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400244
245#define SDEBUG_MAX_PARTS 4
246
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400247#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400248
249
250struct sdebug_dev_info {
251 struct list_head dev_list;
252 unsigned int channel;
253 unsigned int target;
254 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200255 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400256 struct sdebug_host_info *sdbg_host;
257 unsigned long uas_bm[1];
258 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400259 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400260 bool used;
261};
262
263struct sdebug_host_info {
264 struct list_head host_list;
265 struct Scsi_Host *shost;
266 struct device dev;
267 struct list_head dev_info_list;
268};
269
270#define to_sdebug_host(d) \
271 container_of(d, struct sdebug_host_info, dev)
272
Douglas Gilbert10bde982018-01-10 16:57:31 -0500273enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
274 SDEB_DEFER_WQ = 2};
275
Douglas Gilbertfd321192016-04-25 12:16:33 -0400276struct sdebug_defer {
277 struct hrtimer hrt;
278 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400279 int sqa_idx; /* index of sdebug_queue array */
280 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
281 int issuing_cpu;
Douglas Gilbert10bde982018-01-10 16:57:31 -0500282 bool init_hrt;
283 bool init_wq;
284 enum sdeb_defer_type defer_t;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400285};
286
287struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400288 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
289 * instance indicates this slot is in use.
290 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400291 struct sdebug_defer *sd_dp;
292 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400293 unsigned int inj_recovered:1;
294 unsigned int inj_transport:1;
295 unsigned int inj_dif:1;
296 unsigned int inj_dix:1;
297 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800298 unsigned int inj_host_busy:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400299};
300
Douglas Gilbertc4837392016-05-06 00:40:26 -0400301struct sdebug_queue {
302 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
303 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
304 spinlock_t qc_lock;
305 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400306};
307
Douglas Gilbertc4837392016-05-06 00:40:26 -0400308static atomic_t sdebug_cmnd_count; /* number of incoming commands */
309static atomic_t sdebug_completions; /* count of deferred completions */
310static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
311static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
312
Douglas Gilbertfd321192016-04-25 12:16:33 -0400313struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400314 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
315 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400316 u8 opcode; /* if num_attached > 0, preferred */
317 u16 sa; /* service action */
318 u32 flags; /* OR-ed set of SDEB_F_* */
319 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
320 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500321 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
322 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400323};
324
325/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500326enum sdeb_opcode_index {
327 SDEB_I_INVALID_OPCODE = 0,
328 SDEB_I_INQUIRY = 1,
329 SDEB_I_REPORT_LUNS = 2,
330 SDEB_I_REQUEST_SENSE = 3,
331 SDEB_I_TEST_UNIT_READY = 4,
332 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
333 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
334 SDEB_I_LOG_SENSE = 7,
335 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
336 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
337 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
338 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500339 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
340 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500341 SDEB_I_MAINT_IN = 14,
342 SDEB_I_MAINT_OUT = 15,
343 SDEB_I_VERIFY = 16, /* 10 only */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500344 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500345 SDEB_I_RESERVE = 18, /* 6, 10 */
346 SDEB_I_RELEASE = 19, /* 6, 10 */
347 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
348 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
349 SDEB_I_ATA_PT = 22, /* 12, 16 */
350 SDEB_I_SEND_DIAG = 23,
351 SDEB_I_UNMAP = 24,
352 SDEB_I_XDWRITEREAD = 25, /* 10 only */
353 SDEB_I_WRITE_BUFFER = 26,
354 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
Douglas Gilbert80c49562018-02-09 21:36:39 -0500355 SDEB_I_SYNC_CACHE = 28, /* 10, 16 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500356 SDEB_I_COMP_WRITE = 29,
Douglas Gilbert9a051012017-12-23 12:48:10 -0500357 SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500358};
359
Douglas Gilbertc4837392016-05-06 00:40:26 -0400360
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500361static const unsigned char opcode_ind_arr[256] = {
362/* 0x0; 0x0->0x1f: 6 byte cdbs */
363 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
364 0, 0, 0, 0,
365 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
366 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
367 SDEB_I_RELEASE,
368 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
369 SDEB_I_ALLOW_REMOVAL, 0,
370/* 0x20; 0x20->0x3f: 10 byte cdbs */
371 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
372 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
373 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
374 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
375/* 0x40; 0x40->0x5f: 10 byte cdbs */
376 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
377 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
378 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
379 SDEB_I_RELEASE,
380 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400381/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384 0, SDEB_I_VARIABLE_LEN,
385/* 0x80; 0x80->0x9f: 16 byte cdbs */
386 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
387 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500388 0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500389 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 -0500390/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
391 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
392 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500393 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
394 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500395 0, 0, 0, 0, 0, 0, 0, 0,
396 0, 0, 0, 0, 0, 0, 0, 0,
397/* 0xc0; 0xc0->0xff: vendor specific */
398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
400 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
401 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402};
403
Douglas Gilbert80c49562018-02-09 21:36:39 -0500404/*
405 * The following "response" functions return the SCSI mid-level's 4 byte
406 * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
407 * command completion, they can mask their return value with
408 * SDEG_RES_IMMED_MASK .
409 */
410#define SDEG_RES_IMMED_MASK 0x40000000
411
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500412static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
413static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
414static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
415static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
416static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
417static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
418static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
419static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
420static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500421static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500422static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
423static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
424static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
425static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
426static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500427static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
428static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500429static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
430static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
431static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500432static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500433static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert80c49562018-02-09 21:36:39 -0500434static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500435
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500436/*
437 * The following are overflow arrays for cdbs that "hit" the same index in
438 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
439 * should be placed in opcode_info_arr[], the others should be placed here.
440 */
441static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500442 {0, 0x1a, 0, F_D_IN, NULL, NULL,
443 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
444};
445
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500446static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500447 {0, 0x15, 0, F_D_OUT, NULL, NULL,
448 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
449};
450
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500451static const struct opcode_info_t read_iarr[] = {
452 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500453 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500454 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500455 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500456 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500457 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500458 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500459 0xc7, 0, 0, 0, 0} },
460};
461
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500462static const struct opcode_info_t write_iarr[] = {
463 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
464 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
465 0, 0, 0, 0, 0, 0} },
466 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
467 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
468 0, 0, 0} },
469 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
470 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
471 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500472};
473
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500474static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500475 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
476 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500477 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500478};
479
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500480static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
481 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500482 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500483 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500484 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
485 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
486 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500487};
488
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500489static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500490 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500491 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500492 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500493 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500494 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500495 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500496};
497
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500498static const struct opcode_info_t write_same_iarr[] = {
499 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500500 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500501 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500502};
503
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500504static const struct opcode_info_t reserve_iarr[] = {
505 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500506 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
507};
508
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500509static const struct opcode_info_t release_iarr[] = {
510 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500511 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
512};
513
Douglas Gilbert80c49562018-02-09 21:36:39 -0500514static const struct opcode_info_t sync_cache_iarr[] = {
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400515 {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500516 {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
517 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */
518};
519
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500520
521/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
522 * plus the terminating elements for logic that scans this table such as
523 * REPORT SUPPORTED OPERATION CODES. */
524static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
525/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500526 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500527 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500528 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500529 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
530 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
531 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500532 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500533 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
534 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
535 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
536 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500537/* 5 */
538 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
539 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
540 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
541 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
542 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
543 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
544 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500545 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
546 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500547 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500548 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
549 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500550 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
551 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
552 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500553/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500554 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
555 resp_write_dt0, write_iarr, /* WRITE(16) */
556 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500557 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400558 {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500559 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500560 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
561 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
562 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
563 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500564 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
565 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
566 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500567 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
568 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
569 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
570 0xff, 0, 0xc7, 0, 0, 0, 0} },
571/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500572 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
573 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500574 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500575 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
576 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500577 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
578 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
579 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
580 0xff, 0xff} },
581 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
582 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500583 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
584 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500585 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
586 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500587 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
588 0} },
589/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500590 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
591 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500592 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
593 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
594 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
595 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
596 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
597 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500598 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500599 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500600/* 25 */
601 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500602 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500603 0, 0, 0, 0, 0, 0} }, /* XDWRITEREAD(10) */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500604 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
605 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
606 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500607 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
608 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
609 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
610 0, 0, 0, 0, 0} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400611 {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500612 resp_sync_cache, sync_cache_iarr,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500613 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500614 0, 0, 0, 0} }, /* SYNC_CACHE (10) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500615 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500616 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500617 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500618
619/* 30 */
620 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
621 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
622};
623
Douglas Gilbert773642d2016-04-25 12:16:28 -0400624static int sdebug_add_host = DEF_NUM_HOST;
625static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500626static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400627static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400628static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
629static int sdebug_dif = DEF_DIF;
630static int sdebug_dix = DEF_DIX;
631static int sdebug_dsense = DEF_D_SENSE;
632static int sdebug_every_nth = DEF_EVERY_NTH;
633static int sdebug_fake_rw = DEF_FAKE_RW;
634static unsigned int sdebug_guard = DEF_GUARD;
635static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
636static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400637static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Laurence Obermand9da8912018-02-03 13:38:35 -0500638static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
639static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400640static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400641static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400642static int sdebug_no_lun_0 = DEF_NO_LUN_0;
643static int sdebug_no_uld;
644static int sdebug_num_parts = DEF_NUM_PARTS;
645static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
646static int sdebug_opt_blks = DEF_OPT_BLKS;
647static int sdebug_opts = DEF_OPTS;
648static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100649static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400650static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400651static int sdebug_scsi_level = DEF_SCSI_LEVEL;
652static int sdebug_sector_size = DEF_SECTOR_SIZE;
653static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
654static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
655static unsigned int sdebug_lbpu = DEF_LBPU;
656static unsigned int sdebug_lbpws = DEF_LBPWS;
657static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
658static unsigned int sdebug_lbprz = DEF_LBPRZ;
659static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
660static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
661static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
662static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
663static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400664static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400665static bool sdebug_removable = DEF_REMOVABLE;
666static bool sdebug_clustering;
667static bool sdebug_host_lock = DEF_HOST_LOCK;
668static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500669static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400670static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400671static bool have_dif_prot;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400672static bool write_since_sync;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400673static bool sdebug_statistics = DEF_STATISTICS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400675static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676static sector_t sdebug_capacity; /* in sectors */
677
678/* old BIOS stuff, kernel may get rid of them but some mode sense pages
679 may still need them */
680static int sdebug_heads; /* heads per disk */
681static int sdebug_cylinders_per; /* cylinders per surface */
682static int sdebug_sectors_per; /* sectors per cylinder */
683
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684static LIST_HEAD(sdebug_host_list);
685static DEFINE_SPINLOCK(sdebug_host_list_lock);
686
Douglas Gilbertfd321192016-04-25 12:16:33 -0400687static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200688static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400689static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Martin K. Petersen44d92692009-10-15 14:45:27 -0400691static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400692static int num_aborts;
693static int num_dev_resets;
694static int num_target_resets;
695static int num_bus_resets;
696static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500697static int dix_writes;
698static int dix_reads;
699static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Douglas Gilbertc4837392016-05-06 00:40:26 -0400701static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
702static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400703
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704static DEFINE_RWLOCK(atomic_rw);
705
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400706static char sdebug_proc_name[] = MY_NAME;
707static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709static struct bus_type pseudo_lld_bus;
710
711static struct device_driver sdebug_driverfs_driver = {
712 .name = sdebug_proc_name,
713 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714};
715
716static const int check_condition_result =
717 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
718
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500719static const int illegal_condition_result =
720 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
721
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400722static const int device_qfull_result =
723 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
724
Douglas Gilbertfd321192016-04-25 12:16:33 -0400725
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400726/* Only do the extra work involved in logical block provisioning if one or
727 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
728 * real reads and writes (i.e. not skipping them for speed).
729 */
730static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400731{
732 return 0 == sdebug_fake_rw &&
733 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
734}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400735
Akinobu Mita14faa942013-09-18 21:27:24 +0900736static void *fake_store(unsigned long long lba)
737{
738 lba = do_div(lba, sdebug_store_sectors);
739
Douglas Gilbert773642d2016-04-25 12:16:28 -0400740 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900741}
742
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200743static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900744{
Arnd Bergmann49413112015-11-20 17:38:28 +0100745 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900746
747 return dif_storep + sector;
748}
749
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900750static void sdebug_max_tgts_luns(void)
751{
752 struct sdebug_host_info *sdbg_host;
753 struct Scsi_Host *hpnt;
754
755 spin_lock(&sdebug_host_list_lock);
756 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
757 hpnt = sdbg_host->shost;
758 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400759 (sdebug_num_tgts > hpnt->this_id))
760 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900761 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400762 hpnt->max_id = sdebug_num_tgts;
763 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300764 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900765 }
766 spin_unlock(&sdebug_host_list_lock);
767}
768
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500769enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
770
771/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400772static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
773 enum sdeb_cmd_data c_d,
774 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500775{
776 unsigned char *sbuff;
777 u8 sks[4];
778 int sl, asc;
779
780 sbuff = scp->sense_buffer;
781 if (!sbuff) {
782 sdev_printk(KERN_ERR, scp->device,
783 "%s: sense_buffer is NULL\n", __func__);
784 return;
785 }
786 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
787 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400788 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500789 memset(sks, 0, sizeof(sks));
790 sks[0] = 0x80;
791 if (c_d)
792 sks[0] |= 0x40;
793 if (in_bit >= 0) {
794 sks[0] |= 0x8;
795 sks[0] |= 0x7 & in_bit;
796 }
797 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400798 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500799 sl = sbuff[7] + 8;
800 sbuff[7] = sl;
801 sbuff[sl] = 0x2;
802 sbuff[sl + 1] = 0x6;
803 memcpy(sbuff + sl + 4, sks, 3);
804 } else
805 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400806 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500807 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
808 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
809 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
810}
811
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400812static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900813{
814 unsigned char *sbuff;
815
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400816 sbuff = scp->sense_buffer;
817 if (!sbuff) {
818 sdev_printk(KERN_ERR, scp->device,
819 "%s: sense_buffer is NULL\n", __func__);
820 return;
821 }
822 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900823
Douglas Gilbert773642d2016-04-25 12:16:28 -0400824 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900825
Douglas Gilbert773642d2016-04-25 12:16:28 -0400826 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400827 sdev_printk(KERN_INFO, scp->device,
828 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
829 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900830}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Douglas Gilbertfd321192016-04-25 12:16:33 -0400832static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500833{
834 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
835}
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
838{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400839 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400840 if (0x1261 == cmd)
841 sdev_printk(KERN_INFO, dev,
842 "%s: BLKFLSBUF [0x1261]\n", __func__);
843 else if (0x5331 == cmd)
844 sdev_printk(KERN_INFO, dev,
845 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
846 __func__);
847 else
848 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
849 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
851 return -EINVAL;
852 /* return -ENOTTY; // correct return but upsets fdisk */
853}
854
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500855static void config_cdb_len(struct scsi_device *sdev)
856{
857 switch (sdebug_cdb_len) {
858 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
859 sdev->use_10_for_rw = false;
860 sdev->use_16_for_rw = false;
861 sdev->use_10_for_ms = false;
862 break;
863 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
864 sdev->use_10_for_rw = true;
865 sdev->use_16_for_rw = false;
866 sdev->use_10_for_ms = false;
867 break;
868 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
869 sdev->use_10_for_rw = true;
870 sdev->use_16_for_rw = false;
871 sdev->use_10_for_ms = true;
872 break;
873 case 16:
874 sdev->use_10_for_rw = false;
875 sdev->use_16_for_rw = true;
876 sdev->use_10_for_ms = true;
877 break;
878 case 32: /* No knobs to suggest this so same as 16 for now */
879 sdev->use_10_for_rw = false;
880 sdev->use_16_for_rw = true;
881 sdev->use_10_for_ms = true;
882 break;
883 default:
884 pr_warn("unexpected cdb_len=%d, force to 10\n",
885 sdebug_cdb_len);
886 sdev->use_10_for_rw = true;
887 sdev->use_16_for_rw = false;
888 sdev->use_10_for_ms = false;
889 sdebug_cdb_len = 10;
890 break;
891 }
892}
893
894static void all_config_cdb_len(void)
895{
896 struct sdebug_host_info *sdbg_host;
897 struct Scsi_Host *shost;
898 struct scsi_device *sdev;
899
900 spin_lock(&sdebug_host_list_lock);
901 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
902 shost = sdbg_host->shost;
903 shost_for_each_device(sdev, shost) {
904 config_cdb_len(sdev);
905 }
906 }
907 spin_unlock(&sdebug_host_list_lock);
908}
909
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500910static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
911{
912 struct sdebug_host_info *sdhp;
913 struct sdebug_dev_info *dp;
914
915 spin_lock(&sdebug_host_list_lock);
916 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
917 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
918 if ((devip->sdbg_host == dp->sdbg_host) &&
919 (devip->target == dp->target))
920 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
921 }
922 }
923 spin_unlock(&sdebug_host_list_lock);
924}
925
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400926static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400928 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400929
930 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
931 if (k != SDEBUG_NUM_UAS) {
932 const char *cp = NULL;
933
934 switch (k) {
935 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400936 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
937 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400938 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400939 cp = "power on reset";
940 break;
941 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400942 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
943 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400944 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400945 cp = "bus reset";
946 break;
947 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400948 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
949 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400950 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400951 cp = "mode parameters changed";
952 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500953 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400954 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
955 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400956 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500957 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500958 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500959 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400960 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400961 TARGET_CHANGED_ASC,
962 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400963 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500964 cp = "microcode has been changed";
965 break;
966 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400967 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500968 TARGET_CHANGED_ASC,
969 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400970 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500971 cp = "microcode has been changed without reset";
972 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500973 case SDEBUG_UA_LUNS_CHANGED:
974 /*
975 * SPC-3 behavior is to report a UNIT ATTENTION with
976 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
977 * on the target, until a REPORT LUNS command is
978 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400979 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500980 * values as struct scsi_device->scsi_level.
981 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400982 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500983 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400984 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500985 TARGET_CHANGED_ASC,
986 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400987 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500988 cp = "reported luns data has changed";
989 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400990 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400991 pr_warn("unexpected unit attention code=%d\n", k);
992 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400993 cp = "unknown";
994 break;
995 }
996 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400997 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400998 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400999 "%s reports: Unit attention: %s\n",
1000 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 return check_condition_result;
1002 }
1003 return 0;
1004}
1005
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001006/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001007static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 int arr_len)
1009{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001010 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001011 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001013 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001015 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -04001016 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001017
1018 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
1019 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -07001020 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 return 0;
1023}
1024
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001025/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1026 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1027 * calls, not required to write in ascending offset order. Assumes resid
1028 * set to scsi_bufflen() prior to any calls.
1029 */
1030static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1031 int arr_len, unsigned int off_dst)
1032{
1033 int act_len, n;
1034 struct scsi_data_buffer *sdb = scsi_in(scp);
1035 off_t skip = off_dst;
1036
1037 if (sdb->length <= off_dst)
1038 return 0;
1039 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1040 return DID_ERROR << 16;
1041
1042 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1043 arr, arr_len, skip);
1044 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1045 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1046 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1047 sdb->resid = min(sdb->resid, n);
1048 return 0;
1049}
1050
1051/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1052 * 'arr' or -1 if error.
1053 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001054static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1055 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001057 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001059 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001061
1062 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063}
1064
1065
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001066static char sdebug_inq_vendor_id[9] = "Linux ";
1067static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001068static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001069/* Use some locally assigned NAAs for SAS addresses. */
1070static const u64 naa3_comp_a = 0x3222222000000000ULL;
1071static const u64 naa3_comp_b = 0x3333333000000000ULL;
1072static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001074/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001075static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1076 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001077 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001078 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001080 int num, port_a;
1081 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001083 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 /* T10 vendor identifier field format (faked) */
1085 arr[0] = 0x2; /* ASCII */
1086 arr[1] = 0x1;
1087 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001088 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1089 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1091 num = 8 + 16 + dev_id_str_len;
1092 arr[3] = num;
1093 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001094 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001095 if (sdebug_uuid_ctl) {
1096 /* Locally assigned UUID */
1097 arr[num++] = 0x1; /* binary (not necessarily sas) */
1098 arr[num++] = 0xa; /* PIV=0, lu, naa */
1099 arr[num++] = 0x0;
1100 arr[num++] = 0x12;
1101 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1102 arr[num++] = 0x0;
1103 memcpy(arr + num, lu_name, 16);
1104 num += 16;
1105 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001106 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001107 arr[num++] = 0x1; /* binary (not necessarily sas) */
1108 arr[num++] = 0x3; /* PIV=0, lu, naa */
1109 arr[num++] = 0x0;
1110 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001111 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001112 num += 8;
1113 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001114 /* Target relative port number */
1115 arr[num++] = 0x61; /* proto=sas, binary */
1116 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1117 arr[num++] = 0x0; /* reserved */
1118 arr[num++] = 0x4; /* length */
1119 arr[num++] = 0x0; /* reserved */
1120 arr[num++] = 0x0; /* reserved */
1121 arr[num++] = 0x0;
1122 arr[num++] = 0x1; /* relative port A */
1123 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001124 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001125 arr[num++] = 0x61; /* proto=sas, binary */
1126 arr[num++] = 0x93; /* piv=1, target port, naa */
1127 arr[num++] = 0x0;
1128 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001129 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001130 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001131 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001132 arr[num++] = 0x61; /* proto=sas, binary */
1133 arr[num++] = 0x95; /* piv=1, target port group id */
1134 arr[num++] = 0x0;
1135 arr[num++] = 0x4;
1136 arr[num++] = 0;
1137 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001138 put_unaligned_be16(port_group_id, arr + num);
1139 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001140 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001141 arr[num++] = 0x61; /* proto=sas, binary */
1142 arr[num++] = 0xa3; /* piv=1, target device, naa */
1143 arr[num++] = 0x0;
1144 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001145 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001146 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001147 /* SCSI name string: Target device identifier */
1148 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1149 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1150 arr[num++] = 0x0;
1151 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001152 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001153 num += 12;
1154 snprintf(b, sizeof(b), "%08X", target_dev_id);
1155 memcpy(arr + num, b, 8);
1156 num += 8;
1157 memset(arr + num, 0, 4);
1158 num += 4;
1159 return num;
1160}
1161
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001162static unsigned char vpd84_data[] = {
1163/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1164 0x22,0x22,0x22,0x0,0xbb,0x1,
1165 0x22,0x22,0x22,0x0,0xbb,0x2,
1166};
1167
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001168/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001169static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001170{
1171 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1172 return sizeof(vpd84_data);
1173}
1174
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001175/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001176static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001177{
1178 int num = 0;
John Pittman91d4c752018-02-09 21:12:43 -05001179 const char *na1 = "https://www.kernel.org/config";
1180 const char *na2 = "http://www.kernel.org/log";
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001181 int plen, olen;
1182
1183 arr[num++] = 0x1; /* lu, storage config */
1184 arr[num++] = 0x0; /* reserved */
1185 arr[num++] = 0x0;
1186 olen = strlen(na1);
1187 plen = olen + 1;
1188 if (plen % 4)
1189 plen = ((plen / 4) + 1) * 4;
1190 arr[num++] = plen; /* length, null termianted, padded */
1191 memcpy(arr + num, na1, olen);
1192 memset(arr + num + olen, 0, plen - olen);
1193 num += plen;
1194
1195 arr[num++] = 0x4; /* lu, logging */
1196 arr[num++] = 0x0; /* reserved */
1197 arr[num++] = 0x0;
1198 olen = strlen(na2);
1199 plen = olen + 1;
1200 if (plen % 4)
1201 plen = ((plen / 4) + 1) * 4;
1202 arr[num++] = plen; /* length, null terminated, padded */
1203 memcpy(arr + num, na2, olen);
1204 memset(arr + num + olen, 0, plen - olen);
1205 num += plen;
1206
1207 return num;
1208}
1209
1210/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001211static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001212{
1213 int num = 0;
1214 int port_a, port_b;
1215
1216 port_a = target_dev_id + 1;
1217 port_b = port_a + 1;
1218 arr[num++] = 0x0; /* reserved */
1219 arr[num++] = 0x0; /* reserved */
1220 arr[num++] = 0x0;
1221 arr[num++] = 0x1; /* relative port 1 (primary) */
1222 memset(arr + num, 0, 6);
1223 num += 6;
1224 arr[num++] = 0x0;
1225 arr[num++] = 12; /* length tp descriptor */
1226 /* naa-5 target port identifier (A) */
1227 arr[num++] = 0x61; /* proto=sas, binary */
1228 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1229 arr[num++] = 0x0; /* reserved */
1230 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001231 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001232 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001233 arr[num++] = 0x0; /* reserved */
1234 arr[num++] = 0x0; /* reserved */
1235 arr[num++] = 0x0;
1236 arr[num++] = 0x2; /* relative port 2 (secondary) */
1237 memset(arr + num, 0, 6);
1238 num += 6;
1239 arr[num++] = 0x0;
1240 arr[num++] = 12; /* length tp descriptor */
1241 /* naa-5 target port identifier (B) */
1242 arr[num++] = 0x61; /* proto=sas, binary */
1243 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1244 arr[num++] = 0x0; /* reserved */
1245 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001246 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001247 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001248
1249 return num;
1250}
1251
1252
1253static unsigned char vpd89_data[] = {
1254/* from 4th byte */ 0,0,0,0,
1255'l','i','n','u','x',' ',' ',' ',
1256'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1257'1','2','3','4',
12580x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12590xec,0,0,0,
12600x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12610,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12620x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12630x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12640x53,0x41,
12650x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12660x20,0x20,
12670x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12680x10,0x80,
12690,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12700x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12710x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12720,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12730x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12740x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12750,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12760,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12770,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12790x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12800,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12810xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12820,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
12830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12880,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12890,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12900,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12940,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1295};
1296
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001297/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001298static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001299{
1300 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1301 return sizeof(vpd89_data);
1302}
1303
1304
1305static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001306 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1307 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1308 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1309 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001310};
1311
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001312/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001313static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001314{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001315 unsigned int gran;
1316
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001317 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001318
1319 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001320 if (sdebug_opt_xferlen_exp != 0 &&
1321 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1322 gran = 1 << sdebug_opt_xferlen_exp;
1323 else
1324 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001325 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001326
1327 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001328 if (sdebug_store_sectors > 0x400)
1329 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001330
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001331 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001332 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001333
Douglas Gilbert773642d2016-04-25 12:16:28 -04001334 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001335 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001336 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001337
1338 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001339 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001340 }
1341
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001342 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001343 if (sdebug_unmap_alignment) {
1344 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001345 arr[28] |= 0x80; /* UGAVALID */
1346 }
1347
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001348 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001349 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001350
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001351 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001352 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001353
1354 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001355
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001356 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357}
1358
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001359/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001360static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001361{
1362 memset(arr, 0, 0x3c);
1363 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001364 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1365 arr[2] = 0;
1366 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001367
1368 return 0x3c;
1369}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001371/* Logical block provisioning VPD page (SBC-4) */
1372static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001373{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001374 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001375 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001376 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001377 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001378 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001379 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001380 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001381 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001382 if (sdebug_lbprz && scsi_debug_lbp())
1383 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1384 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1385 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1386 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001387 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001388}
1389
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001391#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001393static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
1395 unsigned char pq_pdt;
John Pittman91d4c752018-02-09 21:12:43 -05001396 unsigned char *arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001397 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001398 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001399 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
Douglas Gilbert773642d2016-04-25 12:16:28 -04001401 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001402 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1403 if (! arr)
1404 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001405 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001406 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001407 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001408 pq_pdt = TYPE_WLUN; /* present, wlun */
1409 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1410 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001411 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001412 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 arr[0] = pq_pdt;
1414 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001415 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001416 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 return check_condition_result;
1418 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001419 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001420 char lu_id_str[6];
1421 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001423 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1424 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001425 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001426 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001427 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001428 (devip->target * 1000) + devip->lun);
1429 target_dev_id = ((host_no + 1) * 2000) +
1430 (devip->target * 1000) - 3;
1431 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001433 arr[1] = cmd[2]; /*sanity */
1434 n = 4;
1435 arr[n++] = 0x0; /* this page */
1436 arr[n++] = 0x80; /* unit serial number */
1437 arr[n++] = 0x83; /* device identification */
1438 arr[n++] = 0x84; /* software interface ident. */
1439 arr[n++] = 0x85; /* management network addresses */
1440 arr[n++] = 0x86; /* extended inquiry */
1441 arr[n++] = 0x87; /* mode page policy */
1442 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001443 if (is_disk) { /* SBC only */
1444 arr[n++] = 0x89; /* ATA information */
1445 arr[n++] = 0xb0; /* Block limits */
1446 arr[n++] = 0xb1; /* Block characteristics */
1447 arr[n++] = 0xb2; /* Logical Block Prov */
1448 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001449 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001451 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001453 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001455 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001456 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1457 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001458 lu_id_str, len,
1459 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001460 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1461 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001462 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001463 } else if (0x85 == cmd[2]) { /* Management network addresses */
1464 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001465 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001466 } else if (0x86 == cmd[2]) { /* extended inquiry */
1467 arr[1] = cmd[2]; /*sanity */
1468 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001469 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001470 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001471 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001472 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1473 else
1474 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001475 arr[5] = 0x7; /* head of q, ordered + simple q's */
1476 } else if (0x87 == cmd[2]) { /* mode page policy */
1477 arr[1] = cmd[2]; /*sanity */
1478 arr[3] = 0x8; /* number of following entries */
1479 arr[4] = 0x2; /* disconnect-reconnect mp */
1480 arr[6] = 0x80; /* mlus, shared */
1481 arr[8] = 0x18; /* protocol specific lu */
1482 arr[10] = 0x82; /* mlus, per initiator port */
1483 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1484 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001485 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1486 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001487 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001488 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001489 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001490 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001491 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001492 arr[3] = inquiry_vpd_b0(&arr[4]);
1493 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001494 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001495 arr[3] = inquiry_vpd_b1(&arr[4]);
1496 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001497 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001498 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001500 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001501 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 return check_condition_result;
1503 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001504 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001505 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001506 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001507 kfree(arr);
1508 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 }
1510 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001511 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1512 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 arr[3] = 2; /* response_data_format==2 */
1514 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001515 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001516 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001517 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001518 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001520 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001521 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1522 memcpy(&arr[16], sdebug_inq_product_id, 16);
1523 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001524 /* Use Vendor Specific area to place driver date in ASCII hex */
1525 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001527 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1528 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001529 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001530 if (is_disk) { /* SBC-4 no version claimed */
1531 put_unaligned_be16(0x600, arr + n);
1532 n += 2;
1533 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1534 put_unaligned_be16(0x525, arr + n);
1535 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001537 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001538 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001540 kfree(arr);
1541 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542}
1543
Douglas Gilbertfd321192016-04-25 12:16:33 -04001544static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1545 0, 0, 0x0, 0x0};
1546
John Pittman91d4c752018-02-09 21:12:43 -05001547static int resp_requests(struct scsi_cmnd *scp,
1548 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549{
John Pittman91d4c752018-02-09 21:12:43 -05001550 unsigned char *sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001551 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001552 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001553 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 int len = 18;
1555
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001556 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001557 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001558 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001559 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001560 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001561 arr[0] = 0x72;
1562 arr[1] = 0x0; /* NO_SENSE in sense_key */
1563 arr[2] = THRESHOLD_EXCEEDED;
1564 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001565 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001566 } else {
1567 arr[0] = 0x70;
1568 arr[2] = 0x0; /* NO_SENSE in sense_key */
1569 arr[7] = 0xa; /* 18 byte sense buffer */
1570 arr[12] = THRESHOLD_EXCEEDED;
1571 arr[13] = 0xff; /* TEST set and MRIE==6 */
1572 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001573 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001574 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001575 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001576 ; /* have sense and formats match */
1577 else if (arr[0] <= 0x70) {
1578 if (dsense) {
1579 memset(arr, 0, 8);
1580 arr[0] = 0x72;
1581 len = 8;
1582 } else {
1583 memset(arr, 0, 18);
1584 arr[0] = 0x70;
1585 arr[7] = 0xa;
1586 }
1587 } else if (dsense) {
1588 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001589 arr[0] = 0x72;
1590 arr[1] = sbuff[2]; /* sense key */
1591 arr[2] = sbuff[12]; /* asc */
1592 arr[3] = sbuff[13]; /* ascq */
1593 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001594 } else {
1595 memset(arr, 0, 18);
1596 arr[0] = 0x70;
1597 arr[2] = sbuff[1];
1598 arr[7] = 0xa;
1599 arr[12] = sbuff[1];
1600 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001601 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001602
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001603 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001604 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 return fill_from_dev_buffer(scp, arr, len);
1606}
1607
John Pittman91d4c752018-02-09 21:12:43 -05001608static int resp_start_stop(struct scsi_cmnd *scp,
1609 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001610{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001611 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001612 int power_cond, stop;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001613 bool changing;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001614
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001615 power_cond = (cmd[4] & 0xf0) >> 4;
1616 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001617 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001618 return check_condition_result;
1619 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001620 stop = !(cmd[4] & 1);
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001621 changing = atomic_read(&devip->stopped) == !stop;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001622 atomic_xchg(&devip->stopped, stop);
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001623 if (!changing || cmd[1] & 0x1) /* state unchanged or IMMED set */
1624 return SDEG_RES_IMMED_MASK;
1625 else
1626 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627}
1628
FUJITA Tomonori28898872008-03-30 00:59:55 +09001629static sector_t get_sdebug_capacity(void)
1630{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001631 static const unsigned int gibibyte = 1073741824;
1632
1633 if (sdebug_virtual_gb > 0)
1634 return (sector_t)sdebug_virtual_gb *
1635 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001636 else
1637 return sdebug_store_sectors;
1638}
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640#define SDEBUG_READCAP_ARR_SZ 8
John Pittman91d4c752018-02-09 21:12:43 -05001641static int resp_readcap(struct scsi_cmnd *scp,
1642 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643{
1644 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001645 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001647 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001648 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001650 if (sdebug_capacity < 0xffffffff) {
1651 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001652 put_unaligned_be32(capac, arr + 0);
1653 } else
1654 put_unaligned_be32(0xffffffff, arr + 0);
1655 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1657}
1658
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001659#define SDEBUG_READCAP16_ARR_SZ 32
John Pittman91d4c752018-02-09 21:12:43 -05001660static int resp_readcap16(struct scsi_cmnd *scp,
1661 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001662{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001663 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001664 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001665 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001666
Douglas Gilbert773642d2016-04-25 12:16:28 -04001667 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001668 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001669 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001670 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001671 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1672 put_unaligned_be32(sdebug_sector_size, arr + 8);
1673 arr[13] = sdebug_physblk_exp & 0xf;
1674 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001675
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001676 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001677 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001678 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1679 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1680 * in the wider field maps to 0 in this field.
1681 */
1682 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1683 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001684 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001685
Douglas Gilbert773642d2016-04-25 12:16:28 -04001686 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001687
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001688 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001689 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001690 arr[12] |= 1; /* PROT_EN */
1691 }
1692
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001693 return fill_from_dev_buffer(scp, arr,
1694 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1695}
1696
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001697#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1698
John Pittman91d4c752018-02-09 21:12:43 -05001699static int resp_report_tgtpgs(struct scsi_cmnd *scp,
1700 struct sdebug_dev_info *devip)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001701{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001702 unsigned char *cmd = scp->cmnd;
John Pittman91d4c752018-02-09 21:12:43 -05001703 unsigned char *arr;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001704 int host_no = devip->sdbg_host->shost->host_no;
1705 int n, ret, alen, rlen;
1706 int port_group_a, port_group_b, port_a, port_b;
1707
Douglas Gilbert773642d2016-04-25 12:16:28 -04001708 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001709 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1710 if (! arr)
1711 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001712 /*
1713 * EVPD page 0x88 states we have two ports, one
1714 * real and a fake port with no device connected.
1715 * So we create two port groups with one port each
1716 * and set the group with port B to unavailable.
1717 */
1718 port_a = 0x1; /* relative port A */
1719 port_b = 0x2; /* relative port B */
1720 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001721 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001722 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001723 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001724
1725 /*
1726 * The asymmetric access state is cycled according to the host_id.
1727 */
1728 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001729 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001730 arr[n++] = host_no % 3; /* Asymm access state */
1731 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001732 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001733 arr[n++] = 0x0; /* Active/Optimized path */
1734 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001735 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001736 put_unaligned_be16(port_group_a, arr + n);
1737 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001738 arr[n++] = 0; /* Reserved */
1739 arr[n++] = 0; /* Status code */
1740 arr[n++] = 0; /* Vendor unique */
1741 arr[n++] = 0x1; /* One port per group */
1742 arr[n++] = 0; /* Reserved */
1743 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001744 put_unaligned_be16(port_a, arr + n);
1745 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001746 arr[n++] = 3; /* Port unavailable */
1747 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001748 put_unaligned_be16(port_group_b, arr + n);
1749 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001750 arr[n++] = 0; /* Reserved */
1751 arr[n++] = 0; /* Status code */
1752 arr[n++] = 0; /* Vendor unique */
1753 arr[n++] = 0x1; /* One port per group */
1754 arr[n++] = 0; /* Reserved */
1755 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001756 put_unaligned_be16(port_b, arr + n);
1757 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001758
1759 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001760 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001761
1762 /*
1763 * Return the smallest value of either
1764 * - The allocated length
1765 * - The constructed command length
1766 * - The maximum array size
1767 */
1768 rlen = min(alen,n);
1769 ret = fill_from_dev_buffer(scp, arr,
1770 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1771 kfree(arr);
1772 return ret;
1773}
1774
Douglas Gilbertfd321192016-04-25 12:16:33 -04001775static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1776 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001777{
1778 bool rctd;
1779 u8 reporting_opts, req_opcode, sdeb_i, supp;
1780 u16 req_sa, u;
1781 u32 alloc_len, a_len;
1782 int k, offset, len, errsts, count, bump, na;
1783 const struct opcode_info_t *oip;
1784 const struct opcode_info_t *r_oip;
1785 u8 *arr;
1786 u8 *cmd = scp->cmnd;
1787
1788 rctd = !!(cmd[2] & 0x80);
1789 reporting_opts = cmd[2] & 0x7;
1790 req_opcode = cmd[3];
1791 req_sa = get_unaligned_be16(cmd + 4);
1792 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001793 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001794 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1795 return check_condition_result;
1796 }
1797 if (alloc_len > 8192)
1798 a_len = 8192;
1799 else
1800 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001801 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001802 if (NULL == arr) {
1803 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1804 INSUFF_RES_ASCQ);
1805 return check_condition_result;
1806 }
1807 switch (reporting_opts) {
1808 case 0: /* all commands */
1809 /* count number of commands */
1810 for (count = 0, oip = opcode_info_arr;
1811 oip->num_attached != 0xff; ++oip) {
1812 if (F_INV_OP & oip->flags)
1813 continue;
1814 count += (oip->num_attached + 1);
1815 }
1816 bump = rctd ? 20 : 8;
1817 put_unaligned_be32(count * bump, arr);
1818 for (offset = 4, oip = opcode_info_arr;
1819 oip->num_attached != 0xff && offset < a_len; ++oip) {
1820 if (F_INV_OP & oip->flags)
1821 continue;
1822 na = oip->num_attached;
1823 arr[offset] = oip->opcode;
1824 put_unaligned_be16(oip->sa, arr + offset + 2);
1825 if (rctd)
1826 arr[offset + 5] |= 0x2;
1827 if (FF_SA & oip->flags)
1828 arr[offset + 5] |= 0x1;
1829 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1830 if (rctd)
1831 put_unaligned_be16(0xa, arr + offset + 8);
1832 r_oip = oip;
1833 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1834 if (F_INV_OP & oip->flags)
1835 continue;
1836 offset += bump;
1837 arr[offset] = oip->opcode;
1838 put_unaligned_be16(oip->sa, arr + offset + 2);
1839 if (rctd)
1840 arr[offset + 5] |= 0x2;
1841 if (FF_SA & oip->flags)
1842 arr[offset + 5] |= 0x1;
1843 put_unaligned_be16(oip->len_mask[0],
1844 arr + offset + 6);
1845 if (rctd)
1846 put_unaligned_be16(0xa,
1847 arr + offset + 8);
1848 }
1849 oip = r_oip;
1850 offset += bump;
1851 }
1852 break;
1853 case 1: /* one command: opcode only */
1854 case 2: /* one command: opcode plus service action */
1855 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1856 sdeb_i = opcode_ind_arr[req_opcode];
1857 oip = &opcode_info_arr[sdeb_i];
1858 if (F_INV_OP & oip->flags) {
1859 supp = 1;
1860 offset = 4;
1861 } else {
1862 if (1 == reporting_opts) {
1863 if (FF_SA & oip->flags) {
1864 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1865 2, 2);
1866 kfree(arr);
1867 return check_condition_result;
1868 }
1869 req_sa = 0;
1870 } else if (2 == reporting_opts &&
1871 0 == (FF_SA & oip->flags)) {
1872 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1873 kfree(arr); /* point at requested sa */
1874 return check_condition_result;
1875 }
1876 if (0 == (FF_SA & oip->flags) &&
1877 req_opcode == oip->opcode)
1878 supp = 3;
1879 else if (0 == (FF_SA & oip->flags)) {
1880 na = oip->num_attached;
1881 for (k = 0, oip = oip->arrp; k < na;
1882 ++k, ++oip) {
1883 if (req_opcode == oip->opcode)
1884 break;
1885 }
1886 supp = (k >= na) ? 1 : 3;
1887 } else if (req_sa != oip->sa) {
1888 na = oip->num_attached;
1889 for (k = 0, oip = oip->arrp; k < na;
1890 ++k, ++oip) {
1891 if (req_sa == oip->sa)
1892 break;
1893 }
1894 supp = (k >= na) ? 1 : 3;
1895 } else
1896 supp = 3;
1897 if (3 == supp) {
1898 u = oip->len_mask[0];
1899 put_unaligned_be16(u, arr + 2);
1900 arr[4] = oip->opcode;
1901 for (k = 1; k < u; ++k)
1902 arr[4 + k] = (k < 16) ?
1903 oip->len_mask[k] : 0xff;
1904 offset = 4 + u;
1905 } else
1906 offset = 4;
1907 }
1908 arr[1] = (rctd ? 0x80 : 0) | supp;
1909 if (rctd) {
1910 put_unaligned_be16(0xa, arr + offset);
1911 offset += 12;
1912 }
1913 break;
1914 default:
1915 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1916 kfree(arr);
1917 return check_condition_result;
1918 }
1919 offset = (offset < a_len) ? offset : a_len;
1920 len = (offset < alloc_len) ? offset : alloc_len;
1921 errsts = fill_from_dev_buffer(scp, arr, len);
1922 kfree(arr);
1923 return errsts;
1924}
1925
Douglas Gilbertfd321192016-04-25 12:16:33 -04001926static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1927 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001928{
1929 bool repd;
1930 u32 alloc_len, len;
1931 u8 arr[16];
1932 u8 *cmd = scp->cmnd;
1933
1934 memset(arr, 0, sizeof(arr));
1935 repd = !!(cmd[2] & 0x80);
1936 alloc_len = get_unaligned_be32(cmd + 6);
1937 if (alloc_len < 4) {
1938 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1939 return check_condition_result;
1940 }
1941 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1942 arr[1] = 0x1; /* ITNRS */
1943 if (repd) {
1944 arr[3] = 0xc;
1945 len = 16;
1946 } else
1947 len = 4;
1948
1949 len = (len < alloc_len) ? len : alloc_len;
1950 return fill_from_dev_buffer(scp, arr, len);
1951}
1952
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953/* <<Following mode page info copied from ST318451LW>> */
1954
John Pittman91d4c752018-02-09 21:12:43 -05001955static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956{ /* Read-Write Error Recovery page for mode_sense */
1957 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1958 5, 0, 0xff, 0xff};
1959
1960 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1961 if (1 == pcontrol)
1962 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1963 return sizeof(err_recov_pg);
1964}
1965
John Pittman91d4c752018-02-09 21:12:43 -05001966static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967{ /* Disconnect-Reconnect page for mode_sense */
1968 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1969 0, 0, 0, 0, 0, 0, 0, 0};
1970
1971 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1972 if (1 == pcontrol)
1973 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1974 return sizeof(disconnect_pg);
1975}
1976
John Pittman91d4c752018-02-09 21:12:43 -05001977static int resp_format_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001979 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1980 0, 0, 0, 0, 0, 0, 0, 0,
1981 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982
Martin K. Petersen597136a2008-06-05 00:12:59 -04001983 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001984 put_unaligned_be16(sdebug_sectors_per, p + 10);
1985 put_unaligned_be16(sdebug_sector_size, p + 12);
1986 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001987 p[20] |= 0x20; /* should agree with INQUIRY */
1988 if (1 == pcontrol)
1989 memset(p + 2, 0, sizeof(format_pg) - 2);
1990 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991}
1992
Douglas Gilbertfd321192016-04-25 12:16:33 -04001993static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1994 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1995 0, 0, 0, 0};
1996
John Pittman91d4c752018-02-09 21:12:43 -05001997static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001999 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
2000 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2001 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
2003
Douglas Gilbert773642d2016-04-25 12:16:28 -04002004 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002005 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 memcpy(p, caching_pg, sizeof(caching_pg));
2007 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002008 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2009 else if (2 == pcontrol)
2010 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 return sizeof(caching_pg);
2012}
2013
Douglas Gilbertfd321192016-04-25 12:16:33 -04002014static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2015 0, 0, 0x2, 0x4b};
2016
John Pittman91d4c752018-02-09 21:12:43 -05002017static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002019 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05002020 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002021 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 0, 0, 0x2, 0x4b};
2023
Douglas Gilbert773642d2016-04-25 12:16:28 -04002024 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002026 else
2027 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002028
Douglas Gilbert773642d2016-04-25 12:16:28 -04002029 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002030 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2031
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2033 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002034 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2035 else if (2 == pcontrol)
2036 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 return sizeof(ctrl_m_pg);
2038}
2039
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002040
John Pittman91d4c752018-02-09 21:12:43 -05002041static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002043 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2044 0, 0, 0x0, 0x0};
2045 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2046 0, 0, 0x0, 0x0};
2047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2049 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002050 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2051 else if (2 == pcontrol)
2052 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 return sizeof(iec_m_pg);
2054}
2055
John Pittman91d4c752018-02-09 21:12:43 -05002056static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002057{ /* SAS SSP mode page - short format for mode_sense */
2058 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2059 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2060
2061 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2062 if (1 == pcontrol)
2063 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2064 return sizeof(sas_sf_m_pg);
2065}
2066
2067
John Pittman91d4c752018-02-09 21:12:43 -05002068static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002069 int target_dev_id)
2070{ /* SAS phy control and discover mode page for mode_sense */
2071 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2072 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002073 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2074 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002075 0x2, 0, 0, 0, 0, 0, 0, 0,
2076 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2077 0, 0, 0, 0, 0, 0, 0, 0,
2078 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002079 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2080 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002081 0x3, 0, 0, 0, 0, 0, 0, 0,
2082 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2083 0, 0, 0, 0, 0, 0, 0, 0,
2084 };
2085 int port_a, port_b;
2086
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002087 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2088 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2089 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2090 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002091 port_a = target_dev_id + 1;
2092 port_b = port_a + 1;
2093 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002094 put_unaligned_be32(port_a, p + 20);
2095 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002096 if (1 == pcontrol)
2097 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2098 return sizeof(sas_pcd_m_pg);
2099}
2100
John Pittman91d4c752018-02-09 21:12:43 -05002101static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002102{ /* SAS SSP shared protocol specific port mode subpage */
2103 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2104 0, 0, 0, 0, 0, 0, 0, 0,
2105 };
2106
2107 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2108 if (1 == pcontrol)
2109 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2110 return sizeof(sas_sha_m_pg);
2111}
2112
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113#define SDEBUG_MAX_MSENSE_SZ 256
2114
Douglas Gilbertfd321192016-04-25 12:16:33 -04002115static int resp_mode_sense(struct scsi_cmnd *scp,
2116 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117{
Douglas Gilbert23183912006-09-16 20:30:47 -04002118 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002120 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002121 int target = scp->device->id;
John Pittman91d4c752018-02-09 21:12:43 -05002122 unsigned char *ap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002124 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002125 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002127 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 pcontrol = (cmd[2] & 0xc0) >> 6;
2129 pcode = cmd[2] & 0x3f;
2130 subpcode = cmd[3];
2131 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002132 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2133 is_disk = (sdebug_ptype == TYPE_DISK);
2134 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002135 bd_len = llbaa ? 16 : 8;
2136 else
2137 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002138 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2140 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002141 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142 return check_condition_result;
2143 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002144 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2145 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002146 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002147 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002148 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002149 else
2150 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 if (msense_6) {
2152 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002153 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 offset = 4;
2155 } else {
2156 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002157 if (16 == bd_len)
2158 arr[4] = 0x1; /* set LONGLBA bit */
2159 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 offset = 8;
2161 }
2162 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002163 if ((bd_len > 0) && (!sdebug_capacity))
2164 sdebug_capacity = get_sdebug_capacity();
2165
Douglas Gilbert23183912006-09-16 20:30:47 -04002166 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002167 if (sdebug_capacity > 0xfffffffe)
2168 put_unaligned_be32(0xffffffff, ap + 0);
2169 else
2170 put_unaligned_be32(sdebug_capacity, ap + 0);
2171 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002172 offset += bd_len;
2173 ap = arr + offset;
2174 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002175 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2176 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002177 offset += bd_len;
2178 ap = arr + offset;
2179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002181 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2182 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002183 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 return check_condition_result;
2185 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002186 bad_pcode = false;
2187
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 switch (pcode) {
2189 case 0x1: /* Read-Write error recovery page, direct access */
2190 len = resp_err_recov_pg(ap, pcontrol, target);
2191 offset += len;
2192 break;
2193 case 0x2: /* Disconnect-Reconnect page, all devices */
2194 len = resp_disconnect_pg(ap, pcontrol, target);
2195 offset += len;
2196 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002197 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002198 if (is_disk) {
2199 len = resp_format_pg(ap, pcontrol, target);
2200 offset += len;
2201 } else
2202 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002203 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002205 if (is_disk) {
2206 len = resp_caching_pg(ap, pcontrol, target);
2207 offset += len;
2208 } else
2209 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 break;
2211 case 0xa: /* Control Mode page, all devices */
2212 len = resp_ctrl_m_pg(ap, pcontrol, target);
2213 offset += len;
2214 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002215 case 0x19: /* if spc==1 then sas phy, control+discover */
2216 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002217 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002218 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002219 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002220 len = 0;
2221 if ((0x0 == subpcode) || (0xff == subpcode))
2222 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2223 if ((0x1 == subpcode) || (0xff == subpcode))
2224 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2225 target_dev_id);
2226 if ((0x2 == subpcode) || (0xff == subpcode))
2227 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2228 offset += len;
2229 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 case 0x1c: /* Informational Exceptions Mode page, all devices */
2231 len = resp_iec_m_pg(ap, pcontrol, target);
2232 offset += len;
2233 break;
2234 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002235 if ((0 == subpcode) || (0xff == subpcode)) {
2236 len = resp_err_recov_pg(ap, pcontrol, target);
2237 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002238 if (is_disk) {
2239 len += resp_format_pg(ap + len, pcontrol,
2240 target);
2241 len += resp_caching_pg(ap + len, pcontrol,
2242 target);
2243 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002244 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2245 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2246 if (0xff == subpcode) {
2247 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2248 target, target_dev_id);
2249 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2250 }
2251 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002252 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002253 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002254 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002255 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 break;
2258 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002259 bad_pcode = true;
2260 break;
2261 }
2262 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002263 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 return check_condition_result;
2265 }
2266 if (msense_6)
2267 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002268 else
2269 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2271}
2272
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002273#define SDEBUG_MAX_MSELECT_SZ 512
2274
Douglas Gilbertfd321192016-04-25 12:16:33 -04002275static int resp_mode_select(struct scsi_cmnd *scp,
2276 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002277{
2278 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002279 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002280 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002281 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002282 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002283
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002284 memset(arr, 0, sizeof(arr));
2285 pf = cmd[1] & 0x10;
2286 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002287 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002288 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002289 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002290 return check_condition_result;
2291 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002292 res = fetch_to_dev_buffer(scp, arr, param_len);
2293 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002294 return DID_ERROR << 16;
2295 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002296 sdev_printk(KERN_INFO, scp->device,
2297 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2298 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002299 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2300 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002301 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002302 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002303 return check_condition_result;
2304 }
2305 off = bd_len + (mselect6 ? 4 : 8);
2306 mpage = arr[off] & 0x3f;
2307 ps = !!(arr[off] & 0x80);
2308 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002309 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002310 return check_condition_result;
2311 }
2312 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002313 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002314 (arr[off + 1] + 2);
2315 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002316 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002317 PARAMETER_LIST_LENGTH_ERR, 0);
2318 return check_condition_result;
2319 }
2320 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002321 case 0x8: /* Caching Mode page */
2322 if (caching_pg[1] == arr[off + 1]) {
2323 memcpy(caching_pg + 2, arr + off + 2,
2324 sizeof(caching_pg) - 2);
2325 goto set_mode_changed_ua;
2326 }
2327 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002328 case 0xa: /* Control Mode page */
2329 if (ctrl_m_pg[1] == arr[off + 1]) {
2330 memcpy(ctrl_m_pg + 2, arr + off + 2,
2331 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002332 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002333 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002334 }
2335 break;
2336 case 0x1c: /* Informational Exceptions Mode page */
2337 if (iec_m_pg[1] == arr[off + 1]) {
2338 memcpy(iec_m_pg + 2, arr + off + 2,
2339 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002340 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002341 }
2342 break;
2343 default:
2344 break;
2345 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002346 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002347 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002348set_mode_changed_ua:
2349 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2350 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002351}
2352
John Pittman91d4c752018-02-09 21:12:43 -05002353static int resp_temp_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002354{
2355 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2356 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2357 };
2358
Douglas Gilbert9a051012017-12-23 12:48:10 -05002359 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2360 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002361}
2362
John Pittman91d4c752018-02-09 21:12:43 -05002363static int resp_ie_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002364{
2365 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2366 };
2367
Douglas Gilbert9a051012017-12-23 12:48:10 -05002368 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002369 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2370 arr[4] = THRESHOLD_EXCEEDED;
2371 arr[5] = 0xff;
2372 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002373 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002374}
2375
2376#define SDEBUG_MAX_LSENSE_SZ 512
2377
Douglas Gilbert9a051012017-12-23 12:48:10 -05002378static int resp_log_sense(struct scsi_cmnd *scp,
2379 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002380{
Bart Van Asscheab172412017-08-25 13:46:42 -07002381 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002382 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002383 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002384
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002385 memset(arr, 0, sizeof(arr));
2386 ppc = cmd[1] & 0x2;
2387 sp = cmd[1] & 0x1;
2388 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002389 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002390 return check_condition_result;
2391 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002392 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002393 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002394 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002395 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002396 if (0 == subpcode) {
2397 switch (pcode) {
2398 case 0x0: /* Supported log pages log page */
2399 n = 4;
2400 arr[n++] = 0x0; /* this page */
2401 arr[n++] = 0xd; /* Temperature */
2402 arr[n++] = 0x2f; /* Informational exceptions */
2403 arr[3] = n - 4;
2404 break;
2405 case 0xd: /* Temperature log page */
2406 arr[3] = resp_temp_l_pg(arr + 4);
2407 break;
2408 case 0x2f: /* Informational exceptions log page */
2409 arr[3] = resp_ie_l_pg(arr + 4);
2410 break;
2411 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002412 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002413 return check_condition_result;
2414 }
2415 } else if (0xff == subpcode) {
2416 arr[0] |= 0x40;
2417 arr[1] = subpcode;
2418 switch (pcode) {
2419 case 0x0: /* Supported log pages and subpages log page */
2420 n = 4;
2421 arr[n++] = 0x0;
2422 arr[n++] = 0x0; /* 0,0 page */
2423 arr[n++] = 0x0;
2424 arr[n++] = 0xff; /* this page */
2425 arr[n++] = 0xd;
2426 arr[n++] = 0x0; /* Temperature */
2427 arr[n++] = 0x2f;
2428 arr[n++] = 0x0; /* Informational exceptions */
2429 arr[3] = n - 4;
2430 break;
2431 case 0xd: /* Temperature subpages */
2432 n = 4;
2433 arr[n++] = 0xd;
2434 arr[n++] = 0x0; /* Temperature */
2435 arr[3] = n - 4;
2436 break;
2437 case 0x2f: /* Informational exceptions subpages */
2438 n = 4;
2439 arr[n++] = 0x2f;
2440 arr[n++] = 0x0; /* Informational exceptions */
2441 arr[3] = n - 4;
2442 break;
2443 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002444 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002445 return check_condition_result;
2446 }
2447 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002448 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002449 return check_condition_result;
2450 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002451 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002452 return fill_from_dev_buffer(scp, arr,
2453 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2454}
2455
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002456static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002457 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002459 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002460 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 return check_condition_result;
2462 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002463 /* transfer length excessive (tie in to block limits VPD page) */
2464 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002465 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002466 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002467 return check_condition_result;
2468 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002469 return 0;
2470}
2471
Akinobu Mitaa4517512013-07-08 16:01:57 -07002472/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002473static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2474 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002475{
2476 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002477 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002478 struct scsi_data_buffer *sdb;
2479 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002480
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002481 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002482 sdb = scsi_out(scmd);
2483 dir = DMA_TO_DEVICE;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04002484 write_since_sync = true;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002485 } else {
2486 sdb = scsi_in(scmd);
2487 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002488 }
2489
2490 if (!sdb->length)
2491 return 0;
2492 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2493 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002494
2495 block = do_div(lba, sdebug_store_sectors);
2496 if (block + num > sdebug_store_sectors)
2497 rest = block + num - sdebug_store_sectors;
2498
Dave Gordon386ecb12015-06-30 14:58:57 -07002499 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002500 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002501 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002502 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002503 return ret;
2504
2505 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002506 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002507 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002508 sg_skip + ((num - rest) * sdebug_sector_size),
2509 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002510 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002511
2512 return ret;
2513}
2514
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002515/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2516 * arr into fake_store(lba,num) and return true. If comparison fails then
2517 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002518static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002519{
2520 bool res;
2521 u64 block, rest = 0;
2522 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002523 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002524
2525 block = do_div(lba, store_blks);
2526 if (block + num > store_blks)
2527 rest = block + num - store_blks;
2528
2529 res = !memcmp(fake_storep + (block * lb_size), arr,
2530 (num - rest) * lb_size);
2531 if (!res)
2532 return res;
2533 if (rest)
2534 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2535 rest * lb_size);
2536 if (!res)
2537 return res;
2538 arr += num * lb_size;
2539 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2540 if (rest)
2541 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2542 rest * lb_size);
2543 return res;
2544}
2545
Akinobu Mita51d648a2013-09-18 21:27:28 +09002546static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002547{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002548 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002549
Douglas Gilbert773642d2016-04-25 12:16:28 -04002550 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002551 csum = (__force __be16)ip_compute_csum(buf, len);
2552 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002553 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002554
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002555 return csum;
2556}
2557
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002558static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002559 sector_t sector, u32 ei_lba)
2560{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002561 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002562
2563 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002564 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002565 (unsigned long)sector,
2566 be16_to_cpu(sdt->guard_tag),
2567 be16_to_cpu(csum));
2568 return 0x01;
2569 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002570 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002571 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002572 pr_err("REF check failed on sector %lu\n",
2573 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002574 return 0x03;
2575 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002576 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002577 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002578 pr_err("REF check failed on sector %lu\n",
2579 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002580 return 0x03;
2581 }
2582 return 0;
2583}
2584
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002585static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002586 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002587{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002588 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002589 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002590 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002591 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002592
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002593 /* Bytes of protection data to copy into sgl */
2594 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002595
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002596 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2597 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2598 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2599
2600 while (sg_miter_next(&miter) && resid > 0) {
2601 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002602 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002603 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002604
2605 if (dif_store_end < start + len)
2606 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002607
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002608 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002609
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002610 if (read)
2611 memcpy(paddr, start, len - rest);
2612 else
2613 memcpy(start, paddr, len - rest);
2614
2615 if (rest) {
2616 if (read)
2617 memcpy(paddr + len - rest, dif_storep, rest);
2618 else
2619 memcpy(dif_storep, paddr + len - rest, rest);
2620 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002621
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002622 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002623 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002624 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002625 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002626}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002627
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002628static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2629 unsigned int sectors, u32 ei_lba)
2630{
2631 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002632 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002633 sector_t sector;
2634
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002635 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002636 int ret;
2637
2638 sector = start_sec + i;
2639 sdt = dif_store(sector);
2640
Akinobu Mita51d648a2013-09-18 21:27:28 +09002641 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002642 continue;
2643
2644 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2645 if (ret) {
2646 dif_errors++;
2647 return ret;
2648 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002649 }
2650
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002651 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002652 dix_reads++;
2653
2654 return 0;
2655}
2656
Douglas Gilbertfd321192016-04-25 12:16:33 -04002657static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002658{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002659 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002660 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002661 u64 lba;
2662 u32 num;
2663 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002664 unsigned long iflags;
2665 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002666 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002667
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002668 switch (cmd[0]) {
2669 case READ_16:
2670 ei_lba = 0;
2671 lba = get_unaligned_be64(cmd + 2);
2672 num = get_unaligned_be32(cmd + 10);
2673 check_prot = true;
2674 break;
2675 case READ_10:
2676 ei_lba = 0;
2677 lba = get_unaligned_be32(cmd + 2);
2678 num = get_unaligned_be16(cmd + 7);
2679 check_prot = true;
2680 break;
2681 case READ_6:
2682 ei_lba = 0;
2683 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2684 (u32)(cmd[1] & 0x1f) << 16;
2685 num = (0 == cmd[4]) ? 256 : cmd[4];
2686 check_prot = true;
2687 break;
2688 case READ_12:
2689 ei_lba = 0;
2690 lba = get_unaligned_be32(cmd + 2);
2691 num = get_unaligned_be32(cmd + 6);
2692 check_prot = true;
2693 break;
2694 case XDWRITEREAD_10:
2695 ei_lba = 0;
2696 lba = get_unaligned_be32(cmd + 2);
2697 num = get_unaligned_be16(cmd + 7);
2698 check_prot = false;
2699 break;
2700 default: /* assume READ(32) */
2701 lba = get_unaligned_be64(cmd + 12);
2702 ei_lba = get_unaligned_be32(cmd + 20);
2703 num = get_unaligned_be32(cmd + 28);
2704 check_prot = false;
2705 break;
2706 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002707 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002708 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002709 (cmd[1] & 0xe0)) {
2710 mk_sense_invalid_opcode(scp);
2711 return check_condition_result;
2712 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002713 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2714 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002715 (cmd[1] & 0xe0) == 0)
2716 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2717 "to DIF device\n");
2718 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002719 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002720 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002721
Douglas Gilbertc4837392016-05-06 00:40:26 -04002722 if (sqcp) {
2723 if (sqcp->inj_short)
2724 num /= 2;
2725 }
2726 } else
2727 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002728
2729 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002730 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002731 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2732 return check_condition_result;
2733 }
2734 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002735 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002736 /* needs work to find which cdb byte 'num' comes from */
2737 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2738 return check_condition_result;
2739 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002740
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002741 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05002742 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2743 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002744 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002745 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002746 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002747 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2748 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002749 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2750 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002751 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002752 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002753 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 return check_condition_result;
2755 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002756
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002757 read_lock_irqsave(&atomic_rw, iflags);
2758
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002759 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002760 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002761 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002762
2763 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002764 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002765 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002766 return illegal_condition_result;
2767 }
2768 }
2769
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002770 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002772 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002773 return DID_ERROR << 16;
2774
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002775 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002776
Douglas Gilbertc4837392016-05-06 00:40:26 -04002777 if (unlikely(sqcp)) {
2778 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002779 mk_sense_buffer(scp, RECOVERED_ERROR,
2780 THRESHOLD_EXCEEDED, 0);
2781 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002782 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002783 mk_sense_buffer(scp, ABORTED_COMMAND,
2784 TRANSPORT_PROBLEM, ACK_NAK_TO);
2785 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002786 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002787 /* Logical block guard check failed */
2788 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2789 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002790 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002791 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2792 return illegal_condition_result;
2793 }
2794 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002795 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796}
2797
Tomas Winkler58a86352015-07-28 16:54:23 +03002798static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002799{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002800 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002801
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002802 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002803 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002804 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002805
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002806 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002807 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002808
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002809 if (c >= 0x20 && c < 0x7e)
2810 n += scnprintf(b + n, sizeof(b) - n,
2811 " %c ", buf[i+j]);
2812 else
2813 n += scnprintf(b + n, sizeof(b) - n,
2814 "%02x ", buf[i+j]);
2815 }
2816 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002817 }
2818}
2819
2820static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002821 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002822{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002823 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002824 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002825 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002826 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002827 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002828 int dpage_offset;
2829 struct sg_mapping_iter diter;
2830 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002831
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002832 BUG_ON(scsi_sg_count(SCpnt) == 0);
2833 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2834
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002835 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2836 scsi_prot_sg_count(SCpnt),
2837 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2838 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2839 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002840
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002841 /* For each protection page */
2842 while (sg_miter_next(&piter)) {
2843 dpage_offset = 0;
2844 if (WARN_ON(!sg_miter_next(&diter))) {
2845 ret = 0x01;
2846 goto out;
2847 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002848
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002849 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002850 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002851 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002852 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002853 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002854 if (dpage_offset >= diter.length) {
2855 if (WARN_ON(!sg_miter_next(&diter))) {
2856 ret = 0x01;
2857 goto out;
2858 }
2859 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002860 }
2861
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002862 sdt = piter.addr + ppage_offset;
2863 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002864
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002865 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002866 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002867 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002868 goto out;
2869 }
2870
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002871 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002872 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002873 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002874 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002875 diter.consumed = dpage_offset;
2876 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002877 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002878 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002879
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002880 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002881 dix_writes++;
2882
2883 return 0;
2884
2885out:
2886 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002887 sg_miter_stop(&diter);
2888 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002889 return ret;
2890}
2891
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002892static unsigned long lba_to_map_index(sector_t lba)
2893{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002894 if (sdebug_unmap_alignment)
2895 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2896 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002897 return lba;
2898}
2899
2900static sector_t map_index_to_lba(unsigned long index)
2901{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002902 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002903
Douglas Gilbert773642d2016-04-25 12:16:28 -04002904 if (sdebug_unmap_alignment)
2905 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002906 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002907}
2908
Martin K. Petersen44d92692009-10-15 14:45:27 -04002909static unsigned int map_state(sector_t lba, unsigned int *num)
2910{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002911 sector_t end;
2912 unsigned int mapped;
2913 unsigned long index;
2914 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002915
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002916 index = lba_to_map_index(lba);
2917 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002918
2919 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002920 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002921 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002922 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002923
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002924 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002925 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002926 return mapped;
2927}
2928
2929static void map_region(sector_t lba, unsigned int len)
2930{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002931 sector_t end = lba + len;
2932
Martin K. Petersen44d92692009-10-15 14:45:27 -04002933 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002934 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002935
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002936 if (index < map_size)
2937 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002938
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002939 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002940 }
2941}
2942
2943static void unmap_region(sector_t lba, unsigned int len)
2944{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002945 sector_t end = lba + len;
2946
Martin K. Petersen44d92692009-10-15 14:45:27 -04002947 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002948 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002949
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002950 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002951 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002952 index < map_size) {
2953 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002954 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002955 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002956 lba * sdebug_sector_size,
2957 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002958 sdebug_sector_size *
2959 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002960 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002961 if (dif_storep) {
2962 memset(dif_storep + lba, 0xff,
2963 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002964 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002965 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002966 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002967 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002968 }
2969}
2970
Douglas Gilbertfd321192016-04-25 12:16:33 -04002971static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002973 u8 *cmd = scp->cmnd;
2974 u64 lba;
2975 u32 num;
2976 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002978 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002979 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002981 switch (cmd[0]) {
2982 case WRITE_16:
2983 ei_lba = 0;
2984 lba = get_unaligned_be64(cmd + 2);
2985 num = get_unaligned_be32(cmd + 10);
2986 check_prot = true;
2987 break;
2988 case WRITE_10:
2989 ei_lba = 0;
2990 lba = get_unaligned_be32(cmd + 2);
2991 num = get_unaligned_be16(cmd + 7);
2992 check_prot = true;
2993 break;
2994 case WRITE_6:
2995 ei_lba = 0;
2996 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2997 (u32)(cmd[1] & 0x1f) << 16;
2998 num = (0 == cmd[4]) ? 256 : cmd[4];
2999 check_prot = true;
3000 break;
3001 case WRITE_12:
3002 ei_lba = 0;
3003 lba = get_unaligned_be32(cmd + 2);
3004 num = get_unaligned_be32(cmd + 6);
3005 check_prot = true;
3006 break;
3007 case 0x53: /* XDWRITEREAD(10) */
3008 ei_lba = 0;
3009 lba = get_unaligned_be32(cmd + 2);
3010 num = get_unaligned_be16(cmd + 7);
3011 check_prot = false;
3012 break;
3013 default: /* assume WRITE(32) */
3014 lba = get_unaligned_be64(cmd + 12);
3015 ei_lba = get_unaligned_be32(cmd + 20);
3016 num = get_unaligned_be32(cmd + 28);
3017 check_prot = false;
3018 break;
3019 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003020 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003021 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003022 (cmd[1] & 0xe0)) {
3023 mk_sense_invalid_opcode(scp);
3024 return check_condition_result;
3025 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003026 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3027 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003028 (cmd[1] & 0xe0) == 0)
3029 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3030 "to DIF device\n");
3031 }
3032
3033 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003034 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003035 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3036 return check_condition_result;
3037 }
3038 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003039 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003040 /* needs work to find which cdb byte 'num' comes from */
3041 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3042 return check_condition_result;
3043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003045 write_lock_irqsave(&atomic_rw, iflags);
3046
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003047 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003048 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003049 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003050
3051 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003052 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003053 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003054 return illegal_condition_result;
3055 }
3056 }
3057
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003058 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003059 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003060 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003062 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003063 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003064 else if (unlikely(sdebug_verbose &&
3065 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003066 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003067 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003068 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003069
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003070 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003071 struct sdebug_queued_cmd *sqcp =
3072 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003073
Douglas Gilbertc4837392016-05-06 00:40:26 -04003074 if (sqcp) {
3075 if (sqcp->inj_recovered) {
3076 mk_sense_buffer(scp, RECOVERED_ERROR,
3077 THRESHOLD_EXCEEDED, 0);
3078 return check_condition_result;
3079 } else if (sqcp->inj_dif) {
3080 /* Logical block guard check failed */
3081 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3082 return illegal_condition_result;
3083 } else if (sqcp->inj_dix) {
3084 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3085 return illegal_condition_result;
3086 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003087 }
3088 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 return 0;
3090}
3091
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003092/*
3093 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3094 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3095 */
3096static int resp_write_scat(struct scsi_cmnd *scp,
3097 struct sdebug_dev_info *devip)
3098{
3099 u8 *cmd = scp->cmnd;
3100 u8 *lrdp = NULL;
3101 u8 *up;
3102 u8 wrprotect;
3103 u16 lbdof, num_lrd, k;
3104 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3105 u32 lb_size = sdebug_sector_size;
3106 u32 ei_lba;
3107 u64 lba;
3108 unsigned long iflags;
3109 int ret, res;
3110 bool is_16;
3111 static const u32 lrd_size = 32; /* + parameter list header size */
3112
3113 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3114 is_16 = false;
3115 wrprotect = (cmd[10] >> 5) & 0x7;
3116 lbdof = get_unaligned_be16(cmd + 12);
3117 num_lrd = get_unaligned_be16(cmd + 16);
3118 bt_len = get_unaligned_be32(cmd + 28);
3119 } else { /* that leaves WRITE SCATTERED(16) */
3120 is_16 = true;
3121 wrprotect = (cmd[2] >> 5) & 0x7;
3122 lbdof = get_unaligned_be16(cmd + 4);
3123 num_lrd = get_unaligned_be16(cmd + 8);
3124 bt_len = get_unaligned_be32(cmd + 10);
3125 if (unlikely(have_dif_prot)) {
3126 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3127 wrprotect) {
3128 mk_sense_invalid_opcode(scp);
3129 return illegal_condition_result;
3130 }
3131 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3132 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3133 wrprotect == 0)
3134 sdev_printk(KERN_ERR, scp->device,
3135 "Unprotected WR to DIF device\n");
3136 }
3137 }
3138 if ((num_lrd == 0) || (bt_len == 0))
3139 return 0; /* T10 says these do-nothings are not errors */
3140 if (lbdof == 0) {
3141 if (sdebug_verbose)
3142 sdev_printk(KERN_INFO, scp->device,
3143 "%s: %s: LB Data Offset field bad\n",
3144 my_name, __func__);
3145 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3146 return illegal_condition_result;
3147 }
3148 lbdof_blen = lbdof * lb_size;
3149 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3150 if (sdebug_verbose)
3151 sdev_printk(KERN_INFO, scp->device,
3152 "%s: %s: LBA range descriptors don't fit\n",
3153 my_name, __func__);
3154 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3155 return illegal_condition_result;
3156 }
3157 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3158 if (lrdp == NULL)
3159 return SCSI_MLQUEUE_HOST_BUSY;
3160 if (sdebug_verbose)
3161 sdev_printk(KERN_INFO, scp->device,
3162 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3163 my_name, __func__, lbdof_blen);
3164 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3165 if (res == -1) {
3166 ret = DID_ERROR << 16;
3167 goto err_out;
3168 }
3169
3170 write_lock_irqsave(&atomic_rw, iflags);
3171 sg_off = lbdof_blen;
3172 /* Spec says Buffer xfer Length field in number of LBs in dout */
3173 cum_lb = 0;
3174 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3175 lba = get_unaligned_be64(up + 0);
3176 num = get_unaligned_be32(up + 8);
3177 if (sdebug_verbose)
3178 sdev_printk(KERN_INFO, scp->device,
3179 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3180 my_name, __func__, k, lba, num, sg_off);
3181 if (num == 0)
3182 continue;
3183 ret = check_device_access_params(scp, lba, num);
3184 if (ret)
3185 goto err_out_unlock;
3186 num_by = num * lb_size;
3187 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3188
3189 if ((cum_lb + num) > bt_len) {
3190 if (sdebug_verbose)
3191 sdev_printk(KERN_INFO, scp->device,
3192 "%s: %s: sum of blocks > data provided\n",
3193 my_name, __func__);
3194 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3195 0);
3196 ret = illegal_condition_result;
3197 goto err_out_unlock;
3198 }
3199
3200 /* DIX + T10 DIF */
3201 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3202 int prot_ret = prot_verify_write(scp, lba, num,
3203 ei_lba);
3204
3205 if (prot_ret) {
3206 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3207 prot_ret);
3208 ret = illegal_condition_result;
3209 goto err_out_unlock;
3210 }
3211 }
3212
3213 ret = do_device_access(scp, sg_off, lba, num, true);
3214 if (unlikely(scsi_debug_lbp()))
3215 map_region(lba, num);
3216 if (unlikely(-1 == ret)) {
3217 ret = DID_ERROR << 16;
3218 goto err_out_unlock;
3219 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3220 sdev_printk(KERN_INFO, scp->device,
3221 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3222 my_name, num_by, ret);
3223
3224 if (unlikely(sdebug_any_injecting_opt)) {
3225 struct sdebug_queued_cmd *sqcp =
3226 (struct sdebug_queued_cmd *)scp->host_scribble;
3227
3228 if (sqcp) {
3229 if (sqcp->inj_recovered) {
3230 mk_sense_buffer(scp, RECOVERED_ERROR,
3231 THRESHOLD_EXCEEDED, 0);
3232 ret = illegal_condition_result;
3233 goto err_out_unlock;
3234 } else if (sqcp->inj_dif) {
3235 /* Logical block guard check failed */
3236 mk_sense_buffer(scp, ABORTED_COMMAND,
3237 0x10, 1);
3238 ret = illegal_condition_result;
3239 goto err_out_unlock;
3240 } else if (sqcp->inj_dix) {
3241 mk_sense_buffer(scp, ILLEGAL_REQUEST,
3242 0x10, 1);
3243 ret = illegal_condition_result;
3244 goto err_out_unlock;
3245 }
3246 }
3247 }
3248 sg_off += num_by;
3249 cum_lb += num;
3250 }
3251 ret = 0;
3252err_out_unlock:
3253 write_unlock_irqrestore(&atomic_rw, iflags);
3254err_out:
3255 kfree(lrdp);
3256 return ret;
3257}
3258
Douglas Gilbertfd321192016-04-25 12:16:33 -04003259static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3260 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003261{
3262 unsigned long iflags;
3263 unsigned long long i;
3264 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003265 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003266
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003267 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003268 if (ret)
3269 return ret;
3270
3271 write_lock_irqsave(&atomic_rw, iflags);
3272
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003273 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003274 unmap_region(lba, num);
3275 goto out;
3276 }
3277
Douglas Gilbert773642d2016-04-25 12:16:28 -04003278 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003279 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3280 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003281 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003282 ret = 0;
3283 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003284 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3285 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003286
3287 if (-1 == ret) {
3288 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003289 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003290 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003291 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003292 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003293 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003294 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003295
3296 /* Copy first sector to remaining blocks */
3297 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003298 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3299 fake_storep + lba_off,
3300 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003301
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003302 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003303 map_region(lba, num);
3304out:
3305 write_unlock_irqrestore(&atomic_rw, iflags);
3306
3307 return 0;
3308}
3309
Douglas Gilbertfd321192016-04-25 12:16:33 -04003310static int resp_write_same_10(struct scsi_cmnd *scp,
3311 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003312{
3313 u8 *cmd = scp->cmnd;
3314 u32 lba;
3315 u16 num;
3316 u32 ei_lba = 0;
3317 bool unmap = false;
3318
3319 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003320 if (sdebug_lbpws10 == 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 lba = get_unaligned_be32(cmd + 2);
3327 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003328 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003329 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3330 return check_condition_result;
3331 }
3332 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3333}
3334
Douglas Gilbertfd321192016-04-25 12:16:33 -04003335static int resp_write_same_16(struct scsi_cmnd *scp,
3336 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003337{
3338 u8 *cmd = scp->cmnd;
3339 u64 lba;
3340 u32 num;
3341 u32 ei_lba = 0;
3342 bool unmap = false;
3343 bool ndob = false;
3344
3345 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003346 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003347 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3348 return check_condition_result;
3349 } else
3350 unmap = true;
3351 }
3352 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3353 ndob = true;
3354 lba = get_unaligned_be64(cmd + 2);
3355 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003356 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003357 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3358 return check_condition_result;
3359 }
3360 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3361}
3362
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003363/* Note the mode field is in the same position as the (lower) service action
3364 * field. For the Report supported operation codes command, SPC-4 suggests
3365 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003366static int resp_write_buffer(struct scsi_cmnd *scp,
3367 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003368{
3369 u8 *cmd = scp->cmnd;
3370 struct scsi_device *sdp = scp->device;
3371 struct sdebug_dev_info *dp;
3372 u8 mode;
3373
3374 mode = cmd[1] & 0x1f;
3375 switch (mode) {
3376 case 0x4: /* download microcode (MC) and activate (ACT) */
3377 /* set UAs on this device only */
3378 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3379 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3380 break;
3381 case 0x5: /* download MC, save and ACT */
3382 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3383 break;
3384 case 0x6: /* download MC with offsets and ACT */
3385 /* set UAs on most devices (LUs) in this target */
3386 list_for_each_entry(dp,
3387 &devip->sdbg_host->dev_info_list,
3388 dev_list)
3389 if (dp->target == sdp->id) {
3390 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3391 if (devip != dp)
3392 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3393 dp->uas_bm);
3394 }
3395 break;
3396 case 0x7: /* download MC with offsets, save, and ACT */
3397 /* set UA on all devices (LUs) in this target */
3398 list_for_each_entry(dp,
3399 &devip->sdbg_host->dev_info_list,
3400 dev_list)
3401 if (dp->target == sdp->id)
3402 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3403 dp->uas_bm);
3404 break;
3405 default:
3406 /* do nothing for this command for other mode values */
3407 break;
3408 }
3409 return 0;
3410}
3411
Douglas Gilbertfd321192016-04-25 12:16:33 -04003412static int resp_comp_write(struct scsi_cmnd *scp,
3413 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003414{
3415 u8 *cmd = scp->cmnd;
3416 u8 *arr;
3417 u8 *fake_storep_hold;
3418 u64 lba;
3419 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003420 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003421 u8 num;
3422 unsigned long iflags;
3423 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003424 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003425
Douglas Gilbertd467d312014-11-26 12:33:48 -05003426 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003427 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3428 if (0 == num)
3429 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003430 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003431 (cmd[1] & 0xe0)) {
3432 mk_sense_invalid_opcode(scp);
3433 return check_condition_result;
3434 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003435 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3436 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003437 (cmd[1] & 0xe0) == 0)
3438 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3439 "to DIF device\n");
3440
3441 /* inline check_device_access_params() */
3442 if (lba + num > sdebug_capacity) {
3443 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3444 return check_condition_result;
3445 }
3446 /* transfer length excessive (tie in to block limits VPD page) */
3447 if (num > sdebug_store_sectors) {
3448 /* needs work to find which cdb byte 'num' comes from */
3449 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3450 return check_condition_result;
3451 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003452 dnum = 2 * num;
Kees Cook6396bb22018-06-12 14:03:40 -07003453 arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003454 if (NULL == arr) {
3455 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3456 INSUFF_RES_ASCQ);
3457 return check_condition_result;
3458 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003459
3460 write_lock_irqsave(&atomic_rw, iflags);
3461
3462 /* trick do_device_access() to fetch both compare and write buffers
3463 * from data-in into arr. Safe (atomic) since write_lock held. */
3464 fake_storep_hold = fake_storep;
3465 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003466 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003467 fake_storep = fake_storep_hold;
3468 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003469 retval = DID_ERROR << 16;
3470 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003471 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003472 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3473 "indicated=%u, IO sent=%d bytes\n", my_name,
3474 dnum * lb_size, ret);
3475 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003476 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003477 retval = check_condition_result;
3478 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003479 }
3480 if (scsi_debug_lbp())
3481 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003482cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003483 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003484 kfree(arr);
3485 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003486}
3487
Martin K. Petersen44d92692009-10-15 14:45:27 -04003488struct unmap_block_desc {
3489 __be64 lba;
3490 __be32 blocks;
3491 __be32 __reserved;
3492};
3493
Douglas Gilbertfd321192016-04-25 12:16:33 -04003494static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003495{
3496 unsigned char *buf;
3497 struct unmap_block_desc *desc;
3498 unsigned int i, payload_len, descriptors;
3499 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003500 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003501
Martin K. Petersen44d92692009-10-15 14:45:27 -04003502
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003503 if (!scsi_debug_lbp())
3504 return 0; /* fib and say its done */
3505 payload_len = get_unaligned_be16(scp->cmnd + 7);
3506 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003507
3508 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003509 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003510 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003511 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003512 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003513
Douglas Gilbertb333a812016-04-25 12:16:30 -04003514 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003515 if (!buf) {
3516 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3517 INSUFF_RES_ASCQ);
3518 return check_condition_result;
3519 }
3520
3521 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003522
3523 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3524 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3525
3526 desc = (void *)&buf[8];
3527
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003528 write_lock_irqsave(&atomic_rw, iflags);
3529
Martin K. Petersen44d92692009-10-15 14:45:27 -04003530 for (i = 0 ; i < descriptors ; i++) {
3531 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3532 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3533
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003534 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003535 if (ret)
3536 goto out;
3537
3538 unmap_region(lba, num);
3539 }
3540
3541 ret = 0;
3542
3543out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003544 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003545 kfree(buf);
3546
3547 return ret;
3548}
3549
3550#define SDEBUG_GET_LBA_STATUS_LEN 32
3551
Douglas Gilbertfd321192016-04-25 12:16:33 -04003552static int resp_get_lba_status(struct scsi_cmnd *scp,
3553 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003554{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003555 u8 *cmd = scp->cmnd;
3556 u64 lba;
3557 u32 alloc_len, mapped, num;
3558 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003559 int ret;
3560
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003561 lba = get_unaligned_be64(cmd + 2);
3562 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003563
3564 if (alloc_len < 24)
3565 return 0;
3566
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003567 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003568 if (ret)
3569 return ret;
3570
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003571 if (scsi_debug_lbp())
3572 mapped = map_state(lba, &num);
3573 else {
3574 mapped = 1;
3575 /* following just in case virtual_gb changed */
3576 sdebug_capacity = get_sdebug_capacity();
3577 if (sdebug_capacity - lba <= 0xffffffff)
3578 num = sdebug_capacity - lba;
3579 else
3580 num = 0xffffffff;
3581 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003582
3583 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003584 put_unaligned_be32(20, arr); /* Parameter Data Length */
3585 put_unaligned_be64(lba, arr + 8); /* LBA */
3586 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3587 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003588
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003589 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003590}
3591
Douglas Gilbert80c49562018-02-09 21:36:39 -05003592static int resp_sync_cache(struct scsi_cmnd *scp,
3593 struct sdebug_dev_info *devip)
3594{
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04003595 int res = 0;
Douglas Gilbert80c49562018-02-09 21:36:39 -05003596 u64 lba;
3597 u32 num_blocks;
3598 u8 *cmd = scp->cmnd;
3599
3600 if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
3601 lba = get_unaligned_be32(cmd + 2);
3602 num_blocks = get_unaligned_be16(cmd + 7);
3603 } else { /* SYNCHRONIZE_CACHE(16) */
3604 lba = get_unaligned_be64(cmd + 2);
3605 num_blocks = get_unaligned_be32(cmd + 10);
3606 }
3607 if (lba + num_blocks > sdebug_capacity) {
3608 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3609 return check_condition_result;
3610 }
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04003611 if (!write_since_sync || cmd[1] & 0x2)
3612 res = SDEG_RES_IMMED_MASK;
3613 else /* delay if write_since_sync and IMMED clear */
3614 write_since_sync = false;
3615 return res;
Douglas Gilbert80c49562018-02-09 21:36:39 -05003616}
3617
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003618#define RL_BUCKET_ELEMS 8
3619
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003620/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3621 * (W-LUN), the normal Linux scanning logic does not associate it with a
3622 * device (e.g. /dev/sg7). The following magic will make that association:
3623 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3624 * where <n> is a host number. If there are multiple targets in a host then
3625 * the above will associate a W-LUN to each target. To only get a W-LUN
3626 * for target 2, then use "echo '- 2 49409' > scan" .
3627 */
3628static int resp_report_luns(struct scsi_cmnd *scp,
3629 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003631 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003632 unsigned int alloc_len;
3633 unsigned char select_report;
3634 u64 lun;
3635 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003636 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003637 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3638 unsigned int wlun_cnt; /* report luns W-LUN count */
3639 unsigned int tlun_cnt; /* total LUN count */
3640 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003641 int k, j, n, res;
3642 unsigned int off_rsp = 0;
3643 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003645 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003646
3647 select_report = cmd[2];
3648 alloc_len = get_unaligned_be32(cmd + 6);
3649
3650 if (alloc_len < 4) {
3651 pr_err("alloc len too small %d\n", alloc_len);
3652 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 return check_condition_result;
3654 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003655
3656 switch (select_report) {
3657 case 0: /* all LUNs apart from W-LUNs */
3658 lun_cnt = sdebug_max_luns;
3659 wlun_cnt = 0;
3660 break;
3661 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003662 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003663 wlun_cnt = 1;
3664 break;
3665 case 2: /* all LUNs */
3666 lun_cnt = sdebug_max_luns;
3667 wlun_cnt = 1;
3668 break;
3669 case 0x10: /* only administrative LUs */
3670 case 0x11: /* see SPC-5 */
3671 case 0x12: /* only subsiduary LUs owned by referenced LU */
3672 default:
3673 pr_debug("select report invalid %d\n", select_report);
3674 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3675 return check_condition_result;
3676 }
3677
3678 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003679 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003680
3681 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003682 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3683 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003684 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3685 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3686
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003687 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003688 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003689 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3690 memset(arr, 0, sizeof(arr));
3691 lun_p = (struct scsi_lun *)&arr[0];
3692 if (k == 0) {
3693 put_unaligned_be32(rlen, &arr[0]);
3694 ++lun_p;
3695 j = 1;
3696 }
3697 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3698 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3699 break;
3700 int_to_scsilun(lun++, lun_p);
3701 }
3702 if (j < RL_BUCKET_ELEMS)
3703 break;
3704 n = j * sz_lun;
3705 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3706 if (res)
3707 return res;
3708 off_rsp += n;
3709 }
3710 if (wlun_cnt) {
3711 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3712 ++j;
3713 }
3714 if (j > 0)
3715 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003716 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717}
3718
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003719static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3720 unsigned int num, struct sdebug_dev_info *devip)
3721{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003722 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003723 unsigned char *kaddr, *buf;
3724 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003725 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003726 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003727
3728 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003729 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003730 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003731 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3732 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003733 return check_condition_result;
3734 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003735
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003736 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003737
3738 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003739 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3740 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003741
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003742 while (sg_miter_next(&miter)) {
3743 kaddr = miter.addr;
3744 for (j = 0; j < miter.length; j++)
3745 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003746
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003747 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003748 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003749 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003750 kfree(buf);
3751
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003752 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003753}
3754
Douglas Gilbertfd321192016-04-25 12:16:33 -04003755static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3756 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003757{
3758 u8 *cmd = scp->cmnd;
3759 u64 lba;
3760 u32 num;
3761 int errsts;
3762
3763 if (!scsi_bidi_cmnd(scp)) {
3764 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3765 INSUFF_RES_ASCQ);
3766 return check_condition_result;
3767 }
3768 errsts = resp_read_dt0(scp, devip);
3769 if (errsts)
3770 return errsts;
3771 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3772 errsts = resp_write_dt0(scp, devip);
3773 if (errsts)
3774 return errsts;
3775 }
3776 lba = get_unaligned_be32(cmd + 2);
3777 num = get_unaligned_be16(cmd + 7);
3778 return resp_xdwriteread(scp, lba, num, devip);
3779}
3780
Douglas Gilbertc4837392016-05-06 00:40:26 -04003781static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3782{
Bart Van Assche458df782018-01-26 08:52:19 -08003783 u32 tag = blk_mq_unique_tag(cmnd->request);
3784 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003785
Bart Van Assche458df782018-01-26 08:52:19 -08003786 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3787 if (WARN_ON_ONCE(hwq >= submit_queues))
3788 hwq = 0;
3789 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003790}
3791
3792/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003793static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003795 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003796 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003798 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003799 struct sdebug_queued_cmd *sqcp;
3800 struct scsi_cmnd *scp;
3801 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802
Douglas Gilbert10bde982018-01-10 16:57:31 -05003803 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003804 qc_idx = sd_dp->qc_idx;
3805 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3806 if (sdebug_statistics) {
3807 atomic_inc(&sdebug_completions);
3808 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3809 atomic_inc(&sdebug_miss_cpus);
3810 }
3811 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3812 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 return;
3814 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003815 spin_lock_irqsave(&sqp->qc_lock, iflags);
3816 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003817 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003818 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003819 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3820 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3821 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 return;
3823 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003824 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003825 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003826 atomic_dec(&devip->num_in_q);
3827 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003828 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003829 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003830 retiring = 1;
3831
3832 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003833 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3834 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003835 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003836 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003838
3839 if (unlikely(retiring)) { /* user has reduced max_queue */
3840 int k, retval;
3841
3842 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003843 if (qc_idx >= retval) {
3844 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003845 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003846 return;
3847 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003848 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003849 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003850 atomic_set(&retired_max_queue, 0);
3851 else
3852 atomic_set(&retired_max_queue, k + 1);
3853 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003854 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003855 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856}
3857
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003858/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003859static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003860{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003861 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3862 hrt);
3863 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003864 return HRTIMER_NORESTART;
3865}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
Douglas Gilberta10bc122016-04-25 12:16:32 -04003867/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003868static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003869{
3870 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3871 ew.work);
3872 sdebug_q_cmd_complete(sd_dp);
3873}
3874
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003875static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003876static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003877
Douglas Gilbertfd321192016-04-25 12:16:33 -04003878static struct sdebug_dev_info *sdebug_device_create(
3879 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003880{
3881 struct sdebug_dev_info *devip;
3882
3883 devip = kzalloc(sizeof(*devip), flags);
3884 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003885 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003886 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003887 else if (sdebug_uuid_ctl == 2) {
3888 if (got_shared_uuid)
3889 devip->lu_name = shared_uuid;
3890 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003891 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003892 got_shared_uuid = true;
3893 devip->lu_name = shared_uuid;
3894 }
3895 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003896 devip->sdbg_host = sdbg_host;
3897 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3898 }
3899 return devip;
3900}
3901
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003902static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003904 struct sdebug_host_info *sdbg_host;
3905 struct sdebug_dev_info *open_devip = NULL;
3906 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003908 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3909 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003910 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3914 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003915 (devip->target == sdev->id) &&
3916 (devip->lun == sdev->lun))
3917 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 else {
3919 if ((!devip->used) && (!open_devip))
3920 open_devip = devip;
3921 }
3922 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003923 if (!open_devip) { /* try and make a new one */
3924 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3925 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003926 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 return NULL;
3928 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003930
3931 open_devip->channel = sdev->channel;
3932 open_devip->target = sdev->id;
3933 open_devip->lun = sdev->lun;
3934 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003935 atomic_set(&open_devip->num_in_q, 0);
3936 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003937 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003938 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939}
3940
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003941static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003943 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003944 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003945 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Bart Van Assche8b904b52018-03-07 17:10:10 -08003946 blk_queue_flag_set(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003947 return 0;
3948}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003950static int scsi_debug_slave_configure(struct scsi_device *sdp)
3951{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003952 struct sdebug_dev_info *devip =
3953 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003954
Douglas Gilbert773642d2016-04-25 12:16:28 -04003955 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003956 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003957 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003958 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3959 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3960 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003961 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003962 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003963 return 1; /* no resources, will be marked offline */
3964 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003965 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003966 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003967 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003968 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003969 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003970 return 0;
3971}
3972
3973static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3974{
3975 struct sdebug_dev_info *devip =
3976 (struct sdebug_dev_info *)sdp->hostdata;
3977
Douglas Gilbert773642d2016-04-25 12:16:28 -04003978 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003979 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003980 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3981 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003982 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003983 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003984 sdp->hostdata = NULL;
3985 }
3986}
3987
Douglas Gilbert10bde982018-01-10 16:57:31 -05003988static void stop_qc_helper(struct sdebug_defer *sd_dp,
3989 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003990{
3991 if (!sd_dp)
3992 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003993 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003994 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003995 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003996 cancel_work_sync(&sd_dp->ew.work);
3997}
3998
Douglas Gilberta10bc122016-04-25 12:16:32 -04003999/* If @cmnd found deletes its timer or work queue and returns true; else
4000 returns false */
4001static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004002{
4003 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004004 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004005 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004006 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004007 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004008 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004009 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004010
Douglas Gilbertc4837392016-05-06 00:40:26 -04004011 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4012 spin_lock_irqsave(&sqp->qc_lock, iflags);
4013 qmax = sdebug_max_queue;
4014 r_qmax = atomic_read(&retired_max_queue);
4015 if (r_qmax > qmax)
4016 qmax = r_qmax;
4017 for (k = 0; k < qmax; ++k) {
4018 if (test_bit(k, sqp->in_use_bm)) {
4019 sqcp = &sqp->qc_arr[k];
4020 if (cmnd != sqcp->a_cmnd)
4021 continue;
4022 /* found */
4023 devip = (struct sdebug_dev_info *)
4024 cmnd->device->hostdata;
4025 if (devip)
4026 atomic_dec(&devip->num_in_q);
4027 sqcp->a_cmnd = NULL;
4028 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004029 if (sd_dp) {
4030 l_defer_t = sd_dp->defer_t;
4031 sd_dp->defer_t = SDEB_DEFER_NONE;
4032 } else
4033 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004034 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004035 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004036 clear_bit(k, sqp->in_use_bm);
4037 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004038 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004039 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004040 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004041 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04004042 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004043}
4044
Douglas Gilberta10bc122016-04-25 12:16:32 -04004045/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004046static void stop_all_queued(void)
4047{
4048 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004049 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004050 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004051 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004052 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004053 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004054 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004055
Douglas Gilbertc4837392016-05-06 00:40:26 -04004056 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4057 spin_lock_irqsave(&sqp->qc_lock, iflags);
4058 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4059 if (test_bit(k, sqp->in_use_bm)) {
4060 sqcp = &sqp->qc_arr[k];
4061 if (sqcp->a_cmnd == NULL)
4062 continue;
4063 devip = (struct sdebug_dev_info *)
4064 sqcp->a_cmnd->device->hostdata;
4065 if (devip)
4066 atomic_dec(&devip->num_in_q);
4067 sqcp->a_cmnd = NULL;
4068 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004069 if (sd_dp) {
4070 l_defer_t = sd_dp->defer_t;
4071 sd_dp->defer_t = SDEB_DEFER_NONE;
4072 } else
4073 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004074 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004075 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004076 clear_bit(k, sqp->in_use_bm);
4077 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004078 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004079 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004080 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082}
4083
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004084/* Free queued command memory on heap */
4085static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004087 int j, k;
4088 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004089 struct sdebug_queued_cmd *sqcp;
4090
Douglas Gilbertc4837392016-05-06 00:40:26 -04004091 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4092 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4093 sqcp = &sqp->qc_arr[k];
4094 kfree(sqcp->sd_dp);
4095 sqcp->sd_dp = NULL;
4096 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098}
4099
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004100static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004102 bool ok;
4103
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004104 ++num_aborts;
4105 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004106 ok = stop_queued_cmnd(SCpnt);
4107 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4108 sdev_printk(KERN_INFO, SCpnt->device,
4109 "%s: command%s found\n", __func__,
4110 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004112 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113}
4114
John Pittman91d4c752018-02-09 21:12:43 -05004115static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004118 if (SCpnt && SCpnt->device) {
4119 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004120 struct sdebug_dev_info *devip =
4121 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004122
Douglas Gilbert773642d2016-04-25 12:16:28 -04004123 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004124 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004126 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 }
4128 return SUCCESS;
4129}
4130
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004131static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4132{
4133 struct sdebug_host_info *sdbg_host;
4134 struct sdebug_dev_info *devip;
4135 struct scsi_device *sdp;
4136 struct Scsi_Host *hp;
4137 int k = 0;
4138
4139 ++num_target_resets;
4140 if (!SCpnt)
4141 goto lie;
4142 sdp = SCpnt->device;
4143 if (!sdp)
4144 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004145 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004146 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4147 hp = sdp->host;
4148 if (!hp)
4149 goto lie;
4150 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4151 if (sdbg_host) {
4152 list_for_each_entry(devip,
4153 &sdbg_host->dev_info_list,
4154 dev_list)
4155 if (devip->target == sdp->id) {
4156 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4157 ++k;
4158 }
4159 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004160 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004161 sdev_printk(KERN_INFO, sdp,
4162 "%s: %d device(s) found in target\n", __func__, k);
4163lie:
4164 return SUCCESS;
4165}
4166
John Pittman91d4c752018-02-09 21:12:43 -05004167static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168{
4169 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004170 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004171 struct scsi_device *sdp;
4172 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004173 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004176 if (!(SCpnt && SCpnt->device))
4177 goto lie;
4178 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004179 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004180 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4181 hp = sdp->host;
4182 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004183 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004185 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05004186 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004187 dev_list) {
4188 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4189 ++k;
4190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 }
4192 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004193 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004194 sdev_printk(KERN_INFO, sdp,
4195 "%s: %d device(s) found in host\n", __func__, k);
4196lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 return SUCCESS;
4198}
4199
John Pittman91d4c752018-02-09 21:12:43 -05004200static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201{
John Pittman91d4c752018-02-09 21:12:43 -05004202 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004203 struct sdebug_dev_info *devip;
4204 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004207 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004208 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05004209 spin_lock(&sdebug_host_list_lock);
4210 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004211 list_for_each_entry(devip, &sdbg_host->dev_info_list,
4212 dev_list) {
4213 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4214 ++k;
4215 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05004216 }
4217 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004219 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004220 sdev_printk(KERN_INFO, SCpnt->device,
4221 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 return SUCCESS;
4223}
4224
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09004225static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004226 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227{
John Pittman91d4c752018-02-09 21:12:43 -05004228 struct partition *pp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 int starts[SDEBUG_MAX_PARTS + 2];
4230 int sectors_per_part, num_sectors, k;
4231 int heads_by_sects, start_sec, end_sec;
4232
4233 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004234 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004236 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4237 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03004238 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004240 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004242 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004244 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004245 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4247 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004248 starts[sdebug_num_parts] = num_sectors;
4249 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250
4251 ramp[510] = 0x55; /* magic partition markings */
4252 ramp[511] = 0xAA;
4253 pp = (struct partition *)(ramp + 0x1be);
4254 for (k = 0; starts[k + 1]; ++k, ++pp) {
4255 start_sec = starts[k];
4256 end_sec = starts[k + 1] - 1;
4257 pp->boot_ind = 0;
4258
4259 pp->cyl = start_sec / heads_by_sects;
4260 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4261 / sdebug_sectors_per;
4262 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4263
4264 pp->end_cyl = end_sec / heads_by_sects;
4265 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4266 / sdebug_sectors_per;
4267 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4268
Akinobu Mita150c3542013-08-26 22:08:40 +09004269 pp->start_sect = cpu_to_le32(start_sec);
4270 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 pp->sys_ind = 0x83; /* plain Linux partition */
4272 }
4273}
4274
Douglas Gilbertc4837392016-05-06 00:40:26 -04004275static void block_unblock_all_queues(bool block)
4276{
4277 int j;
4278 struct sdebug_queue *sqp;
4279
4280 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4281 atomic_set(&sqp->blocked, (int)block);
4282}
4283
4284/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4285 * commands will be processed normally before triggers occur.
4286 */
4287static void tweak_cmnd_count(void)
4288{
4289 int count, modulo;
4290
4291 modulo = abs(sdebug_every_nth);
4292 if (modulo < 2)
4293 return;
4294 block_unblock_all_queues(true);
4295 count = atomic_read(&sdebug_cmnd_count);
4296 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4297 block_unblock_all_queues(false);
4298}
4299
4300static void clear_queue_stats(void)
4301{
4302 atomic_set(&sdebug_cmnd_count, 0);
4303 atomic_set(&sdebug_completions, 0);
4304 atomic_set(&sdebug_miss_cpus, 0);
4305 atomic_set(&sdebug_a_tsf, 0);
4306}
4307
4308static void setup_inject(struct sdebug_queue *sqp,
4309 struct sdebug_queued_cmd *sqcp)
4310{
Martin Wilckf9ba7af2018-01-30 00:35:52 +01004311 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4312 if (sdebug_every_nth > 0)
4313 sqcp->inj_recovered = sqcp->inj_transport
4314 = sqcp->inj_dif
4315 = sqcp->inj_dix = sqcp->inj_short = 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004316 return;
Martin Wilckf9ba7af2018-01-30 00:35:52 +01004317 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004318 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4319 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4320 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4321 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4322 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004323 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004324}
4325
4326/* Complete the processing of the thread that queued a SCSI command to this
4327 * driver. It either completes the command by calling cmnd_done() or
4328 * schedules a hr timer or work queue then returns 0. Returns
4329 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4330 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004331static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Martin Wilckf66b8512018-02-14 11:05:57 +01004332 int scsi_result,
4333 int (*pfp)(struct scsi_cmnd *,
4334 struct sdebug_dev_info *),
4335 int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004337 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004338 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004339 struct sdebug_queue *sqp;
4340 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004341 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004342 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004344 if (unlikely(devip == NULL)) {
4345 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004346 scsi_result = DID_NO_CONNECT << 16;
4347 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004349 sdp = cmnd->device;
4350
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004351 if (delta_jiff == 0)
4352 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004354 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004355 sqp = get_queue(cmnd);
4356 spin_lock_irqsave(&sqp->qc_lock, iflags);
4357 if (unlikely(atomic_read(&sqp->blocked))) {
4358 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4359 return SCSI_MLQUEUE_HOST_BUSY;
4360 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004361 num_in_q = atomic_read(&devip->num_in_q);
4362 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004363 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004364 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004365 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004366 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004367 goto respond_in_thread;
4368 } else
4369 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004370 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004371 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4372 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004373 if ((num_in_q == (qdepth - 1)) &&
4374 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004375 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004376 atomic_set(&sdebug_a_tsf, 0);
4377 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004378 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004380 }
4381
Douglas Gilbertc4837392016-05-06 00:40:26 -04004382 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004383 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004384 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004385 if (scsi_result)
4386 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004387 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004388 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004389 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004390 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004391 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004392 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004393 (scsi_result ? "status: TASK SET FULL" :
4394 "report: host busy"));
4395 if (scsi_result)
4396 goto respond_in_thread;
4397 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004398 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004400 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004401 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004402 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004403 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004404 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004405 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004406 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4407 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4408 setup_inject(sqp, sqcp);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004409 if (sd_dp == NULL) {
4410 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4411 if (sd_dp == NULL)
4412 return SCSI_MLQUEUE_HOST_BUSY;
4413 }
Martin Wilckf66b8512018-02-14 11:05:57 +01004414
4415 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4416 if (cmnd->result & SDEG_RES_IMMED_MASK) {
4417 /*
4418 * This is the F_DELAY_OVERR case. No delay.
4419 */
4420 cmnd->result &= ~SDEG_RES_IMMED_MASK;
4421 delta_jiff = ndelay = 0;
4422 }
4423 if (cmnd->result == 0 && scsi_result != 0)
4424 cmnd->result = scsi_result;
4425
4426 if (unlikely(sdebug_verbose && cmnd->result))
4427 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4428 __func__, cmnd->result);
4429
Douglas Gilbert10bde982018-01-10 16:57:31 -05004430 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004431 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004432
Douglas Gilbertb333a812016-04-25 12:16:30 -04004433 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004434 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004435 } else
Douglas Gilbert10bde982018-01-10 16:57:31 -05004436 kt = ndelay;
4437 if (!sd_dp->init_hrt) {
4438 sd_dp->init_hrt = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004439 sqcp->sd_dp = sd_dp;
4440 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004441 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004442 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004443 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4444 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004445 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004446 if (sdebug_statistics)
4447 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004448 sd_dp->defer_t = SDEB_DEFER_HRT;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004449 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4450 } else { /* jdelay < 0, use work queue */
Douglas Gilbert10bde982018-01-10 16:57:31 -05004451 if (!sd_dp->init_wq) {
4452 sd_dp->init_wq = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004453 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004454 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4455 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004456 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004457 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004458 if (sdebug_statistics)
4459 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004460 sd_dp->defer_t = SDEB_DEFER_WQ;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004461 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004462 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004463 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4464 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004465 sdev_printk(KERN_INFO, sdp,
4466 "%s: num_in_q=%d +1, %s%s\n", __func__,
4467 num_in_q, (inject ? "<inject> " : ""),
4468 "status: TASK SET FULL");
4469 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004470
4471respond_in_thread: /* call back to mid-layer using invocation thread */
Martin Wilckf66b8512018-02-14 11:05:57 +01004472 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4473 cmnd->result &= ~SDEG_RES_IMMED_MASK;
4474 if (cmnd->result == 0 && scsi_result != 0)
4475 cmnd->result = scsi_result;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004476 cmnd->scsi_done(cmnd);
4477 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004479
Douglas Gilbert23183912006-09-16 20:30:47 -04004480/* Note: The following macros create attribute files in the
4481 /sys/module/scsi_debug/parameters directory. Unfortunately this
4482 driver is unaware of a change and cannot trigger auxiliary actions
4483 as it can when the corresponding attribute in the
4484 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4485 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004486module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4487module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004488module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004489module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004490module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004491module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4492module_param_named(dif, sdebug_dif, int, S_IRUGO);
4493module_param_named(dix, sdebug_dix, int, S_IRUGO);
4494module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4495module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4496module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4497module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4498module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004499module_param_string(inq_vendor, sdebug_inq_vendor_id,
4500 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4501module_param_string(inq_product, sdebug_inq_product_id,
4502 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4503module_param_string(inq_rev, sdebug_inq_product_rev,
4504 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004505module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4506module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4507module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4508module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4509module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4510module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4511module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Laurence Obermand9da8912018-02-03 13:38:35 -05004512module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4513module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004514module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4515module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4516module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4517module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4518module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4519module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4520module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4521module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004522module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004523module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4524module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4525module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4526module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004527module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004528module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004529module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004530module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4531module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4532module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4533module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4534module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004535module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004536module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004537 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004538module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004539 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540
4541MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4542MODULE_DESCRIPTION("SCSI debug adapter driver");
4543MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004544MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545
4546MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004547MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004548MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004549MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004550MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004551MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004552MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4553MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004554MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004555MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004556MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004557MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004558MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004559MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4560MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004561MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4562 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004563MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4564MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4565MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004566MODULE_PARM_DESC(lbprz,
4567 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004568MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004569MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004570MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05004571MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4572MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004573MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004574MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004575MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004577MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004578MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004579MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004580MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004581MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004583MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004584MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004585MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004586MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004587MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004588MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004589MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4590MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004591MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4592MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004593MODULE_PARM_DESC(uuid_ctl,
4594 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004595MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004596MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4597MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004599#define SDEBUG_INFO_LEN 256
4600static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601
John Pittman91d4c752018-02-09 21:12:43 -05004602static const char *scsi_debug_info(struct Scsi_Host *shp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004604 int k;
4605
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004606 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4607 my_name, SDEBUG_VERSION, sdebug_version_date);
4608 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004609 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004610 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4611 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4612 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4613 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 return sdebug_info;
4615}
4616
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004617/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004618static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4619 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620{
Al Viroc8ed5552013-03-31 01:46:06 -04004621 char arr[16];
4622 int opts;
4623 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624
Al Viroc8ed5552013-03-31 01:46:06 -04004625 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4626 return -EACCES;
4627 memcpy(arr, buffer, minLen);
4628 arr[minLen] = '\0';
4629 if (1 != sscanf(arr, "%d", &opts))
4630 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004631 sdebug_opts = opts;
4632 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4633 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4634 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004635 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004636 return length;
4637}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004639/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4640 * same for each scsi_debug host (if more than one). Some of the counters
4641 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004642static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4643{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004644 int f, j, l;
4645 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004646
Douglas Gilbertc4837392016-05-06 00:40:26 -04004647 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4648 SDEBUG_VERSION, sdebug_version_date);
4649 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4650 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4651 sdebug_opts, sdebug_every_nth);
4652 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4653 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4654 sdebug_sector_size, "bytes");
4655 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4656 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4657 num_aborts);
4658 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4659 num_dev_resets, num_target_resets, num_bus_resets,
4660 num_host_resets);
4661 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4662 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08004663 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4664 sdebug_statistics);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004665 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4666 atomic_read(&sdebug_cmnd_count),
4667 atomic_read(&sdebug_completions),
4668 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4669 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004670
Douglas Gilbertc4837392016-05-06 00:40:26 -04004671 seq_printf(m, "submit_queues=%d\n", submit_queues);
4672 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4673 seq_printf(m, " queue %d:\n", j);
4674 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4675 if (f != sdebug_max_queue) {
4676 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4677 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4678 "first,last bits", f, l);
4679 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004680 }
Al Viroc8ed5552013-03-31 01:46:06 -04004681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682}
4683
Akinobu Mita82069372013-10-14 22:48:04 +09004684static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004686 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004688/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4689 * of delay is jiffies.
4690 */
Akinobu Mita82069372013-10-14 22:48:04 +09004691static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4692 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004694 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004696 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004697 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004698 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004699 int j, k;
4700 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004701
Douglas Gilbertc4837392016-05-06 00:40:26 -04004702 block_unblock_all_queues(true);
4703 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4704 ++j, ++sqp) {
4705 k = find_first_bit(sqp->in_use_bm,
4706 sdebug_max_queue);
4707 if (k != sdebug_max_queue) {
4708 res = -EBUSY; /* queued commands */
4709 break;
4710 }
4711 }
4712 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04004713 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004714 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004715 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004716 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004718 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 }
4720 return -EINVAL;
4721}
Akinobu Mita82069372013-10-14 22:48:04 +09004722static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004724static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4725{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004726 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004727}
4728/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004729/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004730static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004731 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004732{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004733 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004734
4735 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004736 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004737 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004738 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004739 int j, k;
4740 struct sdebug_queue *sqp;
4741
4742 block_unblock_all_queues(true);
4743 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4744 ++j, ++sqp) {
4745 k = find_first_bit(sqp->in_use_bm,
4746 sdebug_max_queue);
4747 if (k != sdebug_max_queue) {
4748 res = -EBUSY; /* queued commands */
4749 break;
4750 }
4751 }
4752 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004753 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004754 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4755 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004756 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004757 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004758 }
4759 return res;
4760 }
4761 return -EINVAL;
4762}
4763static DRIVER_ATTR_RW(ndelay);
4764
Akinobu Mita82069372013-10-14 22:48:04 +09004765static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004767 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768}
4769
Akinobu Mita82069372013-10-14 22:48:04 +09004770static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4771 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004773 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 char work[20];
4775
Douglas Gilbert9a051012017-12-23 12:48:10 -05004776 if (sscanf(buf, "%10s", work) == 1) {
4777 if (strncasecmp(work, "0x", 2) == 0) {
4778 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 goto opts_done;
4780 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004781 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 goto opts_done;
4783 }
4784 }
4785 return -EINVAL;
4786opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004787 sdebug_opts = opts;
4788 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4789 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004790 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 return count;
4792}
Akinobu Mita82069372013-10-14 22:48:04 +09004793static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794
Akinobu Mita82069372013-10-14 22:48:04 +09004795static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004797 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798}
Akinobu Mita82069372013-10-14 22:48:04 +09004799static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4800 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004802 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
4804 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004805 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 return count;
4807 }
4808 return -EINVAL;
4809}
Akinobu Mita82069372013-10-14 22:48:04 +09004810static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811
Akinobu Mita82069372013-10-14 22:48:04 +09004812static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004814 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815}
Akinobu Mita82069372013-10-14 22:48:04 +09004816static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4817 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004819 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820
4821 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004822 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 return count;
4824 }
4825 return -EINVAL;
4826}
Akinobu Mita82069372013-10-14 22:48:04 +09004827static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828
Akinobu Mita82069372013-10-14 22:48:04 +09004829static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004830{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004831 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004832}
Akinobu Mita82069372013-10-14 22:48:04 +09004833static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4834 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004835{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004836 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004837
4838 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004839 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004840 sdebug_fake_rw = (sdebug_fake_rw > 0);
4841 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004842 if ((0 == n) && (NULL == fake_storep)) {
4843 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004844 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004845 1048576;
4846
4847 fake_storep = vmalloc(sz);
4848 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004849 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004850 return -ENOMEM;
4851 }
4852 memset(fake_storep, 0, sz);
4853 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004854 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004855 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004856 return count;
4857 }
4858 return -EINVAL;
4859}
Akinobu Mita82069372013-10-14 22:48:04 +09004860static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004861
Akinobu Mita82069372013-10-14 22:48:04 +09004862static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004863{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004864 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004865}
Akinobu Mita82069372013-10-14 22:48:04 +09004866static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4867 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004868{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004869 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004870
4871 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004872 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004873 return count;
4874 }
4875 return -EINVAL;
4876}
Akinobu Mita82069372013-10-14 22:48:04 +09004877static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004878
Akinobu Mita82069372013-10-14 22:48:04 +09004879static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004881 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882}
Akinobu Mita82069372013-10-14 22:48:04 +09004883static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4884 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004886 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887
4888 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004889 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 sdebug_max_tgts_luns();
4891 return count;
4892 }
4893 return -EINVAL;
4894}
Akinobu Mita82069372013-10-14 22:48:04 +09004895static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896
Akinobu Mita82069372013-10-14 22:48:04 +09004897static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004899 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900}
Akinobu Mita82069372013-10-14 22:48:04 +09004901static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902
Akinobu Mita82069372013-10-14 22:48:04 +09004903static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004905 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906}
Akinobu Mita82069372013-10-14 22:48:04 +09004907static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908
Akinobu Mita82069372013-10-14 22:48:04 +09004909static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004911 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912}
Akinobu Mita82069372013-10-14 22:48:04 +09004913static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4914 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004916 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917
4918 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004919 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004920 if (nth && !sdebug_statistics) {
4921 pr_info("every_nth needs statistics=1, set it\n");
4922 sdebug_statistics = true;
4923 }
4924 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 return count;
4926 }
4927 return -EINVAL;
4928}
Akinobu Mita82069372013-10-14 22:48:04 +09004929static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930
Akinobu Mita82069372013-10-14 22:48:04 +09004931static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004933 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934}
Akinobu Mita82069372013-10-14 22:48:04 +09004935static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4936 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004938 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004939 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940
4941 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004942 if (n > 256) {
4943 pr_warn("max_luns can be no more than 256\n");
4944 return -EINVAL;
4945 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004946 changed = (sdebug_max_luns != n);
4947 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004949 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004950 struct sdebug_host_info *sdhp;
4951 struct sdebug_dev_info *dp;
4952
4953 spin_lock(&sdebug_host_list_lock);
4954 list_for_each_entry(sdhp, &sdebug_host_list,
4955 host_list) {
4956 list_for_each_entry(dp, &sdhp->dev_info_list,
4957 dev_list) {
4958 set_bit(SDEBUG_UA_LUNS_CHANGED,
4959 dp->uas_bm);
4960 }
4961 }
4962 spin_unlock(&sdebug_host_list_lock);
4963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 return count;
4965 }
4966 return -EINVAL;
4967}
Akinobu Mita82069372013-10-14 22:48:04 +09004968static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004969
Akinobu Mita82069372013-10-14 22:48:04 +09004970static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004971{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004972 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004973}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004974/* N.B. max_queue can be changed while there are queued commands. In flight
4975 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004976static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4977 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004978{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004979 int j, n, k, a;
4980 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004981
4982 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004983 (n <= SDEBUG_CANQUEUE)) {
4984 block_unblock_all_queues(true);
4985 k = 0;
4986 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4987 ++j, ++sqp) {
4988 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4989 if (a > k)
4990 k = a;
4991 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004992 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004993 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004994 atomic_set(&retired_max_queue, 0);
4995 else if (k >= n)
4996 atomic_set(&retired_max_queue, k + 1);
4997 else
4998 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004999 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005000 return count;
5001 }
5002 return -EINVAL;
5003}
Akinobu Mita82069372013-10-14 22:48:04 +09005004static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005005
Akinobu Mita82069372013-10-14 22:48:04 +09005006static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005007{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005008 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005009}
Akinobu Mita82069372013-10-14 22:48:04 +09005010static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005011
Akinobu Mita82069372013-10-14 22:48:04 +09005012static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005014 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015}
Akinobu Mita82069372013-10-14 22:48:04 +09005016static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
Akinobu Mita82069372013-10-14 22:48:04 +09005018static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005019{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005020 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005021}
Akinobu Mita82069372013-10-14 22:48:04 +09005022static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
5023 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005024{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005025 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05005026 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005027
5028 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005029 changed = (sdebug_virtual_gb != n);
5030 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005031 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05005032 if (changed) {
5033 struct sdebug_host_info *sdhp;
5034 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005035
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05005036 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05005037 list_for_each_entry(sdhp, &sdebug_host_list,
5038 host_list) {
5039 list_for_each_entry(dp, &sdhp->dev_info_list,
5040 dev_list) {
5041 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
5042 dp->uas_bm);
5043 }
5044 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05005045 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05005046 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005047 return count;
5048 }
5049 return -EINVAL;
5050}
Akinobu Mita82069372013-10-14 22:48:04 +09005051static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005052
Akinobu Mita82069372013-10-14 22:48:04 +09005053static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005055 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056}
5057
Douglas Gilbertfd321192016-04-25 12:16:33 -04005058static int sdebug_add_adapter(void);
5059static void sdebug_remove_adapter(void);
5060
Akinobu Mita82069372013-10-14 22:48:04 +09005061static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
5062 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09005064 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09005066 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 if (delta_hosts > 0) {
5069 do {
5070 sdebug_add_adapter();
5071 } while (--delta_hosts);
5072 } else if (delta_hosts < 0) {
5073 do {
5074 sdebug_remove_adapter();
5075 } while (++delta_hosts);
5076 }
5077 return count;
5078}
Akinobu Mita82069372013-10-14 22:48:04 +09005079static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080
Akinobu Mita82069372013-10-14 22:48:04 +09005081static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04005082{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005083 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005084}
Akinobu Mita82069372013-10-14 22:48:04 +09005085static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
5086 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04005087{
5088 int n;
5089
5090 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005091 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04005092 return count;
5093 }
5094 return -EINVAL;
5095}
Akinobu Mita82069372013-10-14 22:48:04 +09005096static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005097
Douglas Gilbertc4837392016-05-06 00:40:26 -04005098static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5099{
5100 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5101}
5102static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5103 size_t count)
5104{
5105 int n;
5106
5107 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5108 if (n > 0)
5109 sdebug_statistics = true;
5110 else {
5111 clear_queue_stats();
5112 sdebug_statistics = false;
5113 }
5114 return count;
5115 }
5116 return -EINVAL;
5117}
5118static DRIVER_ATTR_RW(statistics);
5119
Akinobu Mita82069372013-10-14 22:48:04 +09005120static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04005121{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005122 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005123}
Akinobu Mita82069372013-10-14 22:48:04 +09005124static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005125
Douglas Gilbertc4837392016-05-06 00:40:26 -04005126static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5127{
5128 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5129}
5130static DRIVER_ATTR_RO(submit_queues);
5131
Akinobu Mita82069372013-10-14 22:48:04 +09005132static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005133{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005134 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005135}
Akinobu Mita82069372013-10-14 22:48:04 +09005136static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005137
Akinobu Mita82069372013-10-14 22:48:04 +09005138static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005139{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005140 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005141}
Akinobu Mita82069372013-10-14 22:48:04 +09005142static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005143
Akinobu Mita82069372013-10-14 22:48:04 +09005144static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005145{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005146 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005147}
Akinobu Mita82069372013-10-14 22:48:04 +09005148static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005149
Akinobu Mita82069372013-10-14 22:48:04 +09005150static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005151{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005152 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005153}
Akinobu Mita82069372013-10-14 22:48:04 +09005154static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005155
Akinobu Mita82069372013-10-14 22:48:04 +09005156static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005157{
5158 ssize_t count;
5159
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005160 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04005161 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
5162 sdebug_store_sectors);
5163
Tejun Heoc7badc92015-02-13 14:37:51 -08005164 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5165 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005166 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08005167 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04005168
5169 return count;
5170}
Akinobu Mita82069372013-10-14 22:48:04 +09005171static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005172
Akinobu Mita82069372013-10-14 22:48:04 +09005173static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02005174{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005175 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02005176}
Akinobu Mita82069372013-10-14 22:48:04 +09005177static ssize_t removable_store(struct device_driver *ddp, const char *buf,
5178 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02005179{
5180 int n;
5181
5182 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005183 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02005184 return count;
5185 }
5186 return -EINVAL;
5187}
Akinobu Mita82069372013-10-14 22:48:04 +09005188static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02005189
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005190static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5191{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005192 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005193}
Douglas Gilbert185dd232016-04-25 12:16:29 -04005194/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005195static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5196 size_t count)
5197{
Douglas Gilbert185dd232016-04-25 12:16:29 -04005198 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005199
5200 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04005201 sdebug_host_lock = (n > 0);
5202 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005203 }
5204 return -EINVAL;
5205}
5206static DRIVER_ATTR_RW(host_lock);
5207
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005208static ssize_t strict_show(struct device_driver *ddp, char *buf)
5209{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005210 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005211}
5212static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5213 size_t count)
5214{
5215 int n;
5216
5217 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005218 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005219 return count;
5220 }
5221 return -EINVAL;
5222}
5223static DRIVER_ATTR_RW(strict);
5224
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005225static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
5226{
5227 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
5228}
5229static DRIVER_ATTR_RO(uuid_ctl);
5230
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005231static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
5232{
5233 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
5234}
5235static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
5236 size_t count)
5237{
5238 int ret, n;
5239
5240 ret = kstrtoint(buf, 0, &n);
5241 if (ret)
5242 return ret;
5243 sdebug_cdb_len = n;
5244 all_config_cdb_len();
5245 return count;
5246}
5247static DRIVER_ATTR_RW(cdb_len);
5248
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005249
Akinobu Mita82069372013-10-14 22:48:04 +09005250/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04005251 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
5252 files (over those found in the /sys/module/scsi_debug/parameters
5253 directory) is that auxiliary actions can be triggered when an attribute
5254 is changed. For example see: sdebug_add_host_store() above.
5255 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005256
Akinobu Mita82069372013-10-14 22:48:04 +09005257static struct attribute *sdebug_drv_attrs[] = {
5258 &driver_attr_delay.attr,
5259 &driver_attr_opts.attr,
5260 &driver_attr_ptype.attr,
5261 &driver_attr_dsense.attr,
5262 &driver_attr_fake_rw.attr,
5263 &driver_attr_no_lun_0.attr,
5264 &driver_attr_num_tgts.attr,
5265 &driver_attr_dev_size_mb.attr,
5266 &driver_attr_num_parts.attr,
5267 &driver_attr_every_nth.attr,
5268 &driver_attr_max_luns.attr,
5269 &driver_attr_max_queue.attr,
5270 &driver_attr_no_uld.attr,
5271 &driver_attr_scsi_level.attr,
5272 &driver_attr_virtual_gb.attr,
5273 &driver_attr_add_host.attr,
5274 &driver_attr_vpd_use_hostno.attr,
5275 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005276 &driver_attr_statistics.attr,
5277 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005278 &driver_attr_dix.attr,
5279 &driver_attr_dif.attr,
5280 &driver_attr_guard.attr,
5281 &driver_attr_ato.attr,
5282 &driver_attr_map.attr,
5283 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005284 &driver_attr_host_lock.attr,
5285 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005286 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005287 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005288 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005289 NULL,
5290};
5291ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005293static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005294
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295static int __init scsi_debug_init(void)
5296{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005297 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 int host_to_add;
5299 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005300 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005302 atomic_set(&retired_max_queue, 0);
5303
Douglas Gilbert773642d2016-04-25 12:16:28 -04005304 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005305 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005306 sdebug_ndelay = 0;
5307 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005308 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005309
Douglas Gilbert773642d2016-04-25 12:16:28 -04005310 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04005311 case 512:
5312 case 1024:
5313 case 2048:
5314 case 4096:
5315 break;
5316 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005317 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005318 return -EINVAL;
5319 }
5320
Douglas Gilbert773642d2016-04-25 12:16:28 -04005321 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005322 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005323 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005324 case T10_PI_TYPE1_PROTECTION:
5325 case T10_PI_TYPE2_PROTECTION:
5326 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005327 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005328 break;
5329
5330 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005331 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005332 return -EINVAL;
5333 }
5334
Douglas Gilbert773642d2016-04-25 12:16:28 -04005335 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005336 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005337 return -EINVAL;
5338 }
5339
Douglas Gilbert773642d2016-04-25 12:16:28 -04005340 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005341 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005342 return -EINVAL;
5343 }
5344
Douglas Gilbert773642d2016-04-25 12:16:28 -04005345 if (sdebug_physblk_exp > 15) {
5346 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005347 return -EINVAL;
5348 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005349 if (sdebug_max_luns > 256) {
5350 pr_warn("max_luns can be no more than 256, use default\n");
5351 sdebug_max_luns = DEF_MAX_LUNS;
5352 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005353
Douglas Gilbert773642d2016-04-25 12:16:28 -04005354 if (sdebug_lowest_aligned > 0x3fff) {
5355 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005356 return -EINVAL;
5357 }
5358
Douglas Gilbertc4837392016-05-06 00:40:26 -04005359 if (submit_queues < 1) {
5360 pr_err("submit_queues must be 1 or more\n");
5361 return -EINVAL;
5362 }
5363 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5364 GFP_KERNEL);
5365 if (sdebug_q_arr == NULL)
5366 return -ENOMEM;
5367 for (k = 0; k < submit_queues; ++k)
5368 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5369
Douglas Gilbert773642d2016-04-25 12:16:28 -04005370 if (sdebug_dev_size_mb < 1)
5371 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5372 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5373 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005374 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375
5376 /* play around with geometry, don't waste too much on track 0 */
5377 sdebug_heads = 8;
5378 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005379 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005381 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005382 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5384 (sdebug_sectors_per * sdebug_heads);
5385 if (sdebug_cylinders_per >= 1024) {
5386 /* other LLDs do this; implies >= 1GB ram disk ... */
5387 sdebug_heads = 255;
5388 sdebug_sectors_per = 63;
5389 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5390 (sdebug_sectors_per * sdebug_heads);
5391 }
5392
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005393 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005394 fake_storep = vmalloc(sz);
5395 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005396 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005397 ret = -ENOMEM;
5398 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005399 }
5400 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005401 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005402 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404
Douglas Gilbert773642d2016-04-25 12:16:28 -04005405 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005406 int dif_size;
5407
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005408 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005409 dif_storep = vmalloc(dif_size);
5410
Tomas Winklerc12879702015-07-28 16:54:20 +03005411 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005412
5413 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005414 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005415 ret = -ENOMEM;
5416 goto free_vm;
5417 }
5418
5419 memset(dif_storep, 0xff, dif_size);
5420 }
5421
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005422 /* Logical Block Provisioning */
5423 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005424 sdebug_unmap_max_blocks =
5425 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005426
Douglas Gilbert773642d2016-04-25 12:16:28 -04005427 sdebug_unmap_max_desc =
5428 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005429
Douglas Gilbert773642d2016-04-25 12:16:28 -04005430 sdebug_unmap_granularity =
5431 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005432
Douglas Gilbert773642d2016-04-25 12:16:28 -04005433 if (sdebug_unmap_alignment &&
5434 sdebug_unmap_granularity <=
5435 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005436 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005437 ret = -EINVAL;
5438 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005439 }
5440
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005441 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
Kees Cook42bc47b2018-06-12 14:27:11 -07005442 map_storep = vmalloc(array_size(sizeof(long),
5443 BITS_TO_LONGS(map_size)));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005444
Tomas Winklerc12879702015-07-28 16:54:20 +03005445 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005446
5447 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005448 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005449 ret = -ENOMEM;
5450 goto free_vm;
5451 }
5452
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005453 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005454
5455 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005456 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005457 map_region(0, 2);
5458 }
5459
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005460 pseudo_primary = root_device_register("pseudo_0");
5461 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005462 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005463 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005464 goto free_vm;
5465 }
5466 ret = bus_register(&pseudo_lld_bus);
5467 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005468 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005469 goto dev_unreg;
5470 }
5471 ret = driver_register(&sdebug_driverfs_driver);
5472 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005473 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005474 goto bus_unreg;
5475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476
Douglas Gilbert773642d2016-04-25 12:16:28 -04005477 host_to_add = sdebug_add_host;
5478 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
Douglas Gilbert9a051012017-12-23 12:48:10 -05005480 for (k = 0; k < host_to_add; k++) {
5481 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005482 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005483 break;
5484 }
5485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486
Douglas Gilbert773642d2016-04-25 12:16:28 -04005487 if (sdebug_verbose)
5488 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005489
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005491
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005492bus_unreg:
5493 bus_unregister(&pseudo_lld_bus);
5494dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005495 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005496free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005497 vfree(map_storep);
5498 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005499 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005500free_q_arr:
5501 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005502 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503}
5504
5505static void __exit scsi_debug_exit(void)
5506{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005507 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508
5509 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005510 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 for (; k; k--)
5512 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 driver_unregister(&sdebug_driverfs_driver);
5514 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005515 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005517 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005518 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005520 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521}
5522
5523device_initcall(scsi_debug_init);
5524module_exit(scsi_debug_exit);
5525
John Pittman91d4c752018-02-09 21:12:43 -05005526static void sdebug_release_adapter(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005528 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529
5530 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005531 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532}
5533
5534static int sdebug_add_adapter(void)
5535{
5536 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005537 int error = 0;
5538 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005539 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540
Douglas Gilbert9a051012017-12-23 12:48:10 -05005541 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5542 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005543 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005544 return -ENOMEM;
5545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546
Douglas Gilbert9a051012017-12-23 12:48:10 -05005547 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548
Douglas Gilbert773642d2016-04-25 12:16:28 -04005549 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005550 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005551 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5552 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005553 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005554 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005556 }
5557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558
Douglas Gilbert9a051012017-12-23 12:48:10 -05005559 spin_lock(&sdebug_host_list_lock);
5560 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5561 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562
Douglas Gilbert9a051012017-12-23 12:48:10 -05005563 sdbg_host->dev.bus = &pseudo_lld_bus;
5564 sdbg_host->dev.parent = pseudo_primary;
5565 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005566 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567
Douglas Gilbert9a051012017-12-23 12:48:10 -05005568 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005569
Douglas Gilbert9a051012017-12-23 12:48:10 -05005570 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571 goto clean;
5572
Douglas Gilbert773642d2016-04-25 12:16:28 -04005573 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005574 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575
5576clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005577 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5578 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 list_del(&sdbg_devinfo->dev_list);
5580 kfree(sdbg_devinfo);
5581 }
5582
5583 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005584 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585}
5586
5587static void sdebug_remove_adapter(void)
5588{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005589 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005590
Douglas Gilbert9a051012017-12-23 12:48:10 -05005591 spin_lock(&sdebug_host_list_lock);
5592 if (!list_empty(&sdebug_host_list)) {
5593 sdbg_host = list_entry(sdebug_host_list.prev,
5594 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 list_del(&sdbg_host->host_list);
5596 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005597 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598
5599 if (!sdbg_host)
5600 return;
5601
Douglas Gilbert773642d2016-04-25 12:16:28 -04005602 device_unregister(&sdbg_host->dev);
5603 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604}
5605
Douglas Gilbertfd321192016-04-25 12:16:33 -04005606static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005607{
5608 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005609 struct sdebug_dev_info *devip;
5610
Douglas Gilbertc4837392016-05-06 00:40:26 -04005611 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005612 devip = (struct sdebug_dev_info *)sdev->hostdata;
5613 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005614 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005615 return -ENODEV;
5616 }
5617 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005618
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005619 if (qdepth < 1)
5620 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005621 /* allow to exceed max host qc_arr elements for testing */
5622 if (qdepth > SDEBUG_CANQUEUE + 10)
5623 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005624 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005625
Douglas Gilbert773642d2016-04-25 12:16:28 -04005626 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005627 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005628 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005629 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005630 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005631 return sdev->queue_depth;
5632}
5633
Douglas Gilbertc4837392016-05-06 00:40:26 -04005634static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005635{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005636 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005637 if (sdebug_every_nth < -1)
5638 sdebug_every_nth = -1;
5639 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005640 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005641 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005642 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005643 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005644 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005645 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005646}
5647
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005648static bool fake_host_busy(struct scsi_cmnd *scp)
5649{
5650 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5651 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5652}
5653
Douglas Gilbertfd321192016-04-25 12:16:33 -04005654static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5655 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005656{
5657 u8 sdeb_i;
5658 struct scsi_device *sdp = scp->device;
5659 const struct opcode_info_t *oip;
5660 const struct opcode_info_t *r_oip;
5661 struct sdebug_dev_info *devip;
5662 u8 *cmd = scp->cmnd;
5663 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
Martin Wilckf66b8512018-02-14 11:05:57 +01005664 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005665 int k, na;
5666 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005667 u32 flags;
5668 u16 sa;
5669 u8 opcode = cmd[0];
5670 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005671
5672 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005673 if (sdebug_statistics)
5674 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005675 if (unlikely(sdebug_verbose &&
5676 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005677 char b[120];
5678 int n, len, sb;
5679
5680 len = scp->cmd_len;
5681 sb = (int)sizeof(b);
5682 if (len > 32)
5683 strcpy(b, "too long, over 32 bytes");
5684 else {
5685 for (k = 0, n = 0; k < len && n < sb; ++k)
5686 n += scnprintf(b + n, sb - n, "%02x ",
5687 (u32)cmd[k]);
5688 }
Bart Van Assche458df782018-01-26 08:52:19 -08005689 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5690 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005691 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005692 if (fake_host_busy(scp))
5693 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005694 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005695 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5696 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005697
5698 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5699 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5700 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005701 if (unlikely(!devip)) {
5702 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005703 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005704 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005705 }
5706 na = oip->num_attached;
5707 r_pfp = oip->pfp;
5708 if (na) { /* multiple commands with this opcode */
5709 r_oip = oip;
5710 if (FF_SA & r_oip->flags) {
5711 if (F_SA_LOW & oip->flags)
5712 sa = 0x1f & cmd[1];
5713 else
5714 sa = get_unaligned_be16(cmd + 8);
5715 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5716 if (opcode == oip->opcode && sa == oip->sa)
5717 break;
5718 }
5719 } else { /* since no service action only check opcode */
5720 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5721 if (opcode == oip->opcode)
5722 break;
5723 }
5724 }
5725 if (k > na) {
5726 if (F_SA_LOW & r_oip->flags)
5727 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5728 else if (F_SA_HIGH & r_oip->flags)
5729 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5730 else
5731 mk_sense_invalid_opcode(scp);
5732 goto check_cond;
5733 }
5734 } /* else (when na==0) we assume the oip is a match */
5735 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005736 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005737 mk_sense_invalid_opcode(scp);
5738 goto check_cond;
5739 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005740 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005741 if (sdebug_verbose)
5742 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5743 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005744 mk_sense_invalid_opcode(scp);
5745 goto check_cond;
5746 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005747 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005748 u8 rem;
5749 int j;
5750
5751 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5752 rem = ~oip->len_mask[k] & cmd[k];
5753 if (rem) {
5754 for (j = 7; j >= 0; --j, rem <<= 1) {
5755 if (0x80 & rem)
5756 break;
5757 }
5758 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5759 goto check_cond;
5760 }
5761 }
5762 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005763 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005764 find_first_bit(devip->uas_bm,
5765 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005766 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005767 if (errsts)
5768 goto check_cond;
5769 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005770 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005771 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005772 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005773 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5774 "%s\n", my_name, "initializing command "
5775 "required");
5776 errsts = check_condition_result;
5777 goto fini;
5778 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005779 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005780 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005781 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005782 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005783 return 0; /* ignore command: make trouble */
5784 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005785 if (likely(oip->pfp))
Martin Wilckf66b8512018-02-14 11:05:57 +01005786 pfp = oip->pfp; /* calls a resp_* function */
5787 else
5788 pfp = r_pfp; /* if leaf function ptr NULL, try the root's */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005789
5790fini:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005791 if (F_DELAY_OVERR & flags)
Martin Wilckf66b8512018-02-14 11:05:57 +01005792 return schedule_resp(scp, devip, errsts, pfp, 0, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05005793 else if ((sdebug_jdelay || sdebug_ndelay) && (flags & F_LONG_DELAY)) {
5794 /*
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04005795 * If any delay is active, for F_SSU_DELAY want at least 1
Douglas Gilbert80c49562018-02-09 21:36:39 -05005796 * second and if sdebug_jdelay>0 want a long delay of that
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04005797 * many seconds; for F_SYNC_DELAY want 1/20 of that.
Douglas Gilbert80c49562018-02-09 21:36:39 -05005798 */
5799 int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04005800 int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
Douglas Gilbert80c49562018-02-09 21:36:39 -05005801
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04005802 jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
Martin Wilckf66b8512018-02-14 11:05:57 +01005803 return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05005804 } else
Martin Wilckf66b8512018-02-14 11:05:57 +01005805 return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
Douglas Gilbert10bde982018-01-10 16:57:31 -05005806 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005807check_cond:
Martin Wilckf66b8512018-02-14 11:05:57 +01005808 return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005809err_out:
Martin Wilckf66b8512018-02-14 11:05:57 +01005810 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005811}
5812
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005813static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005814 .show_info = scsi_debug_show_info,
5815 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005816 .proc_name = sdebug_proc_name,
5817 .name = "SCSI DEBUG",
5818 .info = scsi_debug_info,
5819 .slave_alloc = scsi_debug_slave_alloc,
5820 .slave_configure = scsi_debug_slave_configure,
5821 .slave_destroy = scsi_debug_slave_destroy,
5822 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005823 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005824 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005825 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005826 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005827 .eh_target_reset_handler = scsi_debug_target_reset,
5828 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005829 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005830 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005831 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005832 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005833 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005834 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005835 .use_clustering = DISABLE_CLUSTERING,
5836 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005837 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005838};
5839
John Pittman91d4c752018-02-09 21:12:43 -05005840static int sdebug_driver_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005842 int error = 0;
5843 struct sdebug_host_info *sdbg_host;
5844 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005845 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846
5847 sdbg_host = to_sdebug_host(dev);
5848
Douglas Gilbert773642d2016-04-25 12:16:28 -04005849 sdebug_driver_template.can_queue = sdebug_max_queue;
5850 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005851 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005852 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5853 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005854 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005855 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005857 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005858 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005859 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005860 my_name, submit_queues, nr_cpu_ids);
5861 submit_queues = nr_cpu_ids;
5862 }
5863 /* Decide whether to tell scsi subsystem that we want mq */
5864 /* Following should give the same answer for each host */
Bart Van Assche458df782018-01-26 08:52:19 -08005865 if (shost_use_blk_mq(hpnt))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005866 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867
Douglas Gilbert9a051012017-12-23 12:48:10 -05005868 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005870 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5871 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005873 hpnt->max_id = sdebug_num_tgts;
5874 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005875 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005877 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005878
Douglas Gilbert773642d2016-04-25 12:16:28 -04005879 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005880
Christoph Hellwig8475c812016-09-11 19:35:41 +02005881 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005882 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005883 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005884 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005885 break;
5886
Christoph Hellwig8475c812016-09-11 19:35:41 +02005887 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005888 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005889 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005890 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005891 break;
5892
Christoph Hellwig8475c812016-09-11 19:35:41 +02005893 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005894 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005895 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005896 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005897 break;
5898
5899 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005900 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005901 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005902 break;
5903 }
5904
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005905 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005906
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005907 if (have_dif_prot || sdebug_dix)
5908 pr_info("host protection%s%s%s%s%s%s%s\n",
5909 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5910 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5911 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5912 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5913 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5914 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5915 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005916
Douglas Gilbert773642d2016-04-25 12:16:28 -04005917 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005918 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5919 else
5920 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5921
Douglas Gilbert773642d2016-04-25 12:16:28 -04005922 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5923 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005924 if (sdebug_every_nth) /* need stats counters for every_nth */
5925 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005926 error = scsi_add_host(hpnt, &sdbg_host->dev);
5927 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005928 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005929 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005931 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 scsi_scan_host(hpnt);
5933
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005934 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935}
5936
John Pittman91d4c752018-02-09 21:12:43 -05005937static int sdebug_driver_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005939 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005940 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941
5942 sdbg_host = to_sdebug_host(dev);
5943
5944 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005945 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 return -ENODEV;
5947 }
5948
Douglas Gilbert9a051012017-12-23 12:48:10 -05005949 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005951 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5952 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005953 list_del(&sdbg_devinfo->dev_list);
5954 kfree(sdbg_devinfo);
5955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956
Douglas Gilbert9a051012017-12-23 12:48:10 -05005957 scsi_host_put(sdbg_host->shost);
5958 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959}
5960
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005961static int pseudo_lld_bus_match(struct device *dev,
5962 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005964 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005966
5967static struct bus_type pseudo_lld_bus = {
5968 .name = "pseudo",
5969 .match = pseudo_lld_bus_match,
5970 .probe = sdebug_driver_probe,
5971 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005972 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005973};