blob: 905501075ec6d59f6d1a7b397f53f1f4ba42065e [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 Gilbert80c49562018-02-09 21:36:39 -0500237#define F_LONG_DELAY 0x1000
Douglas Gilbertfd321192016-04-25 12:16:33 -0400238
239#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500240#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400241#define FF_SA (F_SA_HIGH | F_SA_LOW)
242
243#define SDEBUG_MAX_PARTS 4
244
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400245#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400246
247
248struct sdebug_dev_info {
249 struct list_head dev_list;
250 unsigned int channel;
251 unsigned int target;
252 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200253 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400254 struct sdebug_host_info *sdbg_host;
255 unsigned long uas_bm[1];
256 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400257 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400258 bool used;
259};
260
261struct sdebug_host_info {
262 struct list_head host_list;
263 struct Scsi_Host *shost;
264 struct device dev;
265 struct list_head dev_info_list;
266};
267
268#define to_sdebug_host(d) \
269 container_of(d, struct sdebug_host_info, dev)
270
Douglas Gilbert10bde982018-01-10 16:57:31 -0500271enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
272 SDEB_DEFER_WQ = 2};
273
Douglas Gilbertfd321192016-04-25 12:16:33 -0400274struct sdebug_defer {
275 struct hrtimer hrt;
276 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400277 int sqa_idx; /* index of sdebug_queue array */
278 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
279 int issuing_cpu;
Douglas Gilbert10bde982018-01-10 16:57:31 -0500280 bool init_hrt;
281 bool init_wq;
282 enum sdeb_defer_type defer_t;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400283};
284
285struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400286 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
287 * instance indicates this slot is in use.
288 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400289 struct sdebug_defer *sd_dp;
290 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400291 unsigned int inj_recovered:1;
292 unsigned int inj_transport:1;
293 unsigned int inj_dif:1;
294 unsigned int inj_dix:1;
295 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800296 unsigned int inj_host_busy:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400297};
298
Douglas Gilbertc4837392016-05-06 00:40:26 -0400299struct sdebug_queue {
300 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
301 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
302 spinlock_t qc_lock;
303 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400304};
305
Douglas Gilbertc4837392016-05-06 00:40:26 -0400306static atomic_t sdebug_cmnd_count; /* number of incoming commands */
307static atomic_t sdebug_completions; /* count of deferred completions */
308static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
309static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
310
Douglas Gilbertfd321192016-04-25 12:16:33 -0400311struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400312 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
313 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400314 u8 opcode; /* if num_attached > 0, preferred */
315 u16 sa; /* service action */
316 u32 flags; /* OR-ed set of SDEB_F_* */
317 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
318 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500319 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
320 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400321};
322
323/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500324enum sdeb_opcode_index {
325 SDEB_I_INVALID_OPCODE = 0,
326 SDEB_I_INQUIRY = 1,
327 SDEB_I_REPORT_LUNS = 2,
328 SDEB_I_REQUEST_SENSE = 3,
329 SDEB_I_TEST_UNIT_READY = 4,
330 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
331 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
332 SDEB_I_LOG_SENSE = 7,
333 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
334 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
335 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
336 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500337 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
338 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500339 SDEB_I_MAINT_IN = 14,
340 SDEB_I_MAINT_OUT = 15,
341 SDEB_I_VERIFY = 16, /* 10 only */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500342 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500343 SDEB_I_RESERVE = 18, /* 6, 10 */
344 SDEB_I_RELEASE = 19, /* 6, 10 */
345 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
346 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
347 SDEB_I_ATA_PT = 22, /* 12, 16 */
348 SDEB_I_SEND_DIAG = 23,
349 SDEB_I_UNMAP = 24,
350 SDEB_I_XDWRITEREAD = 25, /* 10 only */
351 SDEB_I_WRITE_BUFFER = 26,
352 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
Douglas Gilbert80c49562018-02-09 21:36:39 -0500353 SDEB_I_SYNC_CACHE = 28, /* 10, 16 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500354 SDEB_I_COMP_WRITE = 29,
Douglas Gilbert9a051012017-12-23 12:48:10 -0500355 SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500356};
357
Douglas Gilbertc4837392016-05-06 00:40:26 -0400358
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500359static const unsigned char opcode_ind_arr[256] = {
360/* 0x0; 0x0->0x1f: 6 byte cdbs */
361 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
362 0, 0, 0, 0,
363 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
364 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
365 SDEB_I_RELEASE,
366 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
367 SDEB_I_ALLOW_REMOVAL, 0,
368/* 0x20; 0x20->0x3f: 10 byte cdbs */
369 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
370 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
371 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
372 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
373/* 0x40; 0x40->0x5f: 10 byte cdbs */
374 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
375 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
376 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
377 SDEB_I_RELEASE,
378 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400379/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
382 0, SDEB_I_VARIABLE_LEN,
383/* 0x80; 0x80->0x9f: 16 byte cdbs */
384 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
385 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500386 0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500387 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 -0500388/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
389 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
390 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500391 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
392 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500393 0, 0, 0, 0, 0, 0, 0, 0,
394 0, 0, 0, 0, 0, 0, 0, 0,
395/* 0xc0; 0xc0->0xff: vendor specific */
396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
400};
401
Douglas Gilbert80c49562018-02-09 21:36:39 -0500402/*
403 * The following "response" functions return the SCSI mid-level's 4 byte
404 * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
405 * command completion, they can mask their return value with
406 * SDEG_RES_IMMED_MASK .
407 */
408#define SDEG_RES_IMMED_MASK 0x40000000
409
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500410static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
411static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
412static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
413static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
414static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
415static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
416static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
417static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
418static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500419static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500420static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
421static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
422static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
423static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
424static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500425static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
426static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500427static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
428static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
429static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500430static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500431static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert80c49562018-02-09 21:36:39 -0500432static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500433
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500434/*
435 * The following are overflow arrays for cdbs that "hit" the same index in
436 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
437 * should be placed in opcode_info_arr[], the others should be placed here.
438 */
439static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500440 {0, 0x1a, 0, F_D_IN, NULL, NULL,
441 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
442};
443
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500444static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500445 {0, 0x15, 0, F_D_OUT, NULL, NULL,
446 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
447};
448
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500449static const struct opcode_info_t read_iarr[] = {
450 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500451 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500452 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500453 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500454 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500455 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500456 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500457 0xc7, 0, 0, 0, 0} },
458};
459
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500460static const struct opcode_info_t write_iarr[] = {
461 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
462 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
463 0, 0, 0, 0, 0, 0} },
464 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
465 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
466 0, 0, 0} },
467 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
468 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
469 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500470};
471
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500472static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500473 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
474 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500475 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500476};
477
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500478static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
479 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500480 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500481 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500482 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
483 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
484 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500485};
486
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500487static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500488 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500489 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500490 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500491 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500492 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500493 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500494};
495
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500496static const struct opcode_info_t write_same_iarr[] = {
497 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500498 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500499 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500500};
501
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500502static const struct opcode_info_t reserve_iarr[] = {
503 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500504 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
505};
506
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500507static const struct opcode_info_t release_iarr[] = {
508 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500509 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
510};
511
Douglas Gilbert80c49562018-02-09 21:36:39 -0500512static const struct opcode_info_t sync_cache_iarr[] = {
513 {0, 0x91, 0, F_LONG_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
514 {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
515 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */
516};
517
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500518
519/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
520 * plus the terminating elements for logic that scans this table such as
521 * REPORT SUPPORTED OPERATION CODES. */
522static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
523/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500524 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500525 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500526 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500527 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
528 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
529 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500530 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500531 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
532 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
533 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
534 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500535/* 5 */
536 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
537 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
538 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
539 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
540 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
541 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
542 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500543 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
544 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500545 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500546 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
547 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500548 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
549 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
550 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500551/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500552 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
553 resp_write_dt0, write_iarr, /* WRITE(16) */
554 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500555 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
556 {0, 0x1b, 0, F_LONG_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500557 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500558 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
559 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
560 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
561 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500562 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
563 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
564 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500565 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
566 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
567 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
568 0xff, 0, 0xc7, 0, 0, 0, 0} },
569/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500570 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
571 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500572 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500573 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
574 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500575 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
576 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
577 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
578 0xff, 0xff} },
579 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
580 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500581 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
582 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500583 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
584 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500585 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
586 0} },
587/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500588 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
589 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500590 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
591 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
592 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
593 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
594 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
595 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500596 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500597 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500598/* 25 */
599 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500600 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500601 0, 0, 0, 0, 0, 0} }, /* XDWRITEREAD(10) */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500602 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
603 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
604 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500605 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
606 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
607 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
608 0, 0, 0, 0, 0} },
Douglas Gilbert80c49562018-02-09 21:36:39 -0500609 {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_LONG_DELAY | F_M_ACCESS,
610 resp_sync_cache, sync_cache_iarr,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500611 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500612 0, 0, 0, 0} }, /* SYNC_CACHE (10) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500613 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500614 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500615 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500616
617/* 30 */
618 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
619 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
620};
621
Douglas Gilbert773642d2016-04-25 12:16:28 -0400622static int sdebug_add_host = DEF_NUM_HOST;
623static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500624static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400625static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400626static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
627static int sdebug_dif = DEF_DIF;
628static int sdebug_dix = DEF_DIX;
629static int sdebug_dsense = DEF_D_SENSE;
630static int sdebug_every_nth = DEF_EVERY_NTH;
631static int sdebug_fake_rw = DEF_FAKE_RW;
632static unsigned int sdebug_guard = DEF_GUARD;
633static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
634static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400635static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Laurence Obermand9da8912018-02-03 13:38:35 -0500636static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
637static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400638static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400639static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400640static int sdebug_no_lun_0 = DEF_NO_LUN_0;
641static int sdebug_no_uld;
642static int sdebug_num_parts = DEF_NUM_PARTS;
643static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
644static int sdebug_opt_blks = DEF_OPT_BLKS;
645static int sdebug_opts = DEF_OPTS;
646static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100647static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400648static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400649static int sdebug_scsi_level = DEF_SCSI_LEVEL;
650static int sdebug_sector_size = DEF_SECTOR_SIZE;
651static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
652static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
653static unsigned int sdebug_lbpu = DEF_LBPU;
654static unsigned int sdebug_lbpws = DEF_LBPWS;
655static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
656static unsigned int sdebug_lbprz = DEF_LBPRZ;
657static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
658static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
659static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
660static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
661static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400662static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400663static bool sdebug_removable = DEF_REMOVABLE;
664static bool sdebug_clustering;
665static bool sdebug_host_lock = DEF_HOST_LOCK;
666static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500667static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400668static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400669static bool have_dif_prot;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400670static bool sdebug_statistics = DEF_STATISTICS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400672static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673static sector_t sdebug_capacity; /* in sectors */
674
675/* old BIOS stuff, kernel may get rid of them but some mode sense pages
676 may still need them */
677static int sdebug_heads; /* heads per disk */
678static int sdebug_cylinders_per; /* cylinders per surface */
679static int sdebug_sectors_per; /* sectors per cylinder */
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681static LIST_HEAD(sdebug_host_list);
682static DEFINE_SPINLOCK(sdebug_host_list_lock);
683
Douglas Gilbertfd321192016-04-25 12:16:33 -0400684static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200685static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400686static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Martin K. Petersen44d92692009-10-15 14:45:27 -0400688static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400689static int num_aborts;
690static int num_dev_resets;
691static int num_target_resets;
692static int num_bus_resets;
693static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500694static int dix_writes;
695static int dix_reads;
696static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Douglas Gilbertc4837392016-05-06 00:40:26 -0400698static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
699static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701static DEFINE_RWLOCK(atomic_rw);
702
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400703static char sdebug_proc_name[] = MY_NAME;
704static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706static struct bus_type pseudo_lld_bus;
707
708static struct device_driver sdebug_driverfs_driver = {
709 .name = sdebug_proc_name,
710 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711};
712
713static const int check_condition_result =
714 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
715
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500716static const int illegal_condition_result =
717 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
718
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400719static const int device_qfull_result =
720 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
721
Douglas Gilbertfd321192016-04-25 12:16:33 -0400722
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400723/* Only do the extra work involved in logical block provisioning if one or
724 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
725 * real reads and writes (i.e. not skipping them for speed).
726 */
727static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400728{
729 return 0 == sdebug_fake_rw &&
730 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
731}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400732
Akinobu Mita14faa942013-09-18 21:27:24 +0900733static void *fake_store(unsigned long long lba)
734{
735 lba = do_div(lba, sdebug_store_sectors);
736
Douglas Gilbert773642d2016-04-25 12:16:28 -0400737 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900738}
739
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200740static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900741{
Arnd Bergmann49413112015-11-20 17:38:28 +0100742 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900743
744 return dif_storep + sector;
745}
746
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900747static void sdebug_max_tgts_luns(void)
748{
749 struct sdebug_host_info *sdbg_host;
750 struct Scsi_Host *hpnt;
751
752 spin_lock(&sdebug_host_list_lock);
753 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
754 hpnt = sdbg_host->shost;
755 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400756 (sdebug_num_tgts > hpnt->this_id))
757 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900758 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400759 hpnt->max_id = sdebug_num_tgts;
760 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300761 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900762 }
763 spin_unlock(&sdebug_host_list_lock);
764}
765
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500766enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
767
768/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400769static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
770 enum sdeb_cmd_data c_d,
771 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500772{
773 unsigned char *sbuff;
774 u8 sks[4];
775 int sl, asc;
776
777 sbuff = scp->sense_buffer;
778 if (!sbuff) {
779 sdev_printk(KERN_ERR, scp->device,
780 "%s: sense_buffer is NULL\n", __func__);
781 return;
782 }
783 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
784 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400785 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500786 memset(sks, 0, sizeof(sks));
787 sks[0] = 0x80;
788 if (c_d)
789 sks[0] |= 0x40;
790 if (in_bit >= 0) {
791 sks[0] |= 0x8;
792 sks[0] |= 0x7 & in_bit;
793 }
794 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400795 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500796 sl = sbuff[7] + 8;
797 sbuff[7] = sl;
798 sbuff[sl] = 0x2;
799 sbuff[sl + 1] = 0x6;
800 memcpy(sbuff + sl + 4, sks, 3);
801 } else
802 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400803 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500804 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
805 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
806 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
807}
808
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400809static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900810{
811 unsigned char *sbuff;
812
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400813 sbuff = scp->sense_buffer;
814 if (!sbuff) {
815 sdev_printk(KERN_ERR, scp->device,
816 "%s: sense_buffer is NULL\n", __func__);
817 return;
818 }
819 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900820
Douglas Gilbert773642d2016-04-25 12:16:28 -0400821 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900822
Douglas Gilbert773642d2016-04-25 12:16:28 -0400823 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400824 sdev_printk(KERN_INFO, scp->device,
825 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
826 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900827}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Douglas Gilbertfd321192016-04-25 12:16:33 -0400829static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500830{
831 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
832}
833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
835{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400836 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400837 if (0x1261 == cmd)
838 sdev_printk(KERN_INFO, dev,
839 "%s: BLKFLSBUF [0x1261]\n", __func__);
840 else if (0x5331 == cmd)
841 sdev_printk(KERN_INFO, dev,
842 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
843 __func__);
844 else
845 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
846 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 }
848 return -EINVAL;
849 /* return -ENOTTY; // correct return but upsets fdisk */
850}
851
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500852static void config_cdb_len(struct scsi_device *sdev)
853{
854 switch (sdebug_cdb_len) {
855 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
856 sdev->use_10_for_rw = false;
857 sdev->use_16_for_rw = false;
858 sdev->use_10_for_ms = false;
859 break;
860 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
861 sdev->use_10_for_rw = true;
862 sdev->use_16_for_rw = false;
863 sdev->use_10_for_ms = false;
864 break;
865 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
866 sdev->use_10_for_rw = true;
867 sdev->use_16_for_rw = false;
868 sdev->use_10_for_ms = true;
869 break;
870 case 16:
871 sdev->use_10_for_rw = false;
872 sdev->use_16_for_rw = true;
873 sdev->use_10_for_ms = true;
874 break;
875 case 32: /* No knobs to suggest this so same as 16 for now */
876 sdev->use_10_for_rw = false;
877 sdev->use_16_for_rw = true;
878 sdev->use_10_for_ms = true;
879 break;
880 default:
881 pr_warn("unexpected cdb_len=%d, force to 10\n",
882 sdebug_cdb_len);
883 sdev->use_10_for_rw = true;
884 sdev->use_16_for_rw = false;
885 sdev->use_10_for_ms = false;
886 sdebug_cdb_len = 10;
887 break;
888 }
889}
890
891static void all_config_cdb_len(void)
892{
893 struct sdebug_host_info *sdbg_host;
894 struct Scsi_Host *shost;
895 struct scsi_device *sdev;
896
897 spin_lock(&sdebug_host_list_lock);
898 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
899 shost = sdbg_host->shost;
900 shost_for_each_device(sdev, shost) {
901 config_cdb_len(sdev);
902 }
903 }
904 spin_unlock(&sdebug_host_list_lock);
905}
906
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500907static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
908{
909 struct sdebug_host_info *sdhp;
910 struct sdebug_dev_info *dp;
911
912 spin_lock(&sdebug_host_list_lock);
913 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
914 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
915 if ((devip->sdbg_host == dp->sdbg_host) &&
916 (devip->target == dp->target))
917 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
918 }
919 }
920 spin_unlock(&sdebug_host_list_lock);
921}
922
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400923static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400925 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400926
927 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
928 if (k != SDEBUG_NUM_UAS) {
929 const char *cp = NULL;
930
931 switch (k) {
932 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400933 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
934 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400935 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400936 cp = "power on reset";
937 break;
938 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400939 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
940 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400941 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400942 cp = "bus reset";
943 break;
944 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400945 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
946 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400947 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400948 cp = "mode parameters changed";
949 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500950 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400951 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
952 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400953 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500954 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500955 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500956 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400957 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400958 TARGET_CHANGED_ASC,
959 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400960 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500961 cp = "microcode has been changed";
962 break;
963 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400964 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500965 TARGET_CHANGED_ASC,
966 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400967 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500968 cp = "microcode has been changed without reset";
969 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500970 case SDEBUG_UA_LUNS_CHANGED:
971 /*
972 * SPC-3 behavior is to report a UNIT ATTENTION with
973 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
974 * on the target, until a REPORT LUNS command is
975 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400976 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500977 * values as struct scsi_device->scsi_level.
978 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400979 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500980 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400981 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500982 TARGET_CHANGED_ASC,
983 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400984 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500985 cp = "reported luns data has changed";
986 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400987 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400988 pr_warn("unexpected unit attention code=%d\n", k);
989 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400990 cp = "unknown";
991 break;
992 }
993 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400994 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400995 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400996 "%s reports: Unit attention: %s\n",
997 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 return check_condition_result;
999 }
1000 return 0;
1001}
1002
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001003/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001004static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 int arr_len)
1006{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001007 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001008 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001010 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001012 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -04001013 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001014
1015 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
1016 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -07001017 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return 0;
1020}
1021
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001022/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1023 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1024 * calls, not required to write in ascending offset order. Assumes resid
1025 * set to scsi_bufflen() prior to any calls.
1026 */
1027static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1028 int arr_len, unsigned int off_dst)
1029{
1030 int act_len, n;
1031 struct scsi_data_buffer *sdb = scsi_in(scp);
1032 off_t skip = off_dst;
1033
1034 if (sdb->length <= off_dst)
1035 return 0;
1036 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1037 return DID_ERROR << 16;
1038
1039 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1040 arr, arr_len, skip);
1041 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1042 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1043 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1044 sdb->resid = min(sdb->resid, n);
1045 return 0;
1046}
1047
1048/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1049 * 'arr' or -1 if error.
1050 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001051static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1052 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001054 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001056 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001058
1059 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060}
1061
1062
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001063static char sdebug_inq_vendor_id[9] = "Linux ";
1064static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001065static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001066/* Use some locally assigned NAAs for SAS addresses. */
1067static const u64 naa3_comp_a = 0x3222222000000000ULL;
1068static const u64 naa3_comp_b = 0x3333333000000000ULL;
1069static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001071/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001072static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1073 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001074 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001075 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001077 int num, port_a;
1078 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001080 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 /* T10 vendor identifier field format (faked) */
1082 arr[0] = 0x2; /* ASCII */
1083 arr[1] = 0x1;
1084 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001085 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1086 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1088 num = 8 + 16 + dev_id_str_len;
1089 arr[3] = num;
1090 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001092 if (sdebug_uuid_ctl) {
1093 /* Locally assigned UUID */
1094 arr[num++] = 0x1; /* binary (not necessarily sas) */
1095 arr[num++] = 0xa; /* PIV=0, lu, naa */
1096 arr[num++] = 0x0;
1097 arr[num++] = 0x12;
1098 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1099 arr[num++] = 0x0;
1100 memcpy(arr + num, lu_name, 16);
1101 num += 16;
1102 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001103 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001104 arr[num++] = 0x1; /* binary (not necessarily sas) */
1105 arr[num++] = 0x3; /* PIV=0, lu, naa */
1106 arr[num++] = 0x0;
1107 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001108 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001109 num += 8;
1110 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001111 /* Target relative port number */
1112 arr[num++] = 0x61; /* proto=sas, binary */
1113 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1114 arr[num++] = 0x0; /* reserved */
1115 arr[num++] = 0x4; /* length */
1116 arr[num++] = 0x0; /* reserved */
1117 arr[num++] = 0x0; /* reserved */
1118 arr[num++] = 0x0;
1119 arr[num++] = 0x1; /* relative port A */
1120 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001121 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001122 arr[num++] = 0x61; /* proto=sas, binary */
1123 arr[num++] = 0x93; /* piv=1, target port, naa */
1124 arr[num++] = 0x0;
1125 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001126 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001127 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001128 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001129 arr[num++] = 0x61; /* proto=sas, binary */
1130 arr[num++] = 0x95; /* piv=1, target port group id */
1131 arr[num++] = 0x0;
1132 arr[num++] = 0x4;
1133 arr[num++] = 0;
1134 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001135 put_unaligned_be16(port_group_id, arr + num);
1136 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001137 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001138 arr[num++] = 0x61; /* proto=sas, binary */
1139 arr[num++] = 0xa3; /* piv=1, target device, naa */
1140 arr[num++] = 0x0;
1141 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001142 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001143 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001144 /* SCSI name string: Target device identifier */
1145 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1146 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1147 arr[num++] = 0x0;
1148 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001149 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001150 num += 12;
1151 snprintf(b, sizeof(b), "%08X", target_dev_id);
1152 memcpy(arr + num, b, 8);
1153 num += 8;
1154 memset(arr + num, 0, 4);
1155 num += 4;
1156 return num;
1157}
1158
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001159static unsigned char vpd84_data[] = {
1160/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1161 0x22,0x22,0x22,0x0,0xbb,0x1,
1162 0x22,0x22,0x22,0x0,0xbb,0x2,
1163};
1164
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001165/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001166static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001167{
1168 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1169 return sizeof(vpd84_data);
1170}
1171
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001172/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001173static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001174{
1175 int num = 0;
John Pittman91d4c752018-02-09 21:12:43 -05001176 const char *na1 = "https://www.kernel.org/config";
1177 const char *na2 = "http://www.kernel.org/log";
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001178 int plen, olen;
1179
1180 arr[num++] = 0x1; /* lu, storage config */
1181 arr[num++] = 0x0; /* reserved */
1182 arr[num++] = 0x0;
1183 olen = strlen(na1);
1184 plen = olen + 1;
1185 if (plen % 4)
1186 plen = ((plen / 4) + 1) * 4;
1187 arr[num++] = plen; /* length, null termianted, padded */
1188 memcpy(arr + num, na1, olen);
1189 memset(arr + num + olen, 0, plen - olen);
1190 num += plen;
1191
1192 arr[num++] = 0x4; /* lu, logging */
1193 arr[num++] = 0x0; /* reserved */
1194 arr[num++] = 0x0;
1195 olen = strlen(na2);
1196 plen = olen + 1;
1197 if (plen % 4)
1198 plen = ((plen / 4) + 1) * 4;
1199 arr[num++] = plen; /* length, null terminated, padded */
1200 memcpy(arr + num, na2, olen);
1201 memset(arr + num + olen, 0, plen - olen);
1202 num += plen;
1203
1204 return num;
1205}
1206
1207/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001208static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001209{
1210 int num = 0;
1211 int port_a, port_b;
1212
1213 port_a = target_dev_id + 1;
1214 port_b = port_a + 1;
1215 arr[num++] = 0x0; /* reserved */
1216 arr[num++] = 0x0; /* reserved */
1217 arr[num++] = 0x0;
1218 arr[num++] = 0x1; /* relative port 1 (primary) */
1219 memset(arr + num, 0, 6);
1220 num += 6;
1221 arr[num++] = 0x0;
1222 arr[num++] = 12; /* length tp descriptor */
1223 /* naa-5 target port identifier (A) */
1224 arr[num++] = 0x61; /* proto=sas, binary */
1225 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1226 arr[num++] = 0x0; /* reserved */
1227 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001228 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001229 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001230 arr[num++] = 0x0; /* reserved */
1231 arr[num++] = 0x0; /* reserved */
1232 arr[num++] = 0x0;
1233 arr[num++] = 0x2; /* relative port 2 (secondary) */
1234 memset(arr + num, 0, 6);
1235 num += 6;
1236 arr[num++] = 0x0;
1237 arr[num++] = 12; /* length tp descriptor */
1238 /* naa-5 target port identifier (B) */
1239 arr[num++] = 0x61; /* proto=sas, binary */
1240 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1241 arr[num++] = 0x0; /* reserved */
1242 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001243 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001244 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001245
1246 return num;
1247}
1248
1249
1250static unsigned char vpd89_data[] = {
1251/* from 4th byte */ 0,0,0,0,
1252'l','i','n','u','x',' ',' ',' ',
1253'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1254'1','2','3','4',
12550x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12560xec,0,0,0,
12570x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12580,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12590x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12600x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12610x53,0x41,
12620x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12630x20,0x20,
12640x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12650x10,0x80,
12660,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12670x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12680x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12690,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12700x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12710x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12720,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12730,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12760x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12770,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12780xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12790,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
12800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1292};
1293
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001294/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001295static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001296{
1297 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1298 return sizeof(vpd89_data);
1299}
1300
1301
1302static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001303 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1304 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1305 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1306 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001307};
1308
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001309/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001310static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001311{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001312 unsigned int gran;
1313
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001314 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001315
1316 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001317 if (sdebug_opt_xferlen_exp != 0 &&
1318 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1319 gran = 1 << sdebug_opt_xferlen_exp;
1320 else
1321 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001322 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001323
1324 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001325 if (sdebug_store_sectors > 0x400)
1326 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001327
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001328 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001329 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001330
Douglas Gilbert773642d2016-04-25 12:16:28 -04001331 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001332 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001333 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001334
1335 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001336 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001337 }
1338
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001339 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001340 if (sdebug_unmap_alignment) {
1341 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001342 arr[28] |= 0x80; /* UGAVALID */
1343 }
1344
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001345 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001346 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001347
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001348 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001349 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001350
1351 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001352
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001353 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354}
1355
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001356/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001357static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001358{
1359 memset(arr, 0, 0x3c);
1360 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001361 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1362 arr[2] = 0;
1363 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001364
1365 return 0x3c;
1366}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001368/* Logical block provisioning VPD page (SBC-4) */
1369static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001370{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001371 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001372 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001373 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001374 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001375 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001376 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001377 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001378 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001379 if (sdebug_lbprz && scsi_debug_lbp())
1380 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1381 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1382 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1383 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001384 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001385}
1386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001388#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001390static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391{
1392 unsigned char pq_pdt;
John Pittman91d4c752018-02-09 21:12:43 -05001393 unsigned char *arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001394 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001395 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001396 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Douglas Gilbert773642d2016-04-25 12:16:28 -04001398 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001399 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1400 if (! arr)
1401 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001402 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001403 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001404 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001405 pq_pdt = TYPE_WLUN; /* present, wlun */
1406 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1407 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001408 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001409 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 arr[0] = pq_pdt;
1411 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001412 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001413 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 return check_condition_result;
1415 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001416 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001417 char lu_id_str[6];
1418 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001420 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1421 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001422 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001423 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001424 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001425 (devip->target * 1000) + devip->lun);
1426 target_dev_id = ((host_no + 1) * 2000) +
1427 (devip->target * 1000) - 3;
1428 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001430 arr[1] = cmd[2]; /*sanity */
1431 n = 4;
1432 arr[n++] = 0x0; /* this page */
1433 arr[n++] = 0x80; /* unit serial number */
1434 arr[n++] = 0x83; /* device identification */
1435 arr[n++] = 0x84; /* software interface ident. */
1436 arr[n++] = 0x85; /* management network addresses */
1437 arr[n++] = 0x86; /* extended inquiry */
1438 arr[n++] = 0x87; /* mode page policy */
1439 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001440 if (is_disk) { /* SBC only */
1441 arr[n++] = 0x89; /* ATA information */
1442 arr[n++] = 0xb0; /* Block limits */
1443 arr[n++] = 0xb1; /* Block characteristics */
1444 arr[n++] = 0xb2; /* Logical Block Prov */
1445 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001446 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001448 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001450 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001452 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001453 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1454 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001455 lu_id_str, len,
1456 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001457 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1458 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001459 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001460 } else if (0x85 == cmd[2]) { /* Management network addresses */
1461 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001462 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001463 } else if (0x86 == cmd[2]) { /* extended inquiry */
1464 arr[1] = cmd[2]; /*sanity */
1465 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001466 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001467 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001468 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001469 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1470 else
1471 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001472 arr[5] = 0x7; /* head of q, ordered + simple q's */
1473 } else if (0x87 == cmd[2]) { /* mode page policy */
1474 arr[1] = cmd[2]; /*sanity */
1475 arr[3] = 0x8; /* number of following entries */
1476 arr[4] = 0x2; /* disconnect-reconnect mp */
1477 arr[6] = 0x80; /* mlus, shared */
1478 arr[8] = 0x18; /* protocol specific lu */
1479 arr[10] = 0x82; /* mlus, per initiator port */
1480 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1481 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001482 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1483 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001485 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001486 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001487 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001488 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001489 arr[3] = inquiry_vpd_b0(&arr[4]);
1490 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001491 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001492 arr[3] = inquiry_vpd_b1(&arr[4]);
1493 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001494 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001495 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001497 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001498 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 return check_condition_result;
1500 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001501 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001502 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001503 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001504 kfree(arr);
1505 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 }
1507 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001508 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1509 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 arr[3] = 2; /* response_data_format==2 */
1511 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001512 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001513 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001514 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001515 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001517 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001518 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1519 memcpy(&arr[16], sdebug_inq_product_id, 16);
1520 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001521 /* Use Vendor Specific area to place driver date in ASCII hex */
1522 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001524 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1525 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001526 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001527 if (is_disk) { /* SBC-4 no version claimed */
1528 put_unaligned_be16(0x600, arr + n);
1529 n += 2;
1530 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1531 put_unaligned_be16(0x525, arr + n);
1532 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001534 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001535 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001537 kfree(arr);
1538 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539}
1540
Douglas Gilbertfd321192016-04-25 12:16:33 -04001541static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1542 0, 0, 0x0, 0x0};
1543
John Pittman91d4c752018-02-09 21:12:43 -05001544static int resp_requests(struct scsi_cmnd *scp,
1545 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546{
John Pittman91d4c752018-02-09 21:12:43 -05001547 unsigned char *sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001548 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001549 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001550 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 int len = 18;
1552
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001553 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001554 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001555 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001556 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001557 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001558 arr[0] = 0x72;
1559 arr[1] = 0x0; /* NO_SENSE in sense_key */
1560 arr[2] = THRESHOLD_EXCEEDED;
1561 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001562 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001563 } else {
1564 arr[0] = 0x70;
1565 arr[2] = 0x0; /* NO_SENSE in sense_key */
1566 arr[7] = 0xa; /* 18 byte sense buffer */
1567 arr[12] = THRESHOLD_EXCEEDED;
1568 arr[13] = 0xff; /* TEST set and MRIE==6 */
1569 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001570 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001571 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001572 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001573 ; /* have sense and formats match */
1574 else if (arr[0] <= 0x70) {
1575 if (dsense) {
1576 memset(arr, 0, 8);
1577 arr[0] = 0x72;
1578 len = 8;
1579 } else {
1580 memset(arr, 0, 18);
1581 arr[0] = 0x70;
1582 arr[7] = 0xa;
1583 }
1584 } else if (dsense) {
1585 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001586 arr[0] = 0x72;
1587 arr[1] = sbuff[2]; /* sense key */
1588 arr[2] = sbuff[12]; /* asc */
1589 arr[3] = sbuff[13]; /* ascq */
1590 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001591 } else {
1592 memset(arr, 0, 18);
1593 arr[0] = 0x70;
1594 arr[2] = sbuff[1];
1595 arr[7] = 0xa;
1596 arr[12] = sbuff[1];
1597 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001598 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001599
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001600 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001601 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 return fill_from_dev_buffer(scp, arr, len);
1603}
1604
John Pittman91d4c752018-02-09 21:12:43 -05001605static int resp_start_stop(struct scsi_cmnd *scp,
1606 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001607{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001608 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001609 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001610
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001611 power_cond = (cmd[4] & 0xf0) >> 4;
1612 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001613 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001614 return check_condition_result;
1615 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001616 stop = !(cmd[4] & 1);
1617 atomic_xchg(&devip->stopped, stop);
Douglas Gilbert80c49562018-02-09 21:36:39 -05001618 return (cmd[1] & 0x1) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001619}
1620
FUJITA Tomonori28898872008-03-30 00:59:55 +09001621static sector_t get_sdebug_capacity(void)
1622{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001623 static const unsigned int gibibyte = 1073741824;
1624
1625 if (sdebug_virtual_gb > 0)
1626 return (sector_t)sdebug_virtual_gb *
1627 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001628 else
1629 return sdebug_store_sectors;
1630}
1631
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632#define SDEBUG_READCAP_ARR_SZ 8
John Pittman91d4c752018-02-09 21:12:43 -05001633static int resp_readcap(struct scsi_cmnd *scp,
1634 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635{
1636 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001637 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001639 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001640 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001642 if (sdebug_capacity < 0xffffffff) {
1643 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001644 put_unaligned_be32(capac, arr + 0);
1645 } else
1646 put_unaligned_be32(0xffffffff, arr + 0);
1647 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1649}
1650
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001651#define SDEBUG_READCAP16_ARR_SZ 32
John Pittman91d4c752018-02-09 21:12:43 -05001652static int resp_readcap16(struct scsi_cmnd *scp,
1653 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001654{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001655 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001656 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001657 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001658
Douglas Gilbert773642d2016-04-25 12:16:28 -04001659 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001660 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001661 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001662 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001663 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1664 put_unaligned_be32(sdebug_sector_size, arr + 8);
1665 arr[13] = sdebug_physblk_exp & 0xf;
1666 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001667
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001668 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001669 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001670 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1671 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1672 * in the wider field maps to 0 in this field.
1673 */
1674 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1675 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001676 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001677
Douglas Gilbert773642d2016-04-25 12:16:28 -04001678 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001679
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001680 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001681 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001682 arr[12] |= 1; /* PROT_EN */
1683 }
1684
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001685 return fill_from_dev_buffer(scp, arr,
1686 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1687}
1688
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001689#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1690
John Pittman91d4c752018-02-09 21:12:43 -05001691static int resp_report_tgtpgs(struct scsi_cmnd *scp,
1692 struct sdebug_dev_info *devip)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001693{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001694 unsigned char *cmd = scp->cmnd;
John Pittman91d4c752018-02-09 21:12:43 -05001695 unsigned char *arr;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001696 int host_no = devip->sdbg_host->shost->host_no;
1697 int n, ret, alen, rlen;
1698 int port_group_a, port_group_b, port_a, port_b;
1699
Douglas Gilbert773642d2016-04-25 12:16:28 -04001700 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001701 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1702 if (! arr)
1703 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001704 /*
1705 * EVPD page 0x88 states we have two ports, one
1706 * real and a fake port with no device connected.
1707 * So we create two port groups with one port each
1708 * and set the group with port B to unavailable.
1709 */
1710 port_a = 0x1; /* relative port A */
1711 port_b = 0x2; /* relative port B */
1712 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001713 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001714 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001715 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001716
1717 /*
1718 * The asymmetric access state is cycled according to the host_id.
1719 */
1720 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001721 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001722 arr[n++] = host_no % 3; /* Asymm access state */
1723 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001724 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001725 arr[n++] = 0x0; /* Active/Optimized path */
1726 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001727 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001728 put_unaligned_be16(port_group_a, arr + n);
1729 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001730 arr[n++] = 0; /* Reserved */
1731 arr[n++] = 0; /* Status code */
1732 arr[n++] = 0; /* Vendor unique */
1733 arr[n++] = 0x1; /* One port per group */
1734 arr[n++] = 0; /* Reserved */
1735 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001736 put_unaligned_be16(port_a, arr + n);
1737 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001738 arr[n++] = 3; /* Port unavailable */
1739 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001740 put_unaligned_be16(port_group_b, arr + n);
1741 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001742 arr[n++] = 0; /* Reserved */
1743 arr[n++] = 0; /* Status code */
1744 arr[n++] = 0; /* Vendor unique */
1745 arr[n++] = 0x1; /* One port per group */
1746 arr[n++] = 0; /* Reserved */
1747 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001748 put_unaligned_be16(port_b, arr + n);
1749 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001750
1751 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001752 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001753
1754 /*
1755 * Return the smallest value of either
1756 * - The allocated length
1757 * - The constructed command length
1758 * - The maximum array size
1759 */
1760 rlen = min(alen,n);
1761 ret = fill_from_dev_buffer(scp, arr,
1762 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1763 kfree(arr);
1764 return ret;
1765}
1766
Douglas Gilbertfd321192016-04-25 12:16:33 -04001767static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1768 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001769{
1770 bool rctd;
1771 u8 reporting_opts, req_opcode, sdeb_i, supp;
1772 u16 req_sa, u;
1773 u32 alloc_len, a_len;
1774 int k, offset, len, errsts, count, bump, na;
1775 const struct opcode_info_t *oip;
1776 const struct opcode_info_t *r_oip;
1777 u8 *arr;
1778 u8 *cmd = scp->cmnd;
1779
1780 rctd = !!(cmd[2] & 0x80);
1781 reporting_opts = cmd[2] & 0x7;
1782 req_opcode = cmd[3];
1783 req_sa = get_unaligned_be16(cmd + 4);
1784 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001785 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001786 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1787 return check_condition_result;
1788 }
1789 if (alloc_len > 8192)
1790 a_len = 8192;
1791 else
1792 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001793 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001794 if (NULL == arr) {
1795 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1796 INSUFF_RES_ASCQ);
1797 return check_condition_result;
1798 }
1799 switch (reporting_opts) {
1800 case 0: /* all commands */
1801 /* count number of commands */
1802 for (count = 0, oip = opcode_info_arr;
1803 oip->num_attached != 0xff; ++oip) {
1804 if (F_INV_OP & oip->flags)
1805 continue;
1806 count += (oip->num_attached + 1);
1807 }
1808 bump = rctd ? 20 : 8;
1809 put_unaligned_be32(count * bump, arr);
1810 for (offset = 4, oip = opcode_info_arr;
1811 oip->num_attached != 0xff && offset < a_len; ++oip) {
1812 if (F_INV_OP & oip->flags)
1813 continue;
1814 na = oip->num_attached;
1815 arr[offset] = oip->opcode;
1816 put_unaligned_be16(oip->sa, arr + offset + 2);
1817 if (rctd)
1818 arr[offset + 5] |= 0x2;
1819 if (FF_SA & oip->flags)
1820 arr[offset + 5] |= 0x1;
1821 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1822 if (rctd)
1823 put_unaligned_be16(0xa, arr + offset + 8);
1824 r_oip = oip;
1825 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1826 if (F_INV_OP & oip->flags)
1827 continue;
1828 offset += bump;
1829 arr[offset] = oip->opcode;
1830 put_unaligned_be16(oip->sa, arr + offset + 2);
1831 if (rctd)
1832 arr[offset + 5] |= 0x2;
1833 if (FF_SA & oip->flags)
1834 arr[offset + 5] |= 0x1;
1835 put_unaligned_be16(oip->len_mask[0],
1836 arr + offset + 6);
1837 if (rctd)
1838 put_unaligned_be16(0xa,
1839 arr + offset + 8);
1840 }
1841 oip = r_oip;
1842 offset += bump;
1843 }
1844 break;
1845 case 1: /* one command: opcode only */
1846 case 2: /* one command: opcode plus service action */
1847 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1848 sdeb_i = opcode_ind_arr[req_opcode];
1849 oip = &opcode_info_arr[sdeb_i];
1850 if (F_INV_OP & oip->flags) {
1851 supp = 1;
1852 offset = 4;
1853 } else {
1854 if (1 == reporting_opts) {
1855 if (FF_SA & oip->flags) {
1856 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1857 2, 2);
1858 kfree(arr);
1859 return check_condition_result;
1860 }
1861 req_sa = 0;
1862 } else if (2 == reporting_opts &&
1863 0 == (FF_SA & oip->flags)) {
1864 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1865 kfree(arr); /* point at requested sa */
1866 return check_condition_result;
1867 }
1868 if (0 == (FF_SA & oip->flags) &&
1869 req_opcode == oip->opcode)
1870 supp = 3;
1871 else if (0 == (FF_SA & oip->flags)) {
1872 na = oip->num_attached;
1873 for (k = 0, oip = oip->arrp; k < na;
1874 ++k, ++oip) {
1875 if (req_opcode == oip->opcode)
1876 break;
1877 }
1878 supp = (k >= na) ? 1 : 3;
1879 } else if (req_sa != oip->sa) {
1880 na = oip->num_attached;
1881 for (k = 0, oip = oip->arrp; k < na;
1882 ++k, ++oip) {
1883 if (req_sa == oip->sa)
1884 break;
1885 }
1886 supp = (k >= na) ? 1 : 3;
1887 } else
1888 supp = 3;
1889 if (3 == supp) {
1890 u = oip->len_mask[0];
1891 put_unaligned_be16(u, arr + 2);
1892 arr[4] = oip->opcode;
1893 for (k = 1; k < u; ++k)
1894 arr[4 + k] = (k < 16) ?
1895 oip->len_mask[k] : 0xff;
1896 offset = 4 + u;
1897 } else
1898 offset = 4;
1899 }
1900 arr[1] = (rctd ? 0x80 : 0) | supp;
1901 if (rctd) {
1902 put_unaligned_be16(0xa, arr + offset);
1903 offset += 12;
1904 }
1905 break;
1906 default:
1907 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1908 kfree(arr);
1909 return check_condition_result;
1910 }
1911 offset = (offset < a_len) ? offset : a_len;
1912 len = (offset < alloc_len) ? offset : alloc_len;
1913 errsts = fill_from_dev_buffer(scp, arr, len);
1914 kfree(arr);
1915 return errsts;
1916}
1917
Douglas Gilbertfd321192016-04-25 12:16:33 -04001918static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1919 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001920{
1921 bool repd;
1922 u32 alloc_len, len;
1923 u8 arr[16];
1924 u8 *cmd = scp->cmnd;
1925
1926 memset(arr, 0, sizeof(arr));
1927 repd = !!(cmd[2] & 0x80);
1928 alloc_len = get_unaligned_be32(cmd + 6);
1929 if (alloc_len < 4) {
1930 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1931 return check_condition_result;
1932 }
1933 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1934 arr[1] = 0x1; /* ITNRS */
1935 if (repd) {
1936 arr[3] = 0xc;
1937 len = 16;
1938 } else
1939 len = 4;
1940
1941 len = (len < alloc_len) ? len : alloc_len;
1942 return fill_from_dev_buffer(scp, arr, len);
1943}
1944
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945/* <<Following mode page info copied from ST318451LW>> */
1946
John Pittman91d4c752018-02-09 21:12:43 -05001947static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948{ /* Read-Write Error Recovery page for mode_sense */
1949 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1950 5, 0, 0xff, 0xff};
1951
1952 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1953 if (1 == pcontrol)
1954 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1955 return sizeof(err_recov_pg);
1956}
1957
John Pittman91d4c752018-02-09 21:12:43 -05001958static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959{ /* Disconnect-Reconnect page for mode_sense */
1960 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1961 0, 0, 0, 0, 0, 0, 0, 0};
1962
1963 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1964 if (1 == pcontrol)
1965 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1966 return sizeof(disconnect_pg);
1967}
1968
John Pittman91d4c752018-02-09 21:12:43 -05001969static int resp_format_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001971 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1972 0, 0, 0, 0, 0, 0, 0, 0,
1973 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974
Martin K. Petersen597136a2008-06-05 00:12:59 -04001975 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001976 put_unaligned_be16(sdebug_sectors_per, p + 10);
1977 put_unaligned_be16(sdebug_sector_size, p + 12);
1978 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001979 p[20] |= 0x20; /* should agree with INQUIRY */
1980 if (1 == pcontrol)
1981 memset(p + 2, 0, sizeof(format_pg) - 2);
1982 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983}
1984
Douglas Gilbertfd321192016-04-25 12:16:33 -04001985static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1986 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1987 0, 0, 0, 0};
1988
John Pittman91d4c752018-02-09 21:12:43 -05001989static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001991 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1992 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1993 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1995
Douglas Gilbert773642d2016-04-25 12:16:28 -04001996 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001997 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 memcpy(p, caching_pg, sizeof(caching_pg));
1999 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002000 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2001 else if (2 == pcontrol)
2002 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 return sizeof(caching_pg);
2004}
2005
Douglas Gilbertfd321192016-04-25 12:16:33 -04002006static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2007 0, 0, 0x2, 0x4b};
2008
John Pittman91d4c752018-02-09 21:12:43 -05002009static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002011 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05002012 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002013 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 0, 0, 0x2, 0x4b};
2015
Douglas Gilbert773642d2016-04-25 12:16:28 -04002016 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002018 else
2019 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002020
Douglas Gilbert773642d2016-04-25 12:16:28 -04002021 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002022 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2023
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2025 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002026 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2027 else if (2 == pcontrol)
2028 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 return sizeof(ctrl_m_pg);
2030}
2031
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002032
John Pittman91d4c752018-02-09 21:12:43 -05002033static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002035 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2036 0, 0, 0x0, 0x0};
2037 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2038 0, 0, 0x0, 0x0};
2039
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2041 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002042 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2043 else if (2 == pcontrol)
2044 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 return sizeof(iec_m_pg);
2046}
2047
John Pittman91d4c752018-02-09 21:12:43 -05002048static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002049{ /* SAS SSP mode page - short format for mode_sense */
2050 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2051 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2052
2053 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2054 if (1 == pcontrol)
2055 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2056 return sizeof(sas_sf_m_pg);
2057}
2058
2059
John Pittman91d4c752018-02-09 21:12:43 -05002060static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002061 int target_dev_id)
2062{ /* SAS phy control and discover mode page for mode_sense */
2063 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2064 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002065 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2066 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002067 0x2, 0, 0, 0, 0, 0, 0, 0,
2068 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2069 0, 0, 0, 0, 0, 0, 0, 0,
2070 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002071 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2072 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002073 0x3, 0, 0, 0, 0, 0, 0, 0,
2074 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2075 0, 0, 0, 0, 0, 0, 0, 0,
2076 };
2077 int port_a, port_b;
2078
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002079 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2080 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2081 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2082 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002083 port_a = target_dev_id + 1;
2084 port_b = port_a + 1;
2085 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002086 put_unaligned_be32(port_a, p + 20);
2087 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002088 if (1 == pcontrol)
2089 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2090 return sizeof(sas_pcd_m_pg);
2091}
2092
John Pittman91d4c752018-02-09 21:12:43 -05002093static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002094{ /* SAS SSP shared protocol specific port mode subpage */
2095 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2096 0, 0, 0, 0, 0, 0, 0, 0,
2097 };
2098
2099 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2100 if (1 == pcontrol)
2101 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2102 return sizeof(sas_sha_m_pg);
2103}
2104
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105#define SDEBUG_MAX_MSENSE_SZ 256
2106
Douglas Gilbertfd321192016-04-25 12:16:33 -04002107static int resp_mode_sense(struct scsi_cmnd *scp,
2108 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109{
Douglas Gilbert23183912006-09-16 20:30:47 -04002110 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002112 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002113 int target = scp->device->id;
John Pittman91d4c752018-02-09 21:12:43 -05002114 unsigned char *ap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002116 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002117 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002119 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 pcontrol = (cmd[2] & 0xc0) >> 6;
2121 pcode = cmd[2] & 0x3f;
2122 subpcode = cmd[3];
2123 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002124 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2125 is_disk = (sdebug_ptype == TYPE_DISK);
2126 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002127 bd_len = llbaa ? 16 : 8;
2128 else
2129 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002130 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2132 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002133 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 return check_condition_result;
2135 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002136 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2137 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002138 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002139 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002140 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002141 else
2142 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 if (msense_6) {
2144 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002145 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 offset = 4;
2147 } else {
2148 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002149 if (16 == bd_len)
2150 arr[4] = 0x1; /* set LONGLBA bit */
2151 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 offset = 8;
2153 }
2154 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002155 if ((bd_len > 0) && (!sdebug_capacity))
2156 sdebug_capacity = get_sdebug_capacity();
2157
Douglas Gilbert23183912006-09-16 20:30:47 -04002158 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002159 if (sdebug_capacity > 0xfffffffe)
2160 put_unaligned_be32(0xffffffff, ap + 0);
2161 else
2162 put_unaligned_be32(sdebug_capacity, ap + 0);
2163 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002164 offset += bd_len;
2165 ap = arr + offset;
2166 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002167 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2168 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002169 offset += bd_len;
2170 ap = arr + offset;
2171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002173 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2174 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002175 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 return check_condition_result;
2177 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002178 bad_pcode = false;
2179
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 switch (pcode) {
2181 case 0x1: /* Read-Write error recovery page, direct access */
2182 len = resp_err_recov_pg(ap, pcontrol, target);
2183 offset += len;
2184 break;
2185 case 0x2: /* Disconnect-Reconnect page, all devices */
2186 len = resp_disconnect_pg(ap, pcontrol, target);
2187 offset += len;
2188 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002189 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002190 if (is_disk) {
2191 len = resp_format_pg(ap, pcontrol, target);
2192 offset += len;
2193 } else
2194 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002195 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002197 if (is_disk) {
2198 len = resp_caching_pg(ap, pcontrol, target);
2199 offset += len;
2200 } else
2201 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 break;
2203 case 0xa: /* Control Mode page, all devices */
2204 len = resp_ctrl_m_pg(ap, pcontrol, target);
2205 offset += len;
2206 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002207 case 0x19: /* if spc==1 then sas phy, control+discover */
2208 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002209 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002210 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002211 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002212 len = 0;
2213 if ((0x0 == subpcode) || (0xff == subpcode))
2214 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2215 if ((0x1 == subpcode) || (0xff == subpcode))
2216 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2217 target_dev_id);
2218 if ((0x2 == subpcode) || (0xff == subpcode))
2219 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2220 offset += len;
2221 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 case 0x1c: /* Informational Exceptions Mode page, all devices */
2223 len = resp_iec_m_pg(ap, pcontrol, target);
2224 offset += len;
2225 break;
2226 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002227 if ((0 == subpcode) || (0xff == subpcode)) {
2228 len = resp_err_recov_pg(ap, pcontrol, target);
2229 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002230 if (is_disk) {
2231 len += resp_format_pg(ap + len, pcontrol,
2232 target);
2233 len += resp_caching_pg(ap + len, pcontrol,
2234 target);
2235 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002236 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2237 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2238 if (0xff == subpcode) {
2239 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2240 target, target_dev_id);
2241 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2242 }
2243 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002244 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002245 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002246 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002247 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 break;
2250 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002251 bad_pcode = true;
2252 break;
2253 }
2254 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002255 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 return check_condition_result;
2257 }
2258 if (msense_6)
2259 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002260 else
2261 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2263}
2264
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002265#define SDEBUG_MAX_MSELECT_SZ 512
2266
Douglas Gilbertfd321192016-04-25 12:16:33 -04002267static int resp_mode_select(struct scsi_cmnd *scp,
2268 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002269{
2270 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002271 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002272 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002273 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002274 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002275
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002276 memset(arr, 0, sizeof(arr));
2277 pf = cmd[1] & 0x10;
2278 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002279 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002280 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002281 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002282 return check_condition_result;
2283 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002284 res = fetch_to_dev_buffer(scp, arr, param_len);
2285 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002286 return DID_ERROR << 16;
2287 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002288 sdev_printk(KERN_INFO, scp->device,
2289 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2290 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002291 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2292 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002293 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002294 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002295 return check_condition_result;
2296 }
2297 off = bd_len + (mselect6 ? 4 : 8);
2298 mpage = arr[off] & 0x3f;
2299 ps = !!(arr[off] & 0x80);
2300 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002301 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002302 return check_condition_result;
2303 }
2304 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002305 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002306 (arr[off + 1] + 2);
2307 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002308 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002309 PARAMETER_LIST_LENGTH_ERR, 0);
2310 return check_condition_result;
2311 }
2312 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002313 case 0x8: /* Caching Mode page */
2314 if (caching_pg[1] == arr[off + 1]) {
2315 memcpy(caching_pg + 2, arr + off + 2,
2316 sizeof(caching_pg) - 2);
2317 goto set_mode_changed_ua;
2318 }
2319 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002320 case 0xa: /* Control Mode page */
2321 if (ctrl_m_pg[1] == arr[off + 1]) {
2322 memcpy(ctrl_m_pg + 2, arr + off + 2,
2323 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002324 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002325 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002326 }
2327 break;
2328 case 0x1c: /* Informational Exceptions Mode page */
2329 if (iec_m_pg[1] == arr[off + 1]) {
2330 memcpy(iec_m_pg + 2, arr + off + 2,
2331 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002332 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002333 }
2334 break;
2335 default:
2336 break;
2337 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002338 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002339 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002340set_mode_changed_ua:
2341 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2342 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002343}
2344
John Pittman91d4c752018-02-09 21:12:43 -05002345static int resp_temp_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002346{
2347 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2348 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2349 };
2350
Douglas Gilbert9a051012017-12-23 12:48:10 -05002351 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2352 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002353}
2354
John Pittman91d4c752018-02-09 21:12:43 -05002355static int resp_ie_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002356{
2357 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2358 };
2359
Douglas Gilbert9a051012017-12-23 12:48:10 -05002360 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002361 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2362 arr[4] = THRESHOLD_EXCEEDED;
2363 arr[5] = 0xff;
2364 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002365 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002366}
2367
2368#define SDEBUG_MAX_LSENSE_SZ 512
2369
Douglas Gilbert9a051012017-12-23 12:48:10 -05002370static int resp_log_sense(struct scsi_cmnd *scp,
2371 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002372{
Bart Van Asscheab172412017-08-25 13:46:42 -07002373 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002374 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002375 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002376
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002377 memset(arr, 0, sizeof(arr));
2378 ppc = cmd[1] & 0x2;
2379 sp = cmd[1] & 0x1;
2380 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002381 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002382 return check_condition_result;
2383 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002384 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002385 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002386 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002387 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002388 if (0 == subpcode) {
2389 switch (pcode) {
2390 case 0x0: /* Supported log pages log page */
2391 n = 4;
2392 arr[n++] = 0x0; /* this page */
2393 arr[n++] = 0xd; /* Temperature */
2394 arr[n++] = 0x2f; /* Informational exceptions */
2395 arr[3] = n - 4;
2396 break;
2397 case 0xd: /* Temperature log page */
2398 arr[3] = resp_temp_l_pg(arr + 4);
2399 break;
2400 case 0x2f: /* Informational exceptions log page */
2401 arr[3] = resp_ie_l_pg(arr + 4);
2402 break;
2403 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002404 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002405 return check_condition_result;
2406 }
2407 } else if (0xff == subpcode) {
2408 arr[0] |= 0x40;
2409 arr[1] = subpcode;
2410 switch (pcode) {
2411 case 0x0: /* Supported log pages and subpages log page */
2412 n = 4;
2413 arr[n++] = 0x0;
2414 arr[n++] = 0x0; /* 0,0 page */
2415 arr[n++] = 0x0;
2416 arr[n++] = 0xff; /* this page */
2417 arr[n++] = 0xd;
2418 arr[n++] = 0x0; /* Temperature */
2419 arr[n++] = 0x2f;
2420 arr[n++] = 0x0; /* Informational exceptions */
2421 arr[3] = n - 4;
2422 break;
2423 case 0xd: /* Temperature subpages */
2424 n = 4;
2425 arr[n++] = 0xd;
2426 arr[n++] = 0x0; /* Temperature */
2427 arr[3] = n - 4;
2428 break;
2429 case 0x2f: /* Informational exceptions subpages */
2430 n = 4;
2431 arr[n++] = 0x2f;
2432 arr[n++] = 0x0; /* Informational exceptions */
2433 arr[3] = n - 4;
2434 break;
2435 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002436 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002437 return check_condition_result;
2438 }
2439 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002440 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002441 return check_condition_result;
2442 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002443 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002444 return fill_from_dev_buffer(scp, arr,
2445 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2446}
2447
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002448static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002449 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002451 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002452 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 return check_condition_result;
2454 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002455 /* transfer length excessive (tie in to block limits VPD page) */
2456 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002457 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002458 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002459 return check_condition_result;
2460 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002461 return 0;
2462}
2463
Akinobu Mitaa4517512013-07-08 16:01:57 -07002464/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002465static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2466 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002467{
2468 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002469 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002470 struct scsi_data_buffer *sdb;
2471 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002472
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002473 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002474 sdb = scsi_out(scmd);
2475 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002476 } else {
2477 sdb = scsi_in(scmd);
2478 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002479 }
2480
2481 if (!sdb->length)
2482 return 0;
2483 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2484 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002485
2486 block = do_div(lba, sdebug_store_sectors);
2487 if (block + num > sdebug_store_sectors)
2488 rest = block + num - sdebug_store_sectors;
2489
Dave Gordon386ecb12015-06-30 14:58:57 -07002490 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002491 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002492 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002493 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002494 return ret;
2495
2496 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002497 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002498 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002499 sg_skip + ((num - rest) * sdebug_sector_size),
2500 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002501 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002502
2503 return ret;
2504}
2505
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002506/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2507 * arr into fake_store(lba,num) and return true. If comparison fails then
2508 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002509static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002510{
2511 bool res;
2512 u64 block, rest = 0;
2513 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002514 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002515
2516 block = do_div(lba, store_blks);
2517 if (block + num > store_blks)
2518 rest = block + num - store_blks;
2519
2520 res = !memcmp(fake_storep + (block * lb_size), arr,
2521 (num - rest) * lb_size);
2522 if (!res)
2523 return res;
2524 if (rest)
2525 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2526 rest * lb_size);
2527 if (!res)
2528 return res;
2529 arr += num * lb_size;
2530 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2531 if (rest)
2532 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2533 rest * lb_size);
2534 return res;
2535}
2536
Akinobu Mita51d648a2013-09-18 21:27:28 +09002537static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002538{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002539 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002540
Douglas Gilbert773642d2016-04-25 12:16:28 -04002541 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002542 csum = (__force __be16)ip_compute_csum(buf, len);
2543 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002544 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002545
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002546 return csum;
2547}
2548
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002549static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002550 sector_t sector, u32 ei_lba)
2551{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002552 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002553
2554 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002555 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002556 (unsigned long)sector,
2557 be16_to_cpu(sdt->guard_tag),
2558 be16_to_cpu(csum));
2559 return 0x01;
2560 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002561 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002562 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002563 pr_err("REF check failed on sector %lu\n",
2564 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002565 return 0x03;
2566 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002567 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002568 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002569 pr_err("REF check failed on sector %lu\n",
2570 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002571 return 0x03;
2572 }
2573 return 0;
2574}
2575
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002576static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002577 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002578{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002579 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002580 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002581 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002582 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002583
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002584 /* Bytes of protection data to copy into sgl */
2585 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002586
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002587 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2588 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2589 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2590
2591 while (sg_miter_next(&miter) && resid > 0) {
2592 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002593 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002594 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002595
2596 if (dif_store_end < start + len)
2597 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002598
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002599 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002600
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002601 if (read)
2602 memcpy(paddr, start, len - rest);
2603 else
2604 memcpy(start, paddr, len - rest);
2605
2606 if (rest) {
2607 if (read)
2608 memcpy(paddr + len - rest, dif_storep, rest);
2609 else
2610 memcpy(dif_storep, paddr + len - rest, rest);
2611 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002612
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002613 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002614 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002615 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002616 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002617}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002618
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002619static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2620 unsigned int sectors, u32 ei_lba)
2621{
2622 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002623 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002624 sector_t sector;
2625
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002626 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002627 int ret;
2628
2629 sector = start_sec + i;
2630 sdt = dif_store(sector);
2631
Akinobu Mita51d648a2013-09-18 21:27:28 +09002632 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002633 continue;
2634
2635 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2636 if (ret) {
2637 dif_errors++;
2638 return ret;
2639 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002640 }
2641
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002642 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002643 dix_reads++;
2644
2645 return 0;
2646}
2647
Douglas Gilbertfd321192016-04-25 12:16:33 -04002648static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002649{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002650 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002651 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002652 u64 lba;
2653 u32 num;
2654 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002655 unsigned long iflags;
2656 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002657 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002658
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002659 switch (cmd[0]) {
2660 case READ_16:
2661 ei_lba = 0;
2662 lba = get_unaligned_be64(cmd + 2);
2663 num = get_unaligned_be32(cmd + 10);
2664 check_prot = true;
2665 break;
2666 case READ_10:
2667 ei_lba = 0;
2668 lba = get_unaligned_be32(cmd + 2);
2669 num = get_unaligned_be16(cmd + 7);
2670 check_prot = true;
2671 break;
2672 case READ_6:
2673 ei_lba = 0;
2674 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2675 (u32)(cmd[1] & 0x1f) << 16;
2676 num = (0 == cmd[4]) ? 256 : cmd[4];
2677 check_prot = true;
2678 break;
2679 case READ_12:
2680 ei_lba = 0;
2681 lba = get_unaligned_be32(cmd + 2);
2682 num = get_unaligned_be32(cmd + 6);
2683 check_prot = true;
2684 break;
2685 case XDWRITEREAD_10:
2686 ei_lba = 0;
2687 lba = get_unaligned_be32(cmd + 2);
2688 num = get_unaligned_be16(cmd + 7);
2689 check_prot = false;
2690 break;
2691 default: /* assume READ(32) */
2692 lba = get_unaligned_be64(cmd + 12);
2693 ei_lba = get_unaligned_be32(cmd + 20);
2694 num = get_unaligned_be32(cmd + 28);
2695 check_prot = false;
2696 break;
2697 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002698 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002699 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002700 (cmd[1] & 0xe0)) {
2701 mk_sense_invalid_opcode(scp);
2702 return check_condition_result;
2703 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002704 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2705 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002706 (cmd[1] & 0xe0) == 0)
2707 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2708 "to DIF device\n");
2709 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002710 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002711 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002712
Douglas Gilbertc4837392016-05-06 00:40:26 -04002713 if (sqcp) {
2714 if (sqcp->inj_short)
2715 num /= 2;
2716 }
2717 } else
2718 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002719
2720 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002721 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002722 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2723 return check_condition_result;
2724 }
2725 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002726 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002727 /* needs work to find which cdb byte 'num' comes from */
2728 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2729 return check_condition_result;
2730 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002731
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002732 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05002733 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2734 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002735 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002736 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002737 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002738 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2739 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002740 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2741 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002742 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002743 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002744 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 return check_condition_result;
2746 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002747
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002748 read_lock_irqsave(&atomic_rw, iflags);
2749
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002750 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002751 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002752 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002753
2754 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002755 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002756 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002757 return illegal_condition_result;
2758 }
2759 }
2760
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002761 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002763 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002764 return DID_ERROR << 16;
2765
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002766 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002767
Douglas Gilbertc4837392016-05-06 00:40:26 -04002768 if (unlikely(sqcp)) {
2769 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002770 mk_sense_buffer(scp, RECOVERED_ERROR,
2771 THRESHOLD_EXCEEDED, 0);
2772 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002773 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002774 mk_sense_buffer(scp, ABORTED_COMMAND,
2775 TRANSPORT_PROBLEM, ACK_NAK_TO);
2776 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002777 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002778 /* Logical block guard check failed */
2779 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2780 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002781 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002782 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2783 return illegal_condition_result;
2784 }
2785 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002786 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787}
2788
Tomas Winkler58a86352015-07-28 16:54:23 +03002789static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002790{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002791 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002792
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002793 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002794 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002795 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002796
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002797 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002798 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002799
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002800 if (c >= 0x20 && c < 0x7e)
2801 n += scnprintf(b + n, sizeof(b) - n,
2802 " %c ", buf[i+j]);
2803 else
2804 n += scnprintf(b + n, sizeof(b) - n,
2805 "%02x ", buf[i+j]);
2806 }
2807 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002808 }
2809}
2810
2811static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002812 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002813{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002814 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002815 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002816 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002817 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002818 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002819 int dpage_offset;
2820 struct sg_mapping_iter diter;
2821 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002822
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002823 BUG_ON(scsi_sg_count(SCpnt) == 0);
2824 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2825
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002826 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2827 scsi_prot_sg_count(SCpnt),
2828 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2829 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2830 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002831
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002832 /* For each protection page */
2833 while (sg_miter_next(&piter)) {
2834 dpage_offset = 0;
2835 if (WARN_ON(!sg_miter_next(&diter))) {
2836 ret = 0x01;
2837 goto out;
2838 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002839
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002840 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002841 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002842 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002843 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002844 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002845 if (dpage_offset >= diter.length) {
2846 if (WARN_ON(!sg_miter_next(&diter))) {
2847 ret = 0x01;
2848 goto out;
2849 }
2850 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002851 }
2852
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002853 sdt = piter.addr + ppage_offset;
2854 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002855
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002856 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002857 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002858 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002859 goto out;
2860 }
2861
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002862 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002863 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002864 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002865 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002866 diter.consumed = dpage_offset;
2867 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002868 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002869 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002870
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002871 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002872 dix_writes++;
2873
2874 return 0;
2875
2876out:
2877 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002878 sg_miter_stop(&diter);
2879 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002880 return ret;
2881}
2882
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002883static unsigned long lba_to_map_index(sector_t lba)
2884{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002885 if (sdebug_unmap_alignment)
2886 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2887 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002888 return lba;
2889}
2890
2891static sector_t map_index_to_lba(unsigned long index)
2892{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002893 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002894
Douglas Gilbert773642d2016-04-25 12:16:28 -04002895 if (sdebug_unmap_alignment)
2896 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002897 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002898}
2899
Martin K. Petersen44d92692009-10-15 14:45:27 -04002900static unsigned int map_state(sector_t lba, unsigned int *num)
2901{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002902 sector_t end;
2903 unsigned int mapped;
2904 unsigned long index;
2905 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002906
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002907 index = lba_to_map_index(lba);
2908 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002909
2910 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002911 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002912 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002913 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002914
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002915 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002916 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002917 return mapped;
2918}
2919
2920static void map_region(sector_t lba, unsigned int len)
2921{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002922 sector_t end = lba + len;
2923
Martin K. Petersen44d92692009-10-15 14:45:27 -04002924 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002925 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002926
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002927 if (index < map_size)
2928 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002929
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002930 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002931 }
2932}
2933
2934static void unmap_region(sector_t lba, unsigned int len)
2935{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002936 sector_t end = lba + len;
2937
Martin K. Petersen44d92692009-10-15 14:45:27 -04002938 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002939 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002940
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002941 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002942 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002943 index < map_size) {
2944 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002945 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002946 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002947 lba * sdebug_sector_size,
2948 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002949 sdebug_sector_size *
2950 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002951 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002952 if (dif_storep) {
2953 memset(dif_storep + lba, 0xff,
2954 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002955 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002956 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002957 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002958 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002959 }
2960}
2961
Douglas Gilbertfd321192016-04-25 12:16:33 -04002962static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002964 u8 *cmd = scp->cmnd;
2965 u64 lba;
2966 u32 num;
2967 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002969 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002970 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002972 switch (cmd[0]) {
2973 case WRITE_16:
2974 ei_lba = 0;
2975 lba = get_unaligned_be64(cmd + 2);
2976 num = get_unaligned_be32(cmd + 10);
2977 check_prot = true;
2978 break;
2979 case WRITE_10:
2980 ei_lba = 0;
2981 lba = get_unaligned_be32(cmd + 2);
2982 num = get_unaligned_be16(cmd + 7);
2983 check_prot = true;
2984 break;
2985 case WRITE_6:
2986 ei_lba = 0;
2987 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2988 (u32)(cmd[1] & 0x1f) << 16;
2989 num = (0 == cmd[4]) ? 256 : cmd[4];
2990 check_prot = true;
2991 break;
2992 case WRITE_12:
2993 ei_lba = 0;
2994 lba = get_unaligned_be32(cmd + 2);
2995 num = get_unaligned_be32(cmd + 6);
2996 check_prot = true;
2997 break;
2998 case 0x53: /* XDWRITEREAD(10) */
2999 ei_lba = 0;
3000 lba = get_unaligned_be32(cmd + 2);
3001 num = get_unaligned_be16(cmd + 7);
3002 check_prot = false;
3003 break;
3004 default: /* assume WRITE(32) */
3005 lba = get_unaligned_be64(cmd + 12);
3006 ei_lba = get_unaligned_be32(cmd + 20);
3007 num = get_unaligned_be32(cmd + 28);
3008 check_prot = false;
3009 break;
3010 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003011 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003012 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003013 (cmd[1] & 0xe0)) {
3014 mk_sense_invalid_opcode(scp);
3015 return check_condition_result;
3016 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003017 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3018 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003019 (cmd[1] & 0xe0) == 0)
3020 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3021 "to DIF device\n");
3022 }
3023
3024 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003025 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003026 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3027 return check_condition_result;
3028 }
3029 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003030 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003031 /* needs work to find which cdb byte 'num' comes from */
3032 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3033 return check_condition_result;
3034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003036 write_lock_irqsave(&atomic_rw, iflags);
3037
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003038 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003039 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003040 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003041
3042 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003043 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003044 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003045 return illegal_condition_result;
3046 }
3047 }
3048
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003049 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003050 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003051 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003053 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003054 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003055 else if (unlikely(sdebug_verbose &&
3056 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003057 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003058 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003059 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003060
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003061 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003062 struct sdebug_queued_cmd *sqcp =
3063 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003064
Douglas Gilbertc4837392016-05-06 00:40:26 -04003065 if (sqcp) {
3066 if (sqcp->inj_recovered) {
3067 mk_sense_buffer(scp, RECOVERED_ERROR,
3068 THRESHOLD_EXCEEDED, 0);
3069 return check_condition_result;
3070 } else if (sqcp->inj_dif) {
3071 /* Logical block guard check failed */
3072 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3073 return illegal_condition_result;
3074 } else if (sqcp->inj_dix) {
3075 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3076 return illegal_condition_result;
3077 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003078 }
3079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 return 0;
3081}
3082
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003083/*
3084 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3085 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3086 */
3087static int resp_write_scat(struct scsi_cmnd *scp,
3088 struct sdebug_dev_info *devip)
3089{
3090 u8 *cmd = scp->cmnd;
3091 u8 *lrdp = NULL;
3092 u8 *up;
3093 u8 wrprotect;
3094 u16 lbdof, num_lrd, k;
3095 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3096 u32 lb_size = sdebug_sector_size;
3097 u32 ei_lba;
3098 u64 lba;
3099 unsigned long iflags;
3100 int ret, res;
3101 bool is_16;
3102 static const u32 lrd_size = 32; /* + parameter list header size */
3103
3104 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3105 is_16 = false;
3106 wrprotect = (cmd[10] >> 5) & 0x7;
3107 lbdof = get_unaligned_be16(cmd + 12);
3108 num_lrd = get_unaligned_be16(cmd + 16);
3109 bt_len = get_unaligned_be32(cmd + 28);
3110 } else { /* that leaves WRITE SCATTERED(16) */
3111 is_16 = true;
3112 wrprotect = (cmd[2] >> 5) & 0x7;
3113 lbdof = get_unaligned_be16(cmd + 4);
3114 num_lrd = get_unaligned_be16(cmd + 8);
3115 bt_len = get_unaligned_be32(cmd + 10);
3116 if (unlikely(have_dif_prot)) {
3117 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3118 wrprotect) {
3119 mk_sense_invalid_opcode(scp);
3120 return illegal_condition_result;
3121 }
3122 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3123 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3124 wrprotect == 0)
3125 sdev_printk(KERN_ERR, scp->device,
3126 "Unprotected WR to DIF device\n");
3127 }
3128 }
3129 if ((num_lrd == 0) || (bt_len == 0))
3130 return 0; /* T10 says these do-nothings are not errors */
3131 if (lbdof == 0) {
3132 if (sdebug_verbose)
3133 sdev_printk(KERN_INFO, scp->device,
3134 "%s: %s: LB Data Offset field bad\n",
3135 my_name, __func__);
3136 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3137 return illegal_condition_result;
3138 }
3139 lbdof_blen = lbdof * lb_size;
3140 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3141 if (sdebug_verbose)
3142 sdev_printk(KERN_INFO, scp->device,
3143 "%s: %s: LBA range descriptors don't fit\n",
3144 my_name, __func__);
3145 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3146 return illegal_condition_result;
3147 }
3148 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3149 if (lrdp == NULL)
3150 return SCSI_MLQUEUE_HOST_BUSY;
3151 if (sdebug_verbose)
3152 sdev_printk(KERN_INFO, scp->device,
3153 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3154 my_name, __func__, lbdof_blen);
3155 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3156 if (res == -1) {
3157 ret = DID_ERROR << 16;
3158 goto err_out;
3159 }
3160
3161 write_lock_irqsave(&atomic_rw, iflags);
3162 sg_off = lbdof_blen;
3163 /* Spec says Buffer xfer Length field in number of LBs in dout */
3164 cum_lb = 0;
3165 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3166 lba = get_unaligned_be64(up + 0);
3167 num = get_unaligned_be32(up + 8);
3168 if (sdebug_verbose)
3169 sdev_printk(KERN_INFO, scp->device,
3170 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3171 my_name, __func__, k, lba, num, sg_off);
3172 if (num == 0)
3173 continue;
3174 ret = check_device_access_params(scp, lba, num);
3175 if (ret)
3176 goto err_out_unlock;
3177 num_by = num * lb_size;
3178 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3179
3180 if ((cum_lb + num) > bt_len) {
3181 if (sdebug_verbose)
3182 sdev_printk(KERN_INFO, scp->device,
3183 "%s: %s: sum of blocks > data provided\n",
3184 my_name, __func__);
3185 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3186 0);
3187 ret = illegal_condition_result;
3188 goto err_out_unlock;
3189 }
3190
3191 /* DIX + T10 DIF */
3192 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3193 int prot_ret = prot_verify_write(scp, lba, num,
3194 ei_lba);
3195
3196 if (prot_ret) {
3197 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3198 prot_ret);
3199 ret = illegal_condition_result;
3200 goto err_out_unlock;
3201 }
3202 }
3203
3204 ret = do_device_access(scp, sg_off, lba, num, true);
3205 if (unlikely(scsi_debug_lbp()))
3206 map_region(lba, num);
3207 if (unlikely(-1 == ret)) {
3208 ret = DID_ERROR << 16;
3209 goto err_out_unlock;
3210 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3211 sdev_printk(KERN_INFO, scp->device,
3212 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3213 my_name, num_by, ret);
3214
3215 if (unlikely(sdebug_any_injecting_opt)) {
3216 struct sdebug_queued_cmd *sqcp =
3217 (struct sdebug_queued_cmd *)scp->host_scribble;
3218
3219 if (sqcp) {
3220 if (sqcp->inj_recovered) {
3221 mk_sense_buffer(scp, RECOVERED_ERROR,
3222 THRESHOLD_EXCEEDED, 0);
3223 ret = illegal_condition_result;
3224 goto err_out_unlock;
3225 } else if (sqcp->inj_dif) {
3226 /* Logical block guard check failed */
3227 mk_sense_buffer(scp, ABORTED_COMMAND,
3228 0x10, 1);
3229 ret = illegal_condition_result;
3230 goto err_out_unlock;
3231 } else if (sqcp->inj_dix) {
3232 mk_sense_buffer(scp, ILLEGAL_REQUEST,
3233 0x10, 1);
3234 ret = illegal_condition_result;
3235 goto err_out_unlock;
3236 }
3237 }
3238 }
3239 sg_off += num_by;
3240 cum_lb += num;
3241 }
3242 ret = 0;
3243err_out_unlock:
3244 write_unlock_irqrestore(&atomic_rw, iflags);
3245err_out:
3246 kfree(lrdp);
3247 return ret;
3248}
3249
Douglas Gilbertfd321192016-04-25 12:16:33 -04003250static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3251 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003252{
3253 unsigned long iflags;
3254 unsigned long long i;
3255 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003256 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003257
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003258 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003259 if (ret)
3260 return ret;
3261
3262 write_lock_irqsave(&atomic_rw, iflags);
3263
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003264 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003265 unmap_region(lba, num);
3266 goto out;
3267 }
3268
Douglas Gilbert773642d2016-04-25 12:16:28 -04003269 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003270 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3271 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003272 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003273 ret = 0;
3274 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003275 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3276 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003277
3278 if (-1 == ret) {
3279 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003280 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003281 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003282 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003283 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003284 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003285 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003286
3287 /* Copy first sector to remaining blocks */
3288 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003289 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3290 fake_storep + lba_off,
3291 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003292
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003293 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003294 map_region(lba, num);
3295out:
3296 write_unlock_irqrestore(&atomic_rw, iflags);
3297
3298 return 0;
3299}
3300
Douglas Gilbertfd321192016-04-25 12:16:33 -04003301static int resp_write_same_10(struct scsi_cmnd *scp,
3302 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003303{
3304 u8 *cmd = scp->cmnd;
3305 u32 lba;
3306 u16 num;
3307 u32 ei_lba = 0;
3308 bool unmap = false;
3309
3310 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003311 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003312 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3313 return check_condition_result;
3314 } else
3315 unmap = true;
3316 }
3317 lba = get_unaligned_be32(cmd + 2);
3318 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003319 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003320 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3321 return check_condition_result;
3322 }
3323 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3324}
3325
Douglas Gilbertfd321192016-04-25 12:16:33 -04003326static int resp_write_same_16(struct scsi_cmnd *scp,
3327 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003328{
3329 u8 *cmd = scp->cmnd;
3330 u64 lba;
3331 u32 num;
3332 u32 ei_lba = 0;
3333 bool unmap = false;
3334 bool ndob = false;
3335
3336 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003337 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003338 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3339 return check_condition_result;
3340 } else
3341 unmap = true;
3342 }
3343 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3344 ndob = true;
3345 lba = get_unaligned_be64(cmd + 2);
3346 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003347 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003348 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3349 return check_condition_result;
3350 }
3351 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3352}
3353
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003354/* Note the mode field is in the same position as the (lower) service action
3355 * field. For the Report supported operation codes command, SPC-4 suggests
3356 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003357static int resp_write_buffer(struct scsi_cmnd *scp,
3358 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003359{
3360 u8 *cmd = scp->cmnd;
3361 struct scsi_device *sdp = scp->device;
3362 struct sdebug_dev_info *dp;
3363 u8 mode;
3364
3365 mode = cmd[1] & 0x1f;
3366 switch (mode) {
3367 case 0x4: /* download microcode (MC) and activate (ACT) */
3368 /* set UAs on this device only */
3369 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3370 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3371 break;
3372 case 0x5: /* download MC, save and ACT */
3373 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3374 break;
3375 case 0x6: /* download MC with offsets and ACT */
3376 /* set UAs on most devices (LUs) in this target */
3377 list_for_each_entry(dp,
3378 &devip->sdbg_host->dev_info_list,
3379 dev_list)
3380 if (dp->target == sdp->id) {
3381 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3382 if (devip != dp)
3383 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3384 dp->uas_bm);
3385 }
3386 break;
3387 case 0x7: /* download MC with offsets, save, and ACT */
3388 /* set UA on all devices (LUs) in this target */
3389 list_for_each_entry(dp,
3390 &devip->sdbg_host->dev_info_list,
3391 dev_list)
3392 if (dp->target == sdp->id)
3393 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3394 dp->uas_bm);
3395 break;
3396 default:
3397 /* do nothing for this command for other mode values */
3398 break;
3399 }
3400 return 0;
3401}
3402
Douglas Gilbertfd321192016-04-25 12:16:33 -04003403static int resp_comp_write(struct scsi_cmnd *scp,
3404 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003405{
3406 u8 *cmd = scp->cmnd;
3407 u8 *arr;
3408 u8 *fake_storep_hold;
3409 u64 lba;
3410 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003411 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003412 u8 num;
3413 unsigned long iflags;
3414 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003415 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003416
Douglas Gilbertd467d312014-11-26 12:33:48 -05003417 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003418 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3419 if (0 == num)
3420 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003421 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003422 (cmd[1] & 0xe0)) {
3423 mk_sense_invalid_opcode(scp);
3424 return check_condition_result;
3425 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003426 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3427 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003428 (cmd[1] & 0xe0) == 0)
3429 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3430 "to DIF device\n");
3431
3432 /* inline check_device_access_params() */
3433 if (lba + num > sdebug_capacity) {
3434 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3435 return check_condition_result;
3436 }
3437 /* transfer length excessive (tie in to block limits VPD page) */
3438 if (num > sdebug_store_sectors) {
3439 /* needs work to find which cdb byte 'num' comes from */
3440 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3441 return check_condition_result;
3442 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003443 dnum = 2 * num;
3444 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3445 if (NULL == arr) {
3446 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3447 INSUFF_RES_ASCQ);
3448 return check_condition_result;
3449 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003450
3451 write_lock_irqsave(&atomic_rw, iflags);
3452
3453 /* trick do_device_access() to fetch both compare and write buffers
3454 * from data-in into arr. Safe (atomic) since write_lock held. */
3455 fake_storep_hold = fake_storep;
3456 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003457 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003458 fake_storep = fake_storep_hold;
3459 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003460 retval = DID_ERROR << 16;
3461 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003462 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003463 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3464 "indicated=%u, IO sent=%d bytes\n", my_name,
3465 dnum * lb_size, ret);
3466 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003467 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003468 retval = check_condition_result;
3469 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003470 }
3471 if (scsi_debug_lbp())
3472 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003473cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003474 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003475 kfree(arr);
3476 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003477}
3478
Martin K. Petersen44d92692009-10-15 14:45:27 -04003479struct unmap_block_desc {
3480 __be64 lba;
3481 __be32 blocks;
3482 __be32 __reserved;
3483};
3484
Douglas Gilbertfd321192016-04-25 12:16:33 -04003485static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003486{
3487 unsigned char *buf;
3488 struct unmap_block_desc *desc;
3489 unsigned int i, payload_len, descriptors;
3490 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003491 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003492
Martin K. Petersen44d92692009-10-15 14:45:27 -04003493
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003494 if (!scsi_debug_lbp())
3495 return 0; /* fib and say its done */
3496 payload_len = get_unaligned_be16(scp->cmnd + 7);
3497 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003498
3499 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003500 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003501 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003502 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003503 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003504
Douglas Gilbertb333a812016-04-25 12:16:30 -04003505 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003506 if (!buf) {
3507 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3508 INSUFF_RES_ASCQ);
3509 return check_condition_result;
3510 }
3511
3512 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003513
3514 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3515 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3516
3517 desc = (void *)&buf[8];
3518
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003519 write_lock_irqsave(&atomic_rw, iflags);
3520
Martin K. Petersen44d92692009-10-15 14:45:27 -04003521 for (i = 0 ; i < descriptors ; i++) {
3522 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3523 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3524
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003525 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003526 if (ret)
3527 goto out;
3528
3529 unmap_region(lba, num);
3530 }
3531
3532 ret = 0;
3533
3534out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003535 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003536 kfree(buf);
3537
3538 return ret;
3539}
3540
3541#define SDEBUG_GET_LBA_STATUS_LEN 32
3542
Douglas Gilbertfd321192016-04-25 12:16:33 -04003543static int resp_get_lba_status(struct scsi_cmnd *scp,
3544 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003545{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003546 u8 *cmd = scp->cmnd;
3547 u64 lba;
3548 u32 alloc_len, mapped, num;
3549 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003550 int ret;
3551
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003552 lba = get_unaligned_be64(cmd + 2);
3553 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003554
3555 if (alloc_len < 24)
3556 return 0;
3557
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003558 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003559 if (ret)
3560 return ret;
3561
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003562 if (scsi_debug_lbp())
3563 mapped = map_state(lba, &num);
3564 else {
3565 mapped = 1;
3566 /* following just in case virtual_gb changed */
3567 sdebug_capacity = get_sdebug_capacity();
3568 if (sdebug_capacity - lba <= 0xffffffff)
3569 num = sdebug_capacity - lba;
3570 else
3571 num = 0xffffffff;
3572 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003573
3574 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003575 put_unaligned_be32(20, arr); /* Parameter Data Length */
3576 put_unaligned_be64(lba, arr + 8); /* LBA */
3577 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3578 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003579
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003580 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003581}
3582
Douglas Gilbert80c49562018-02-09 21:36:39 -05003583static int resp_sync_cache(struct scsi_cmnd *scp,
3584 struct sdebug_dev_info *devip)
3585{
3586 u64 lba;
3587 u32 num_blocks;
3588 u8 *cmd = scp->cmnd;
3589
3590 if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
3591 lba = get_unaligned_be32(cmd + 2);
3592 num_blocks = get_unaligned_be16(cmd + 7);
3593 } else { /* SYNCHRONIZE_CACHE(16) */
3594 lba = get_unaligned_be64(cmd + 2);
3595 num_blocks = get_unaligned_be32(cmd + 10);
3596 }
3597 if (lba + num_blocks > sdebug_capacity) {
3598 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3599 return check_condition_result;
3600 }
3601 return (cmd[1] & 0x2) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
3602}
3603
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003604#define RL_BUCKET_ELEMS 8
3605
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003606/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3607 * (W-LUN), the normal Linux scanning logic does not associate it with a
3608 * device (e.g. /dev/sg7). The following magic will make that association:
3609 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3610 * where <n> is a host number. If there are multiple targets in a host then
3611 * the above will associate a W-LUN to each target. To only get a W-LUN
3612 * for target 2, then use "echo '- 2 49409' > scan" .
3613 */
3614static int resp_report_luns(struct scsi_cmnd *scp,
3615 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003617 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003618 unsigned int alloc_len;
3619 unsigned char select_report;
3620 u64 lun;
3621 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003622 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003623 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3624 unsigned int wlun_cnt; /* report luns W-LUN count */
3625 unsigned int tlun_cnt; /* total LUN count */
3626 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003627 int k, j, n, res;
3628 unsigned int off_rsp = 0;
3629 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003631 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003632
3633 select_report = cmd[2];
3634 alloc_len = get_unaligned_be32(cmd + 6);
3635
3636 if (alloc_len < 4) {
3637 pr_err("alloc len too small %d\n", alloc_len);
3638 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 return check_condition_result;
3640 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003641
3642 switch (select_report) {
3643 case 0: /* all LUNs apart from W-LUNs */
3644 lun_cnt = sdebug_max_luns;
3645 wlun_cnt = 0;
3646 break;
3647 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003648 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003649 wlun_cnt = 1;
3650 break;
3651 case 2: /* all LUNs */
3652 lun_cnt = sdebug_max_luns;
3653 wlun_cnt = 1;
3654 break;
3655 case 0x10: /* only administrative LUs */
3656 case 0x11: /* see SPC-5 */
3657 case 0x12: /* only subsiduary LUs owned by referenced LU */
3658 default:
3659 pr_debug("select report invalid %d\n", select_report);
3660 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3661 return check_condition_result;
3662 }
3663
3664 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003665 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003666
3667 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003668 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3669 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003670 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3671 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3672
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003673 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003674 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003675 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3676 memset(arr, 0, sizeof(arr));
3677 lun_p = (struct scsi_lun *)&arr[0];
3678 if (k == 0) {
3679 put_unaligned_be32(rlen, &arr[0]);
3680 ++lun_p;
3681 j = 1;
3682 }
3683 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3684 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3685 break;
3686 int_to_scsilun(lun++, lun_p);
3687 }
3688 if (j < RL_BUCKET_ELEMS)
3689 break;
3690 n = j * sz_lun;
3691 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3692 if (res)
3693 return res;
3694 off_rsp += n;
3695 }
3696 if (wlun_cnt) {
3697 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3698 ++j;
3699 }
3700 if (j > 0)
3701 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003702 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703}
3704
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003705static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3706 unsigned int num, struct sdebug_dev_info *devip)
3707{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003708 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003709 unsigned char *kaddr, *buf;
3710 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003711 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003712 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003713
3714 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003715 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003716 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003717 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3718 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003719 return check_condition_result;
3720 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003721
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003722 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003723
3724 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003725 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3726 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003727
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003728 while (sg_miter_next(&miter)) {
3729 kaddr = miter.addr;
3730 for (j = 0; j < miter.length; j++)
3731 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003732
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003733 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003734 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003735 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003736 kfree(buf);
3737
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003738 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003739}
3740
Douglas Gilbertfd321192016-04-25 12:16:33 -04003741static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3742 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003743{
3744 u8 *cmd = scp->cmnd;
3745 u64 lba;
3746 u32 num;
3747 int errsts;
3748
3749 if (!scsi_bidi_cmnd(scp)) {
3750 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3751 INSUFF_RES_ASCQ);
3752 return check_condition_result;
3753 }
3754 errsts = resp_read_dt0(scp, devip);
3755 if (errsts)
3756 return errsts;
3757 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3758 errsts = resp_write_dt0(scp, devip);
3759 if (errsts)
3760 return errsts;
3761 }
3762 lba = get_unaligned_be32(cmd + 2);
3763 num = get_unaligned_be16(cmd + 7);
3764 return resp_xdwriteread(scp, lba, num, devip);
3765}
3766
Douglas Gilbertc4837392016-05-06 00:40:26 -04003767static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3768{
Bart Van Assche458df782018-01-26 08:52:19 -08003769 u32 tag = blk_mq_unique_tag(cmnd->request);
3770 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003771
Bart Van Assche458df782018-01-26 08:52:19 -08003772 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3773 if (WARN_ON_ONCE(hwq >= submit_queues))
3774 hwq = 0;
3775 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003776}
3777
3778/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003779static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003781 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003782 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003784 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003785 struct sdebug_queued_cmd *sqcp;
3786 struct scsi_cmnd *scp;
3787 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788
Douglas Gilbert10bde982018-01-10 16:57:31 -05003789 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003790 qc_idx = sd_dp->qc_idx;
3791 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3792 if (sdebug_statistics) {
3793 atomic_inc(&sdebug_completions);
3794 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3795 atomic_inc(&sdebug_miss_cpus);
3796 }
3797 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3798 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 return;
3800 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003801 spin_lock_irqsave(&sqp->qc_lock, iflags);
3802 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003803 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003804 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003805 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3806 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3807 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 return;
3809 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003810 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003811 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003812 atomic_dec(&devip->num_in_q);
3813 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003814 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003815 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003816 retiring = 1;
3817
3818 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003819 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3820 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003821 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003822 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003824
3825 if (unlikely(retiring)) { /* user has reduced max_queue */
3826 int k, retval;
3827
3828 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003829 if (qc_idx >= retval) {
3830 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003831 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003832 return;
3833 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003834 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003835 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003836 atomic_set(&retired_max_queue, 0);
3837 else
3838 atomic_set(&retired_max_queue, k + 1);
3839 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003840 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003841 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842}
3843
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003844/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003845static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003846{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003847 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3848 hrt);
3849 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003850 return HRTIMER_NORESTART;
3851}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852
Douglas Gilberta10bc122016-04-25 12:16:32 -04003853/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003854static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003855{
3856 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3857 ew.work);
3858 sdebug_q_cmd_complete(sd_dp);
3859}
3860
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003861static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003862static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003863
Douglas Gilbertfd321192016-04-25 12:16:33 -04003864static struct sdebug_dev_info *sdebug_device_create(
3865 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003866{
3867 struct sdebug_dev_info *devip;
3868
3869 devip = kzalloc(sizeof(*devip), flags);
3870 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003871 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003872 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003873 else if (sdebug_uuid_ctl == 2) {
3874 if (got_shared_uuid)
3875 devip->lu_name = shared_uuid;
3876 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003877 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003878 got_shared_uuid = true;
3879 devip->lu_name = shared_uuid;
3880 }
3881 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003882 devip->sdbg_host = sdbg_host;
3883 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3884 }
3885 return devip;
3886}
3887
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003888static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003890 struct sdebug_host_info *sdbg_host;
3891 struct sdebug_dev_info *open_devip = NULL;
3892 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003894 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3895 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003896 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3900 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003901 (devip->target == sdev->id) &&
3902 (devip->lun == sdev->lun))
3903 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 else {
3905 if ((!devip->used) && (!open_devip))
3906 open_devip = devip;
3907 }
3908 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003909 if (!open_devip) { /* try and make a new one */
3910 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3911 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003912 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 return NULL;
3914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003916
3917 open_devip->channel = sdev->channel;
3918 open_devip->target = sdev->id;
3919 open_devip->lun = sdev->lun;
3920 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003921 atomic_set(&open_devip->num_in_q, 0);
3922 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003923 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003924 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925}
3926
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003927static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003929 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003930 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003931 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003932 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003933 return 0;
3934}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003936static int scsi_debug_slave_configure(struct scsi_device *sdp)
3937{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003938 struct sdebug_dev_info *devip =
3939 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003940
Douglas Gilbert773642d2016-04-25 12:16:28 -04003941 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003942 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003943 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003944 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3945 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3946 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003947 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003948 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003949 return 1; /* no resources, will be marked offline */
3950 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003951 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003952 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003953 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003954 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003955 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003956 return 0;
3957}
3958
3959static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3960{
3961 struct sdebug_dev_info *devip =
3962 (struct sdebug_dev_info *)sdp->hostdata;
3963
Douglas Gilbert773642d2016-04-25 12:16:28 -04003964 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003965 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003966 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3967 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003968 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003969 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003970 sdp->hostdata = NULL;
3971 }
3972}
3973
Douglas Gilbert10bde982018-01-10 16:57:31 -05003974static void stop_qc_helper(struct sdebug_defer *sd_dp,
3975 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003976{
3977 if (!sd_dp)
3978 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003979 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003980 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003981 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003982 cancel_work_sync(&sd_dp->ew.work);
3983}
3984
Douglas Gilberta10bc122016-04-25 12:16:32 -04003985/* If @cmnd found deletes its timer or work queue and returns true; else
3986 returns false */
3987static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003988{
3989 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003990 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003991 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003992 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003993 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003994 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003995 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003996
Douglas Gilbertc4837392016-05-06 00:40:26 -04003997 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3998 spin_lock_irqsave(&sqp->qc_lock, iflags);
3999 qmax = sdebug_max_queue;
4000 r_qmax = atomic_read(&retired_max_queue);
4001 if (r_qmax > qmax)
4002 qmax = r_qmax;
4003 for (k = 0; k < qmax; ++k) {
4004 if (test_bit(k, sqp->in_use_bm)) {
4005 sqcp = &sqp->qc_arr[k];
4006 if (cmnd != sqcp->a_cmnd)
4007 continue;
4008 /* found */
4009 devip = (struct sdebug_dev_info *)
4010 cmnd->device->hostdata;
4011 if (devip)
4012 atomic_dec(&devip->num_in_q);
4013 sqcp->a_cmnd = NULL;
4014 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004015 if (sd_dp) {
4016 l_defer_t = sd_dp->defer_t;
4017 sd_dp->defer_t = SDEB_DEFER_NONE;
4018 } else
4019 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004020 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004021 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004022 clear_bit(k, sqp->in_use_bm);
4023 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004024 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004025 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004026 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004027 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04004028 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004029}
4030
Douglas Gilberta10bc122016-04-25 12:16:32 -04004031/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004032static void stop_all_queued(void)
4033{
4034 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004035 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004036 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004037 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004038 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004039 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004040 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004041
Douglas Gilbertc4837392016-05-06 00:40:26 -04004042 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4043 spin_lock_irqsave(&sqp->qc_lock, iflags);
4044 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4045 if (test_bit(k, sqp->in_use_bm)) {
4046 sqcp = &sqp->qc_arr[k];
4047 if (sqcp->a_cmnd == NULL)
4048 continue;
4049 devip = (struct sdebug_dev_info *)
4050 sqcp->a_cmnd->device->hostdata;
4051 if (devip)
4052 atomic_dec(&devip->num_in_q);
4053 sqcp->a_cmnd = NULL;
4054 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004055 if (sd_dp) {
4056 l_defer_t = sd_dp->defer_t;
4057 sd_dp->defer_t = SDEB_DEFER_NONE;
4058 } else
4059 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004060 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004061 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004062 clear_bit(k, sqp->in_use_bm);
4063 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004064 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004065 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004066 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068}
4069
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004070/* Free queued command memory on heap */
4071static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004073 int j, k;
4074 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004075 struct sdebug_queued_cmd *sqcp;
4076
Douglas Gilbertc4837392016-05-06 00:40:26 -04004077 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4078 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4079 sqcp = &sqp->qc_arr[k];
4080 kfree(sqcp->sd_dp);
4081 sqcp->sd_dp = NULL;
4082 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084}
4085
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004086static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004088 bool ok;
4089
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004090 ++num_aborts;
4091 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004092 ok = stop_queued_cmnd(SCpnt);
4093 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4094 sdev_printk(KERN_INFO, SCpnt->device,
4095 "%s: command%s found\n", __func__,
4096 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004098 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099}
4100
John Pittman91d4c752018-02-09 21:12:43 -05004101static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004104 if (SCpnt && SCpnt->device) {
4105 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004106 struct sdebug_dev_info *devip =
4107 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004108
Douglas Gilbert773642d2016-04-25 12:16:28 -04004109 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004110 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004112 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 }
4114 return SUCCESS;
4115}
4116
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004117static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4118{
4119 struct sdebug_host_info *sdbg_host;
4120 struct sdebug_dev_info *devip;
4121 struct scsi_device *sdp;
4122 struct Scsi_Host *hp;
4123 int k = 0;
4124
4125 ++num_target_resets;
4126 if (!SCpnt)
4127 goto lie;
4128 sdp = SCpnt->device;
4129 if (!sdp)
4130 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004131 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004132 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4133 hp = sdp->host;
4134 if (!hp)
4135 goto lie;
4136 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4137 if (sdbg_host) {
4138 list_for_each_entry(devip,
4139 &sdbg_host->dev_info_list,
4140 dev_list)
4141 if (devip->target == sdp->id) {
4142 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4143 ++k;
4144 }
4145 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004146 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004147 sdev_printk(KERN_INFO, sdp,
4148 "%s: %d device(s) found in target\n", __func__, k);
4149lie:
4150 return SUCCESS;
4151}
4152
John Pittman91d4c752018-02-09 21:12:43 -05004153static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154{
4155 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004156 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004157 struct scsi_device *sdp;
4158 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004159 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004162 if (!(SCpnt && SCpnt->device))
4163 goto lie;
4164 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004165 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004166 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4167 hp = sdp->host;
4168 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004169 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004171 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05004172 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004173 dev_list) {
4174 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4175 ++k;
4176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 }
4178 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004179 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004180 sdev_printk(KERN_INFO, sdp,
4181 "%s: %d device(s) found in host\n", __func__, k);
4182lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 return SUCCESS;
4184}
4185
John Pittman91d4c752018-02-09 21:12:43 -05004186static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187{
John Pittman91d4c752018-02-09 21:12:43 -05004188 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004189 struct sdebug_dev_info *devip;
4190 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004193 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004194 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05004195 spin_lock(&sdebug_host_list_lock);
4196 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004197 list_for_each_entry(devip, &sdbg_host->dev_info_list,
4198 dev_list) {
4199 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4200 ++k;
4201 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05004202 }
4203 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004205 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004206 sdev_printk(KERN_INFO, SCpnt->device,
4207 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 return SUCCESS;
4209}
4210
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09004211static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004212 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213{
John Pittman91d4c752018-02-09 21:12:43 -05004214 struct partition *pp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 int starts[SDEBUG_MAX_PARTS + 2];
4216 int sectors_per_part, num_sectors, k;
4217 int heads_by_sects, start_sec, end_sec;
4218
4219 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004220 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004222 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4223 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03004224 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004226 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004228 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004230 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004231 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4233 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004234 starts[sdebug_num_parts] = num_sectors;
4235 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
4237 ramp[510] = 0x55; /* magic partition markings */
4238 ramp[511] = 0xAA;
4239 pp = (struct partition *)(ramp + 0x1be);
4240 for (k = 0; starts[k + 1]; ++k, ++pp) {
4241 start_sec = starts[k];
4242 end_sec = starts[k + 1] - 1;
4243 pp->boot_ind = 0;
4244
4245 pp->cyl = start_sec / heads_by_sects;
4246 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4247 / sdebug_sectors_per;
4248 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4249
4250 pp->end_cyl = end_sec / heads_by_sects;
4251 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4252 / sdebug_sectors_per;
4253 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4254
Akinobu Mita150c3542013-08-26 22:08:40 +09004255 pp->start_sect = cpu_to_le32(start_sec);
4256 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 pp->sys_ind = 0x83; /* plain Linux partition */
4258 }
4259}
4260
Douglas Gilbertc4837392016-05-06 00:40:26 -04004261static void block_unblock_all_queues(bool block)
4262{
4263 int j;
4264 struct sdebug_queue *sqp;
4265
4266 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4267 atomic_set(&sqp->blocked, (int)block);
4268}
4269
4270/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4271 * commands will be processed normally before triggers occur.
4272 */
4273static void tweak_cmnd_count(void)
4274{
4275 int count, modulo;
4276
4277 modulo = abs(sdebug_every_nth);
4278 if (modulo < 2)
4279 return;
4280 block_unblock_all_queues(true);
4281 count = atomic_read(&sdebug_cmnd_count);
4282 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4283 block_unblock_all_queues(false);
4284}
4285
4286static void clear_queue_stats(void)
4287{
4288 atomic_set(&sdebug_cmnd_count, 0);
4289 atomic_set(&sdebug_completions, 0);
4290 atomic_set(&sdebug_miss_cpus, 0);
4291 atomic_set(&sdebug_a_tsf, 0);
4292}
4293
4294static void setup_inject(struct sdebug_queue *sqp,
4295 struct sdebug_queued_cmd *sqcp)
4296{
Martin Wilckf9ba7af2018-01-30 00:35:52 +01004297 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4298 if (sdebug_every_nth > 0)
4299 sqcp->inj_recovered = sqcp->inj_transport
4300 = sqcp->inj_dif
4301 = sqcp->inj_dix = sqcp->inj_short = 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004302 return;
Martin Wilckf9ba7af2018-01-30 00:35:52 +01004303 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004304 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4305 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4306 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4307 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4308 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004309 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004310}
4311
4312/* Complete the processing of the thread that queued a SCSI command to this
4313 * driver. It either completes the command by calling cmnd_done() or
4314 * schedules a hr timer or work queue then returns 0. Returns
4315 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4316 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004317static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Douglas Gilbert10bde982018-01-10 16:57:31 -05004318 int scsi_result, int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004320 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004321 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004322 struct sdebug_queue *sqp;
4323 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004324 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004325 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004327 if (unlikely(devip == NULL)) {
4328 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004329 scsi_result = DID_NO_CONNECT << 16;
4330 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004332 sdp = cmnd->device;
4333
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004334 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004335 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4336 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004337 if (delta_jiff == 0)
4338 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004340 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004341 sqp = get_queue(cmnd);
4342 spin_lock_irqsave(&sqp->qc_lock, iflags);
4343 if (unlikely(atomic_read(&sqp->blocked))) {
4344 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4345 return SCSI_MLQUEUE_HOST_BUSY;
4346 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004347 num_in_q = atomic_read(&devip->num_in_q);
4348 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004349 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004350 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004351 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004352 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004353 goto respond_in_thread;
4354 } else
4355 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004356 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004357 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4358 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004359 if ((num_in_q == (qdepth - 1)) &&
4360 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004361 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004362 atomic_set(&sdebug_a_tsf, 0);
4363 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004364 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004366 }
4367
Douglas Gilbertc4837392016-05-06 00:40:26 -04004368 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004369 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004370 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004371 if (scsi_result)
4372 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004373 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004374 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004375 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004376 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004377 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004378 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004379 (scsi_result ? "status: TASK SET FULL" :
4380 "report: host busy"));
4381 if (scsi_result)
4382 goto respond_in_thread;
4383 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004384 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004386 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004387 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004388 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004389 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004390 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004391 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004392 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004393 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4394 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4395 setup_inject(sqp, sqcp);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004396 if (sd_dp == NULL) {
4397 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4398 if (sd_dp == NULL)
4399 return SCSI_MLQUEUE_HOST_BUSY;
4400 }
4401 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004402 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004403
Douglas Gilbertb333a812016-04-25 12:16:30 -04004404 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004405 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004406 } else
Douglas Gilbert10bde982018-01-10 16:57:31 -05004407 kt = ndelay;
4408 if (!sd_dp->init_hrt) {
4409 sd_dp->init_hrt = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004410 sqcp->sd_dp = sd_dp;
4411 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004412 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004413 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004414 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4415 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004416 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004417 if (sdebug_statistics)
4418 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004419 sd_dp->defer_t = SDEB_DEFER_HRT;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004420 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4421 } else { /* jdelay < 0, use work queue */
Douglas Gilbert10bde982018-01-10 16:57:31 -05004422 if (!sd_dp->init_wq) {
4423 sd_dp->init_wq = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004424 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004425 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4426 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004427 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004428 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004429 if (sdebug_statistics)
4430 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004431 sd_dp->defer_t = SDEB_DEFER_WQ;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004432 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004433 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004434 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4435 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004436 sdev_printk(KERN_INFO, sdp,
4437 "%s: num_in_q=%d +1, %s%s\n", __func__,
4438 num_in_q, (inject ? "<inject> " : ""),
4439 "status: TASK SET FULL");
4440 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004441
4442respond_in_thread: /* call back to mid-layer using invocation thread */
4443 cmnd->result = scsi_result;
4444 cmnd->scsi_done(cmnd);
4445 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004447
Douglas Gilbert23183912006-09-16 20:30:47 -04004448/* Note: The following macros create attribute files in the
4449 /sys/module/scsi_debug/parameters directory. Unfortunately this
4450 driver is unaware of a change and cannot trigger auxiliary actions
4451 as it can when the corresponding attribute in the
4452 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4453 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004454module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4455module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004456module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004457module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004458module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004459module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4460module_param_named(dif, sdebug_dif, int, S_IRUGO);
4461module_param_named(dix, sdebug_dix, int, S_IRUGO);
4462module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4463module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4464module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4465module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4466module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004467module_param_string(inq_vendor, sdebug_inq_vendor_id,
4468 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4469module_param_string(inq_product, sdebug_inq_product_id,
4470 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4471module_param_string(inq_rev, sdebug_inq_product_rev,
4472 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004473module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4474module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4475module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4476module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4477module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4478module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4479module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Laurence Obermand9da8912018-02-03 13:38:35 -05004480module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4481module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004482module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4483module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4484module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4485module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4486module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4487module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4488module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4489module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004490module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004491module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4492module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4493module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4494module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004495module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004496module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004497module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004498module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4499module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4500module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4501module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4502module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004503module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004504module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004505 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004506module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004507 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508
4509MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4510MODULE_DESCRIPTION("SCSI debug adapter driver");
4511MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004512MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
4514MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004515MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004516MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004517MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004518MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004519MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004520MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4521MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004522MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004523MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004524MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004525MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004526MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004527MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4528MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004529MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4530 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004531MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4532MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4533MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004534MODULE_PARM_DESC(lbprz,
4535 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004536MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004537MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004538MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05004539MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4540MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004541MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004542MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004543MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004545MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004546MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004547MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004548MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004549MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004551MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004552MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004553MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004554MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004555MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004556MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004557MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4558MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004559MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4560MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004561MODULE_PARM_DESC(uuid_ctl,
4562 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004563MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004564MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4565MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004567#define SDEBUG_INFO_LEN 256
4568static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569
John Pittman91d4c752018-02-09 21:12:43 -05004570static const char *scsi_debug_info(struct Scsi_Host *shp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004572 int k;
4573
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004574 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4575 my_name, SDEBUG_VERSION, sdebug_version_date);
4576 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004577 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004578 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4579 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4580 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4581 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582 return sdebug_info;
4583}
4584
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004585/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004586static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4587 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588{
Al Viroc8ed5552013-03-31 01:46:06 -04004589 char arr[16];
4590 int opts;
4591 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592
Al Viroc8ed5552013-03-31 01:46:06 -04004593 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4594 return -EACCES;
4595 memcpy(arr, buffer, minLen);
4596 arr[minLen] = '\0';
4597 if (1 != sscanf(arr, "%d", &opts))
4598 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004599 sdebug_opts = opts;
4600 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4601 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4602 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004603 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004604 return length;
4605}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004607/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4608 * same for each scsi_debug host (if more than one). Some of the counters
4609 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004610static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4611{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004612 int f, j, l;
4613 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004614
Douglas Gilbertc4837392016-05-06 00:40:26 -04004615 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4616 SDEBUG_VERSION, sdebug_version_date);
4617 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4618 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4619 sdebug_opts, sdebug_every_nth);
4620 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4621 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4622 sdebug_sector_size, "bytes");
4623 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4624 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4625 num_aborts);
4626 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4627 num_dev_resets, num_target_resets, num_bus_resets,
4628 num_host_resets);
4629 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4630 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08004631 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4632 sdebug_statistics);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004633 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4634 atomic_read(&sdebug_cmnd_count),
4635 atomic_read(&sdebug_completions),
4636 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4637 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004638
Douglas Gilbertc4837392016-05-06 00:40:26 -04004639 seq_printf(m, "submit_queues=%d\n", submit_queues);
4640 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4641 seq_printf(m, " queue %d:\n", j);
4642 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4643 if (f != sdebug_max_queue) {
4644 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4645 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4646 "first,last bits", f, l);
4647 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004648 }
Al Viroc8ed5552013-03-31 01:46:06 -04004649 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650}
4651
Akinobu Mita82069372013-10-14 22:48:04 +09004652static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004654 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004656/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4657 * of delay is jiffies.
4658 */
Akinobu Mita82069372013-10-14 22:48:04 +09004659static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4660 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004662 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004664 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004665 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004666 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004667 int j, k;
4668 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004669
Douglas Gilbertc4837392016-05-06 00:40:26 -04004670 block_unblock_all_queues(true);
4671 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4672 ++j, ++sqp) {
4673 k = find_first_bit(sqp->in_use_bm,
4674 sdebug_max_queue);
4675 if (k != sdebug_max_queue) {
4676 res = -EBUSY; /* queued commands */
4677 break;
4678 }
4679 }
4680 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04004681 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004682 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004683 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004684 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004686 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 }
4688 return -EINVAL;
4689}
Akinobu Mita82069372013-10-14 22:48:04 +09004690static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004692static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4693{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004694 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004695}
4696/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004697/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004698static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004699 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004700{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004701 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004702
4703 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004704 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004705 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004706 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004707 int j, k;
4708 struct sdebug_queue *sqp;
4709
4710 block_unblock_all_queues(true);
4711 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4712 ++j, ++sqp) {
4713 k = find_first_bit(sqp->in_use_bm,
4714 sdebug_max_queue);
4715 if (k != sdebug_max_queue) {
4716 res = -EBUSY; /* queued commands */
4717 break;
4718 }
4719 }
4720 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004721 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004722 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4723 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004724 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004725 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004726 }
4727 return res;
4728 }
4729 return -EINVAL;
4730}
4731static DRIVER_ATTR_RW(ndelay);
4732
Akinobu Mita82069372013-10-14 22:48:04 +09004733static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004735 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736}
4737
Akinobu Mita82069372013-10-14 22:48:04 +09004738static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4739 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004741 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 char work[20];
4743
Douglas Gilbert9a051012017-12-23 12:48:10 -05004744 if (sscanf(buf, "%10s", work) == 1) {
4745 if (strncasecmp(work, "0x", 2) == 0) {
4746 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 goto opts_done;
4748 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004749 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 goto opts_done;
4751 }
4752 }
4753 return -EINVAL;
4754opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004755 sdebug_opts = opts;
4756 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4757 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004758 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 return count;
4760}
Akinobu Mita82069372013-10-14 22:48:04 +09004761static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Akinobu Mita82069372013-10-14 22:48:04 +09004763static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004765 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766}
Akinobu Mita82069372013-10-14 22:48:04 +09004767static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4768 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004770 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
4772 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004773 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 return count;
4775 }
4776 return -EINVAL;
4777}
Akinobu Mita82069372013-10-14 22:48:04 +09004778static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779
Akinobu Mita82069372013-10-14 22:48:04 +09004780static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004782 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783}
Akinobu Mita82069372013-10-14 22:48:04 +09004784static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4785 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004787 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788
4789 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004790 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 return count;
4792 }
4793 return -EINVAL;
4794}
Akinobu Mita82069372013-10-14 22:48:04 +09004795static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796
Akinobu Mita82069372013-10-14 22:48:04 +09004797static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004798{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004799 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004800}
Akinobu Mita82069372013-10-14 22:48:04 +09004801static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4802 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004803{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004804 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004805
4806 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004807 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004808 sdebug_fake_rw = (sdebug_fake_rw > 0);
4809 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004810 if ((0 == n) && (NULL == fake_storep)) {
4811 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004812 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004813 1048576;
4814
4815 fake_storep = vmalloc(sz);
4816 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004817 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004818 return -ENOMEM;
4819 }
4820 memset(fake_storep, 0, sz);
4821 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004822 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004823 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004824 return count;
4825 }
4826 return -EINVAL;
4827}
Akinobu Mita82069372013-10-14 22:48:04 +09004828static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004829
Akinobu Mita82069372013-10-14 22:48:04 +09004830static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004831{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004832 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004833}
Akinobu Mita82069372013-10-14 22:48:04 +09004834static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4835 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004836{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004837 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004838
4839 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004840 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004841 return count;
4842 }
4843 return -EINVAL;
4844}
Akinobu Mita82069372013-10-14 22:48:04 +09004845static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004846
Akinobu Mita82069372013-10-14 22:48:04 +09004847static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004849 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850}
Akinobu Mita82069372013-10-14 22:48:04 +09004851static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4852 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004854 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855
4856 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004857 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 sdebug_max_tgts_luns();
4859 return count;
4860 }
4861 return -EINVAL;
4862}
Akinobu Mita82069372013-10-14 22:48:04 +09004863static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
Akinobu Mita82069372013-10-14 22:48:04 +09004865static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004867 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868}
Akinobu Mita82069372013-10-14 22:48:04 +09004869static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870
Akinobu Mita82069372013-10-14 22:48:04 +09004871static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004873 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874}
Akinobu Mita82069372013-10-14 22:48:04 +09004875static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876
Akinobu Mita82069372013-10-14 22:48:04 +09004877static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004879 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880}
Akinobu Mita82069372013-10-14 22:48:04 +09004881static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4882 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004884 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885
4886 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004887 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004888 if (nth && !sdebug_statistics) {
4889 pr_info("every_nth needs statistics=1, set it\n");
4890 sdebug_statistics = true;
4891 }
4892 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 return count;
4894 }
4895 return -EINVAL;
4896}
Akinobu Mita82069372013-10-14 22:48:04 +09004897static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898
Akinobu Mita82069372013-10-14 22:48:04 +09004899static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004901 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902}
Akinobu Mita82069372013-10-14 22:48:04 +09004903static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4904 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004906 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004907 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908
4909 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004910 if (n > 256) {
4911 pr_warn("max_luns can be no more than 256\n");
4912 return -EINVAL;
4913 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004914 changed = (sdebug_max_luns != n);
4915 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004917 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004918 struct sdebug_host_info *sdhp;
4919 struct sdebug_dev_info *dp;
4920
4921 spin_lock(&sdebug_host_list_lock);
4922 list_for_each_entry(sdhp, &sdebug_host_list,
4923 host_list) {
4924 list_for_each_entry(dp, &sdhp->dev_info_list,
4925 dev_list) {
4926 set_bit(SDEBUG_UA_LUNS_CHANGED,
4927 dp->uas_bm);
4928 }
4929 }
4930 spin_unlock(&sdebug_host_list_lock);
4931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 return count;
4933 }
4934 return -EINVAL;
4935}
Akinobu Mita82069372013-10-14 22:48:04 +09004936static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937
Akinobu Mita82069372013-10-14 22:48:04 +09004938static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004939{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004940 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004941}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004942/* N.B. max_queue can be changed while there are queued commands. In flight
4943 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004944static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4945 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004946{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004947 int j, n, k, a;
4948 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004949
4950 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004951 (n <= SDEBUG_CANQUEUE)) {
4952 block_unblock_all_queues(true);
4953 k = 0;
4954 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4955 ++j, ++sqp) {
4956 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4957 if (a > k)
4958 k = a;
4959 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004960 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004961 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004962 atomic_set(&retired_max_queue, 0);
4963 else if (k >= n)
4964 atomic_set(&retired_max_queue, k + 1);
4965 else
4966 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004967 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004968 return count;
4969 }
4970 return -EINVAL;
4971}
Akinobu Mita82069372013-10-14 22:48:04 +09004972static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004973
Akinobu Mita82069372013-10-14 22:48:04 +09004974static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004975{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004976 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004977}
Akinobu Mita82069372013-10-14 22:48:04 +09004978static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004979
Akinobu Mita82069372013-10-14 22:48:04 +09004980static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004982 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983}
Akinobu Mita82069372013-10-14 22:48:04 +09004984static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985
Akinobu Mita82069372013-10-14 22:48:04 +09004986static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004987{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004988 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004989}
Akinobu Mita82069372013-10-14 22:48:04 +09004990static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4991 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004992{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004993 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004994 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004995
4996 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004997 changed = (sdebug_virtual_gb != n);
4998 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004999 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05005000 if (changed) {
5001 struct sdebug_host_info *sdhp;
5002 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005003
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05005004 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05005005 list_for_each_entry(sdhp, &sdebug_host_list,
5006 host_list) {
5007 list_for_each_entry(dp, &sdhp->dev_info_list,
5008 dev_list) {
5009 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
5010 dp->uas_bm);
5011 }
5012 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05005013 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05005014 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005015 return count;
5016 }
5017 return -EINVAL;
5018}
Akinobu Mita82069372013-10-14 22:48:04 +09005019static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005020
Akinobu Mita82069372013-10-14 22:48:04 +09005021static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005023 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024}
5025
Douglas Gilbertfd321192016-04-25 12:16:33 -04005026static int sdebug_add_adapter(void);
5027static void sdebug_remove_adapter(void);
5028
Akinobu Mita82069372013-10-14 22:48:04 +09005029static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
5030 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09005032 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09005034 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 if (delta_hosts > 0) {
5037 do {
5038 sdebug_add_adapter();
5039 } while (--delta_hosts);
5040 } else if (delta_hosts < 0) {
5041 do {
5042 sdebug_remove_adapter();
5043 } while (++delta_hosts);
5044 }
5045 return count;
5046}
Akinobu Mita82069372013-10-14 22:48:04 +09005047static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048
Akinobu Mita82069372013-10-14 22:48:04 +09005049static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04005050{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005051 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005052}
Akinobu Mita82069372013-10-14 22:48:04 +09005053static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
5054 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04005055{
5056 int n;
5057
5058 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005059 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04005060 return count;
5061 }
5062 return -EINVAL;
5063}
Akinobu Mita82069372013-10-14 22:48:04 +09005064static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005065
Douglas Gilbertc4837392016-05-06 00:40:26 -04005066static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5067{
5068 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5069}
5070static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5071 size_t count)
5072{
5073 int n;
5074
5075 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5076 if (n > 0)
5077 sdebug_statistics = true;
5078 else {
5079 clear_queue_stats();
5080 sdebug_statistics = false;
5081 }
5082 return count;
5083 }
5084 return -EINVAL;
5085}
5086static DRIVER_ATTR_RW(statistics);
5087
Akinobu Mita82069372013-10-14 22:48:04 +09005088static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04005089{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005090 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005091}
Akinobu Mita82069372013-10-14 22:48:04 +09005092static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005093
Douglas Gilbertc4837392016-05-06 00:40:26 -04005094static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5095{
5096 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5097}
5098static DRIVER_ATTR_RO(submit_queues);
5099
Akinobu Mita82069372013-10-14 22:48:04 +09005100static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005101{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005102 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005103}
Akinobu Mita82069372013-10-14 22:48:04 +09005104static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005105
Akinobu Mita82069372013-10-14 22:48:04 +09005106static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005107{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005108 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005109}
Akinobu Mita82069372013-10-14 22:48:04 +09005110static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005111
Akinobu Mita82069372013-10-14 22:48:04 +09005112static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005113{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005114 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005115}
Akinobu Mita82069372013-10-14 22:48:04 +09005116static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005117
Akinobu Mita82069372013-10-14 22:48:04 +09005118static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005119{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005120 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005121}
Akinobu Mita82069372013-10-14 22:48:04 +09005122static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005123
Akinobu Mita82069372013-10-14 22:48:04 +09005124static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005125{
5126 ssize_t count;
5127
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005128 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04005129 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
5130 sdebug_store_sectors);
5131
Tejun Heoc7badc92015-02-13 14:37:51 -08005132 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5133 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005134 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08005135 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04005136
5137 return count;
5138}
Akinobu Mita82069372013-10-14 22:48:04 +09005139static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005140
Akinobu Mita82069372013-10-14 22:48:04 +09005141static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02005142{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005143 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02005144}
Akinobu Mita82069372013-10-14 22:48:04 +09005145static ssize_t removable_store(struct device_driver *ddp, const char *buf,
5146 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02005147{
5148 int n;
5149
5150 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005151 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02005152 return count;
5153 }
5154 return -EINVAL;
5155}
Akinobu Mita82069372013-10-14 22:48:04 +09005156static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02005157
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005158static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5159{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005160 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005161}
Douglas Gilbert185dd232016-04-25 12:16:29 -04005162/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005163static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5164 size_t count)
5165{
Douglas Gilbert185dd232016-04-25 12:16:29 -04005166 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005167
5168 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04005169 sdebug_host_lock = (n > 0);
5170 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005171 }
5172 return -EINVAL;
5173}
5174static DRIVER_ATTR_RW(host_lock);
5175
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005176static ssize_t strict_show(struct device_driver *ddp, char *buf)
5177{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005178 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005179}
5180static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5181 size_t count)
5182{
5183 int n;
5184
5185 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005186 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005187 return count;
5188 }
5189 return -EINVAL;
5190}
5191static DRIVER_ATTR_RW(strict);
5192
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005193static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
5194{
5195 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
5196}
5197static DRIVER_ATTR_RO(uuid_ctl);
5198
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005199static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
5200{
5201 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
5202}
5203static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
5204 size_t count)
5205{
5206 int ret, n;
5207
5208 ret = kstrtoint(buf, 0, &n);
5209 if (ret)
5210 return ret;
5211 sdebug_cdb_len = n;
5212 all_config_cdb_len();
5213 return count;
5214}
5215static DRIVER_ATTR_RW(cdb_len);
5216
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005217
Akinobu Mita82069372013-10-14 22:48:04 +09005218/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04005219 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
5220 files (over those found in the /sys/module/scsi_debug/parameters
5221 directory) is that auxiliary actions can be triggered when an attribute
5222 is changed. For example see: sdebug_add_host_store() above.
5223 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005224
Akinobu Mita82069372013-10-14 22:48:04 +09005225static struct attribute *sdebug_drv_attrs[] = {
5226 &driver_attr_delay.attr,
5227 &driver_attr_opts.attr,
5228 &driver_attr_ptype.attr,
5229 &driver_attr_dsense.attr,
5230 &driver_attr_fake_rw.attr,
5231 &driver_attr_no_lun_0.attr,
5232 &driver_attr_num_tgts.attr,
5233 &driver_attr_dev_size_mb.attr,
5234 &driver_attr_num_parts.attr,
5235 &driver_attr_every_nth.attr,
5236 &driver_attr_max_luns.attr,
5237 &driver_attr_max_queue.attr,
5238 &driver_attr_no_uld.attr,
5239 &driver_attr_scsi_level.attr,
5240 &driver_attr_virtual_gb.attr,
5241 &driver_attr_add_host.attr,
5242 &driver_attr_vpd_use_hostno.attr,
5243 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005244 &driver_attr_statistics.attr,
5245 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005246 &driver_attr_dix.attr,
5247 &driver_attr_dif.attr,
5248 &driver_attr_guard.attr,
5249 &driver_attr_ato.attr,
5250 &driver_attr_map.attr,
5251 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005252 &driver_attr_host_lock.attr,
5253 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005254 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005255 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005256 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005257 NULL,
5258};
5259ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005261static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005262
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263static int __init scsi_debug_init(void)
5264{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005265 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 int host_to_add;
5267 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005268 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005270 atomic_set(&retired_max_queue, 0);
5271
Douglas Gilbert773642d2016-04-25 12:16:28 -04005272 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005273 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005274 sdebug_ndelay = 0;
5275 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005276 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005277
Douglas Gilbert773642d2016-04-25 12:16:28 -04005278 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04005279 case 512:
5280 case 1024:
5281 case 2048:
5282 case 4096:
5283 break;
5284 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005285 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005286 return -EINVAL;
5287 }
5288
Douglas Gilbert773642d2016-04-25 12:16:28 -04005289 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005290 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005291 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005292 case T10_PI_TYPE1_PROTECTION:
5293 case T10_PI_TYPE2_PROTECTION:
5294 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005295 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005296 break;
5297
5298 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005299 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005300 return -EINVAL;
5301 }
5302
Douglas Gilbert773642d2016-04-25 12:16:28 -04005303 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005304 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005305 return -EINVAL;
5306 }
5307
Douglas Gilbert773642d2016-04-25 12:16:28 -04005308 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005309 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005310 return -EINVAL;
5311 }
5312
Douglas Gilbert773642d2016-04-25 12:16:28 -04005313 if (sdebug_physblk_exp > 15) {
5314 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005315 return -EINVAL;
5316 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005317 if (sdebug_max_luns > 256) {
5318 pr_warn("max_luns can be no more than 256, use default\n");
5319 sdebug_max_luns = DEF_MAX_LUNS;
5320 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005321
Douglas Gilbert773642d2016-04-25 12:16:28 -04005322 if (sdebug_lowest_aligned > 0x3fff) {
5323 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005324 return -EINVAL;
5325 }
5326
Douglas Gilbertc4837392016-05-06 00:40:26 -04005327 if (submit_queues < 1) {
5328 pr_err("submit_queues must be 1 or more\n");
5329 return -EINVAL;
5330 }
5331 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5332 GFP_KERNEL);
5333 if (sdebug_q_arr == NULL)
5334 return -ENOMEM;
5335 for (k = 0; k < submit_queues; ++k)
5336 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5337
Douglas Gilbert773642d2016-04-25 12:16:28 -04005338 if (sdebug_dev_size_mb < 1)
5339 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5340 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5341 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005342 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343
5344 /* play around with geometry, don't waste too much on track 0 */
5345 sdebug_heads = 8;
5346 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005347 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005349 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005350 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5352 (sdebug_sectors_per * sdebug_heads);
5353 if (sdebug_cylinders_per >= 1024) {
5354 /* other LLDs do this; implies >= 1GB ram disk ... */
5355 sdebug_heads = 255;
5356 sdebug_sectors_per = 63;
5357 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5358 (sdebug_sectors_per * sdebug_heads);
5359 }
5360
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005361 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005362 fake_storep = vmalloc(sz);
5363 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005364 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005365 ret = -ENOMEM;
5366 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005367 }
5368 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005369 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005370 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372
Douglas Gilbert773642d2016-04-25 12:16:28 -04005373 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005374 int dif_size;
5375
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005376 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005377 dif_storep = vmalloc(dif_size);
5378
Tomas Winklerc12879702015-07-28 16:54:20 +03005379 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005380
5381 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005382 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005383 ret = -ENOMEM;
5384 goto free_vm;
5385 }
5386
5387 memset(dif_storep, 0xff, dif_size);
5388 }
5389
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005390 /* Logical Block Provisioning */
5391 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005392 sdebug_unmap_max_blocks =
5393 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005394
Douglas Gilbert773642d2016-04-25 12:16:28 -04005395 sdebug_unmap_max_desc =
5396 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005397
Douglas Gilbert773642d2016-04-25 12:16:28 -04005398 sdebug_unmap_granularity =
5399 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005400
Douglas Gilbert773642d2016-04-25 12:16:28 -04005401 if (sdebug_unmap_alignment &&
5402 sdebug_unmap_granularity <=
5403 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005404 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005405 ret = -EINVAL;
5406 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005407 }
5408
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005409 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5410 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005411
Tomas Winklerc12879702015-07-28 16:54:20 +03005412 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005413
5414 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005415 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005416 ret = -ENOMEM;
5417 goto free_vm;
5418 }
5419
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005420 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005421
5422 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005423 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005424 map_region(0, 2);
5425 }
5426
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005427 pseudo_primary = root_device_register("pseudo_0");
5428 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005429 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005430 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005431 goto free_vm;
5432 }
5433 ret = bus_register(&pseudo_lld_bus);
5434 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005435 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005436 goto dev_unreg;
5437 }
5438 ret = driver_register(&sdebug_driverfs_driver);
5439 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005440 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005441 goto bus_unreg;
5442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443
Douglas Gilbert773642d2016-04-25 12:16:28 -04005444 host_to_add = sdebug_add_host;
5445 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446
Douglas Gilbert9a051012017-12-23 12:48:10 -05005447 for (k = 0; k < host_to_add; k++) {
5448 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005449 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005450 break;
5451 }
5452 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453
Douglas Gilbert773642d2016-04-25 12:16:28 -04005454 if (sdebug_verbose)
5455 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005456
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005458
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005459bus_unreg:
5460 bus_unregister(&pseudo_lld_bus);
5461dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005462 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005463free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005464 vfree(map_storep);
5465 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005466 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005467free_q_arr:
5468 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005469 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470}
5471
5472static void __exit scsi_debug_exit(void)
5473{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005474 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475
5476 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005477 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 for (; k; k--)
5479 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 driver_unregister(&sdebug_driverfs_driver);
5481 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005482 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005484 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005485 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005487 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488}
5489
5490device_initcall(scsi_debug_init);
5491module_exit(scsi_debug_exit);
5492
John Pittman91d4c752018-02-09 21:12:43 -05005493static void sdebug_release_adapter(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005495 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496
5497 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005498 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499}
5500
5501static int sdebug_add_adapter(void)
5502{
5503 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005504 int error = 0;
5505 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005506 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507
Douglas Gilbert9a051012017-12-23 12:48:10 -05005508 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5509 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005510 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005511 return -ENOMEM;
5512 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513
Douglas Gilbert9a051012017-12-23 12:48:10 -05005514 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515
Douglas Gilbert773642d2016-04-25 12:16:28 -04005516 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005517 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005518 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5519 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005520 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005521 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005523 }
5524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525
Douglas Gilbert9a051012017-12-23 12:48:10 -05005526 spin_lock(&sdebug_host_list_lock);
5527 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5528 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529
Douglas Gilbert9a051012017-12-23 12:48:10 -05005530 sdbg_host->dev.bus = &pseudo_lld_bus;
5531 sdbg_host->dev.parent = pseudo_primary;
5532 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005533 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534
Douglas Gilbert9a051012017-12-23 12:48:10 -05005535 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536
Douglas Gilbert9a051012017-12-23 12:48:10 -05005537 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538 goto clean;
5539
Douglas Gilbert773642d2016-04-25 12:16:28 -04005540 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005541 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542
5543clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005544 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5545 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 list_del(&sdbg_devinfo->dev_list);
5547 kfree(sdbg_devinfo);
5548 }
5549
5550 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005551 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552}
5553
5554static void sdebug_remove_adapter(void)
5555{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005556 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557
Douglas Gilbert9a051012017-12-23 12:48:10 -05005558 spin_lock(&sdebug_host_list_lock);
5559 if (!list_empty(&sdebug_host_list)) {
5560 sdbg_host = list_entry(sdebug_host_list.prev,
5561 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 list_del(&sdbg_host->host_list);
5563 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005564 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565
5566 if (!sdbg_host)
5567 return;
5568
Douglas Gilbert773642d2016-04-25 12:16:28 -04005569 device_unregister(&sdbg_host->dev);
5570 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005571}
5572
Douglas Gilbertfd321192016-04-25 12:16:33 -04005573static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005574{
5575 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005576 struct sdebug_dev_info *devip;
5577
Douglas Gilbertc4837392016-05-06 00:40:26 -04005578 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005579 devip = (struct sdebug_dev_info *)sdev->hostdata;
5580 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005581 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005582 return -ENODEV;
5583 }
5584 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005585
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005586 if (qdepth < 1)
5587 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005588 /* allow to exceed max host qc_arr elements for testing */
5589 if (qdepth > SDEBUG_CANQUEUE + 10)
5590 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005591 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005592
Douglas Gilbert773642d2016-04-25 12:16:28 -04005593 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005594 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005595 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005596 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005597 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005598 return sdev->queue_depth;
5599}
5600
Douglas Gilbertc4837392016-05-06 00:40:26 -04005601static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005602{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005603 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005604 if (sdebug_every_nth < -1)
5605 sdebug_every_nth = -1;
5606 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005607 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005608 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005609 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005610 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005611 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005612 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005613}
5614
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005615static bool fake_host_busy(struct scsi_cmnd *scp)
5616{
5617 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5618 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5619}
5620
Douglas Gilbertfd321192016-04-25 12:16:33 -04005621static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5622 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005623{
5624 u8 sdeb_i;
5625 struct scsi_device *sdp = scp->device;
5626 const struct opcode_info_t *oip;
5627 const struct opcode_info_t *r_oip;
5628 struct sdebug_dev_info *devip;
5629 u8 *cmd = scp->cmnd;
5630 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5631 int k, na;
5632 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005633 u32 flags;
5634 u16 sa;
5635 u8 opcode = cmd[0];
5636 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005637
5638 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005639 if (sdebug_statistics)
5640 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005641 if (unlikely(sdebug_verbose &&
5642 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005643 char b[120];
5644 int n, len, sb;
5645
5646 len = scp->cmd_len;
5647 sb = (int)sizeof(b);
5648 if (len > 32)
5649 strcpy(b, "too long, over 32 bytes");
5650 else {
5651 for (k = 0, n = 0; k < len && n < sb; ++k)
5652 n += scnprintf(b + n, sb - n, "%02x ",
5653 (u32)cmd[k]);
5654 }
Bart Van Assche458df782018-01-26 08:52:19 -08005655 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5656 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005657 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005658 if (fake_host_busy(scp))
5659 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005660 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005661 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5662 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005663
5664 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5665 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5666 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005667 if (unlikely(!devip)) {
5668 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005669 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005670 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005671 }
5672 na = oip->num_attached;
5673 r_pfp = oip->pfp;
5674 if (na) { /* multiple commands with this opcode */
5675 r_oip = oip;
5676 if (FF_SA & r_oip->flags) {
5677 if (F_SA_LOW & oip->flags)
5678 sa = 0x1f & cmd[1];
5679 else
5680 sa = get_unaligned_be16(cmd + 8);
5681 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5682 if (opcode == oip->opcode && sa == oip->sa)
5683 break;
5684 }
5685 } else { /* since no service action only check opcode */
5686 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5687 if (opcode == oip->opcode)
5688 break;
5689 }
5690 }
5691 if (k > na) {
5692 if (F_SA_LOW & r_oip->flags)
5693 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5694 else if (F_SA_HIGH & r_oip->flags)
5695 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5696 else
5697 mk_sense_invalid_opcode(scp);
5698 goto check_cond;
5699 }
5700 } /* else (when na==0) we assume the oip is a match */
5701 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005702 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005703 mk_sense_invalid_opcode(scp);
5704 goto check_cond;
5705 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005706 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005707 if (sdebug_verbose)
5708 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5709 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005710 mk_sense_invalid_opcode(scp);
5711 goto check_cond;
5712 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005713 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005714 u8 rem;
5715 int j;
5716
5717 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5718 rem = ~oip->len_mask[k] & cmd[k];
5719 if (rem) {
5720 for (j = 7; j >= 0; --j, rem <<= 1) {
5721 if (0x80 & rem)
5722 break;
5723 }
5724 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5725 goto check_cond;
5726 }
5727 }
5728 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005729 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005730 find_first_bit(devip->uas_bm,
5731 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005732 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005733 if (errsts)
5734 goto check_cond;
5735 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005736 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005737 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005738 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005739 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5740 "%s\n", my_name, "initializing command "
5741 "required");
5742 errsts = check_condition_result;
5743 goto fini;
5744 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005745 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005746 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005747 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005748 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005749 return 0; /* ignore command: make trouble */
5750 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005751 if (likely(oip->pfp))
5752 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005753 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5754 errsts = r_pfp(scp, devip);
Douglas Gilbert80c49562018-02-09 21:36:39 -05005755 if (errsts & SDEG_RES_IMMED_MASK) {
5756 errsts &= ~SDEG_RES_IMMED_MASK;
5757 flags |= F_DELAY_OVERR;
5758 flags &= ~F_LONG_DELAY;
5759 }
5760
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005761
5762fini:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005763 if (F_DELAY_OVERR & flags)
5764 return schedule_resp(scp, devip, errsts, 0, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05005765 else if ((sdebug_jdelay || sdebug_ndelay) && (flags & F_LONG_DELAY)) {
5766 /*
5767 * If any delay is active, want F_LONG_DELAY to be at least 1
5768 * second and if sdebug_jdelay>0 want a long delay of that
5769 * many seconds.
5770 */
5771 int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
5772
5773 jdelay = mult_frac(USER_HZ * jdelay, HZ, USER_HZ);
5774 return schedule_resp(scp, devip, errsts, jdelay, 0);
5775 } else
Douglas Gilbert10bde982018-01-10 16:57:31 -05005776 return schedule_resp(scp, devip, errsts, sdebug_jdelay,
5777 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005778check_cond:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005779 return schedule_resp(scp, devip, check_condition_result, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005780err_out:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005781 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005782}
5783
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005784static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005785 .show_info = scsi_debug_show_info,
5786 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005787 .proc_name = sdebug_proc_name,
5788 .name = "SCSI DEBUG",
5789 .info = scsi_debug_info,
5790 .slave_alloc = scsi_debug_slave_alloc,
5791 .slave_configure = scsi_debug_slave_configure,
5792 .slave_destroy = scsi_debug_slave_destroy,
5793 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005794 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005795 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005796 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005797 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005798 .eh_target_reset_handler = scsi_debug_target_reset,
5799 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005800 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005801 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005802 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005803 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005804 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005805 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005806 .use_clustering = DISABLE_CLUSTERING,
5807 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005808 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005809};
5810
John Pittman91d4c752018-02-09 21:12:43 -05005811static int sdebug_driver_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005813 int error = 0;
5814 struct sdebug_host_info *sdbg_host;
5815 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005816 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817
5818 sdbg_host = to_sdebug_host(dev);
5819
Douglas Gilbert773642d2016-04-25 12:16:28 -04005820 sdebug_driver_template.can_queue = sdebug_max_queue;
5821 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005822 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005823 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5824 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005825 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005826 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005828 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005829 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005830 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005831 my_name, submit_queues, nr_cpu_ids);
5832 submit_queues = nr_cpu_ids;
5833 }
5834 /* Decide whether to tell scsi subsystem that we want mq */
5835 /* Following should give the same answer for each host */
Bart Van Assche458df782018-01-26 08:52:19 -08005836 if (shost_use_blk_mq(hpnt))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005837 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838
Douglas Gilbert9a051012017-12-23 12:48:10 -05005839 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005841 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5842 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005844 hpnt->max_id = sdebug_num_tgts;
5845 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005846 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005848 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005849
Douglas Gilbert773642d2016-04-25 12:16:28 -04005850 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005851
Christoph Hellwig8475c812016-09-11 19:35:41 +02005852 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005853 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005854 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005855 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005856 break;
5857
Christoph Hellwig8475c812016-09-11 19:35:41 +02005858 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005859 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005860 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005861 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005862 break;
5863
Christoph Hellwig8475c812016-09-11 19:35:41 +02005864 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005865 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005866 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005867 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005868 break;
5869
5870 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005871 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005872 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005873 break;
5874 }
5875
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005876 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005877
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005878 if (have_dif_prot || sdebug_dix)
5879 pr_info("host protection%s%s%s%s%s%s%s\n",
5880 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5881 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5882 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5883 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5884 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5885 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5886 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005887
Douglas Gilbert773642d2016-04-25 12:16:28 -04005888 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005889 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5890 else
5891 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5892
Douglas Gilbert773642d2016-04-25 12:16:28 -04005893 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5894 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005895 if (sdebug_every_nth) /* need stats counters for every_nth */
5896 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005897 error = scsi_add_host(hpnt, &sdbg_host->dev);
5898 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005899 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005900 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005902 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 scsi_scan_host(hpnt);
5904
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005905 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906}
5907
John Pittman91d4c752018-02-09 21:12:43 -05005908static int sdebug_driver_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005910 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005911 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912
5913 sdbg_host = to_sdebug_host(dev);
5914
5915 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005916 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 return -ENODEV;
5918 }
5919
Douglas Gilbert9a051012017-12-23 12:48:10 -05005920 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005922 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5923 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005924 list_del(&sdbg_devinfo->dev_list);
5925 kfree(sdbg_devinfo);
5926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927
Douglas Gilbert9a051012017-12-23 12:48:10 -05005928 scsi_host_put(sdbg_host->shost);
5929 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930}
5931
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005932static int pseudo_lld_bus_match(struct device *dev,
5933 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005935 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005937
5938static struct bus_type pseudo_lld_bus = {
5939 .name = "pseudo",
5940 .match = pseudo_lld_bus_match,
5941 .probe = sdebug_driver_probe,
5942 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005943 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005944};