blob: 1cb353f18d0810500a58ee9e94eb067e86722f7e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05009 * Copyright (C) 2001 - 2017 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Douglas Gilbert773642d2016-04-25 12:16:28 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040016 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Tomas Winklerc12879702015-07-28 16:54:20 +030020
21#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040027#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/types.h>
30#include <linux/string.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <linux/init.h>
34#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/vmalloc.h>
36#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020037#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050039#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040040#include <linux/spinlock.h>
41#include <linux/interrupt.h>
42#include <linux/atomic.h>
43#include <linux/hrtimer.h>
Douglas Gilbert09ba24c2016-05-06 00:40:28 -040044#include <linux/uuid.h>
Christoph Hellwig6ebf1052016-09-11 19:35:39 +020045#include <linux/t10-pi.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050046
47#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090048
Martin K. Petersen44d92692009-10-15 14:45:27 -040049#include <asm/unaligned.h>
50
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090051#include <scsi/scsi.h>
52#include <scsi/scsi_cmnd.h>
53#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <scsi/scsi_host.h>
55#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090056#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040057#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040058#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Martin K. Petersenc6a44282009-01-04 03:08:19 -050060#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Douglas Gilbert773642d2016-04-25 12:16:28 -040063/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbert9b760fd2017-12-05 00:05:49 -050064#define SDEBUG_VERSION "0187" /* format to fit INQUIRY revision field */
65static const char *sdebug_version_date = "20171202";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040066
67#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define NO_ADDITIONAL_SENSE 0x0
71#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050072#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040074#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050076#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040078#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040079#define UA_RESET_ASC 0x29
80#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050081#define TARGET_CHANGED_ASC 0x3f
82#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050083#define INSUFF_RES_ASC 0x55
84#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040085#define POWER_ON_RESET_ASCQ 0x0
86#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
87#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050088#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050090#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define THRESHOLD_EXCEEDED 0x5d
92#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050093#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050094#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
95#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Douglas Gilbert481b5e52017-12-23 12:48:14 -050096#define WRITE_ERROR_ASC 0xc
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050098/* Additional Sense Code Qualifier (ASCQ) */
99#define ACK_NAK_TO 0x3
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/* Default values for driver parameters */
102#define DEF_NUM_HOST 1
103#define DEF_NUM_TGTS 1
104#define DEF_MAX_LUNS 1
105/* With these defaults, this driver will make 1 host with 1 target
106 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
107 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500108#define DEF_ATO 1
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500109#define DEF_CDB_LEN 10
Douglas Gilbertc2206092016-04-25 12:16:31 -0400110#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500112#define DEF_DIF 0
113#define DEF_DIX 0
114#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500116#define DEF_FAKE_RW 0
117#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400118#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_LBPU 0
120#define DEF_LBPWS 0
121#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600122#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500123#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400124#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500125#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#define DEF_NUM_PARTS 0
127#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500128#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500129#define DEF_PHYSBLK_EXP 0
Lukas Herbolt86e68282017-01-26 10:00:37 +0100130#define DEF_OPT_XFERLEN_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400131#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200132#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400133#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500134#define DEF_SECTOR_SIZE 512
135#define DEF_UNMAP_ALIGNMENT 0
136#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400137#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
138#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500139#define DEF_VIRTUAL_GB 0
140#define DEF_VPD_USE_HOSTNO 1
141#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500142#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400143#define DEF_STATISTICS false
144#define DEF_SUBMIT_QUEUES 1
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400145#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400146#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400148#define SDEBUG_LUN_0_VAL 0
149
Douglas Gilbert773642d2016-04-25 12:16:28 -0400150/* bit mask values for sdebug_opts */
151#define SDEBUG_OPT_NOISE 1
152#define SDEBUG_OPT_MEDIUM_ERR 2
153#define SDEBUG_OPT_TIMEOUT 4
154#define SDEBUG_OPT_RECOVERED_ERR 8
155#define SDEBUG_OPT_TRANSPORT_ERR 16
156#define SDEBUG_OPT_DIF_ERR 32
157#define SDEBUG_OPT_DIX_ERR 64
158#define SDEBUG_OPT_MAC_TIMEOUT 128
159#define SDEBUG_OPT_SHORT_TRANSFER 0x100
160#define SDEBUG_OPT_Q_NOISE 0x200
161#define SDEBUG_OPT_ALL_TSF 0x400
162#define SDEBUG_OPT_RARE_TSF 0x800
163#define SDEBUG_OPT_N_WCE 0x1000
164#define SDEBUG_OPT_RESET_NOISE 0x2000
165#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800166#define SDEBUG_OPT_HOST_BUSY 0x8000
Douglas Gilbert773642d2016-04-25 12:16:28 -0400167#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
168 SDEBUG_OPT_RESET_NOISE)
169#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
170 SDEBUG_OPT_TRANSPORT_ERR | \
171 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800172 SDEBUG_OPT_SHORT_TRANSFER | \
173 SDEBUG_OPT_HOST_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400175 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400177 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500178 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400179 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 *
181 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400182 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400184 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500185 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400186 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
187 * This will continue on every subsequent command until some other action
188 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
189 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 */
191
Douglas Gilbertfd321192016-04-25 12:16:33 -0400192/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400193 * priority order. In the subset implemented here lower numbers have higher
194 * priority. The UA numbers should be a sequence starting from 0 with
195 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
196#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
197#define SDEBUG_UA_BUS_RESET 1
198#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500199#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500200#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500201#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
202#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
203#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400204
Douglas Gilbert773642d2016-04-25 12:16:28 -0400205/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 * sector on read commands: */
207#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500208#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
211 * or "peripheral device" addressing (value 0) */
212#define SAM2_LUN_ADDRESS_METHOD 0
213
Douglas Gilbertc4837392016-05-06 00:40:26 -0400214/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215 * (for response) per submit queue at one time. Can be reduced by max_queue
216 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219 * but cannot exceed SDEBUG_CANQUEUE .
220 */
221#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
222#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400223#define DEF_CMD_PER_LUN 255
224
Douglas Gilbertfd321192016-04-25 12:16:33 -0400225#define F_D_IN 1
226#define F_D_OUT 2
227#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
228#define F_D_UNKN 8
229#define F_RL_WLUN_OK 0x10
230#define F_SKIP_UA 0x20
231#define F_DELAY_OVERR 0x40
232#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
233#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
234#define F_INV_OP 0x200
235#define F_FAKE_RW 0x400
236#define F_M_ACCESS 0x800 /* media access */
237
238#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500239#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400240#define FF_SA (F_SA_HIGH | F_SA_LOW)
241
242#define SDEBUG_MAX_PARTS 4
243
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400244#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400245
246
247struct sdebug_dev_info {
248 struct list_head dev_list;
249 unsigned int channel;
250 unsigned int target;
251 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200252 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400253 struct sdebug_host_info *sdbg_host;
254 unsigned long uas_bm[1];
255 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400256 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400257 bool used;
258};
259
260struct sdebug_host_info {
261 struct list_head host_list;
262 struct Scsi_Host *shost;
263 struct device dev;
264 struct list_head dev_info_list;
265};
266
267#define to_sdebug_host(d) \
268 container_of(d, struct sdebug_host_info, dev)
269
Douglas Gilbert10bde982018-01-10 16:57:31 -0500270enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
271 SDEB_DEFER_WQ = 2};
272
Douglas Gilbertfd321192016-04-25 12:16:33 -0400273struct sdebug_defer {
274 struct hrtimer hrt;
275 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400276 int sqa_idx; /* index of sdebug_queue array */
277 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
278 int issuing_cpu;
Douglas Gilbert10bde982018-01-10 16:57:31 -0500279 bool init_hrt;
280 bool init_wq;
281 enum sdeb_defer_type defer_t;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400282};
283
284struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400285 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
286 * instance indicates this slot is in use.
287 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400288 struct sdebug_defer *sd_dp;
289 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400290 unsigned int inj_recovered:1;
291 unsigned int inj_transport:1;
292 unsigned int inj_dif:1;
293 unsigned int inj_dix:1;
294 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800295 unsigned int inj_host_busy:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400296};
297
Douglas Gilbertc4837392016-05-06 00:40:26 -0400298struct sdebug_queue {
299 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
300 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
301 spinlock_t qc_lock;
302 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400303};
304
Douglas Gilbertc4837392016-05-06 00:40:26 -0400305static atomic_t sdebug_cmnd_count; /* number of incoming commands */
306static atomic_t sdebug_completions; /* count of deferred completions */
307static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
308static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
309
Douglas Gilbertfd321192016-04-25 12:16:33 -0400310struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400311 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
312 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400313 u8 opcode; /* if num_attached > 0, preferred */
314 u16 sa; /* service action */
315 u32 flags; /* OR-ed set of SDEB_F_* */
316 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
317 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500318 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
319 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400320};
321
322/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500323enum sdeb_opcode_index {
324 SDEB_I_INVALID_OPCODE = 0,
325 SDEB_I_INQUIRY = 1,
326 SDEB_I_REPORT_LUNS = 2,
327 SDEB_I_REQUEST_SENSE = 3,
328 SDEB_I_TEST_UNIT_READY = 4,
329 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
330 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
331 SDEB_I_LOG_SENSE = 7,
332 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
333 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
334 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
335 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500336 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
337 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500338 SDEB_I_MAINT_IN = 14,
339 SDEB_I_MAINT_OUT = 15,
340 SDEB_I_VERIFY = 16, /* 10 only */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500341 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500342 SDEB_I_RESERVE = 18, /* 6, 10 */
343 SDEB_I_RELEASE = 19, /* 6, 10 */
344 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
345 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
346 SDEB_I_ATA_PT = 22, /* 12, 16 */
347 SDEB_I_SEND_DIAG = 23,
348 SDEB_I_UNMAP = 24,
349 SDEB_I_XDWRITEREAD = 25, /* 10 only */
350 SDEB_I_WRITE_BUFFER = 26,
351 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
352 SDEB_I_SYNC_CACHE = 28, /* 10 only */
353 SDEB_I_COMP_WRITE = 29,
Douglas Gilbert9a051012017-12-23 12:48:10 -0500354 SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500355};
356
Douglas Gilbertc4837392016-05-06 00:40:26 -0400357
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500358static const unsigned char opcode_ind_arr[256] = {
359/* 0x0; 0x0->0x1f: 6 byte cdbs */
360 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
361 0, 0, 0, 0,
362 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
363 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
364 SDEB_I_RELEASE,
365 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
366 SDEB_I_ALLOW_REMOVAL, 0,
367/* 0x20; 0x20->0x3f: 10 byte cdbs */
368 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
369 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
370 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
371 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
372/* 0x40; 0x40->0x5f: 10 byte cdbs */
373 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
374 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
375 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
376 SDEB_I_RELEASE,
377 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400378/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381 0, SDEB_I_VARIABLE_LEN,
382/* 0x80; 0x80->0x9f: 16 byte cdbs */
383 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
384 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
385 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500386 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500387/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
388 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
389 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500390 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
391 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500392 0, 0, 0, 0, 0, 0, 0, 0,
393 0, 0, 0, 0, 0, 0, 0, 0,
394/* 0xc0; 0xc0->0xff: vendor specific */
395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399};
400
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500401static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
402static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
403static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
404static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
405static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
406static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
407static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
408static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
409static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500410static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500411static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
412static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
413static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
414static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
415static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500416static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
417static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500418static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
419static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
420static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500421static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500422static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500423
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500424/*
425 * The following are overflow arrays for cdbs that "hit" the same index in
426 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
427 * should be placed in opcode_info_arr[], the others should be placed here.
428 */
429static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500430 {0, 0x1a, 0, F_D_IN, NULL, NULL,
431 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
432};
433
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500434static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500435 {0, 0x15, 0, F_D_OUT, NULL, NULL,
436 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
437};
438
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500439static const struct opcode_info_t read_iarr[] = {
440 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500441 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500442 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500443 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500444 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500445 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500446 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500447 0xc7, 0, 0, 0, 0} },
448};
449
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500450static const struct opcode_info_t write_iarr[] = {
451 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
452 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
453 0, 0, 0, 0, 0, 0} },
454 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
455 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
456 0, 0, 0} },
457 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
458 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
459 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500460};
461
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500462static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500463 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
464 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500465 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500466};
467
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500468static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
469 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500470 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500471 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500472 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
473 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
474 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500475};
476
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500477static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500478 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500479 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500480 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500481 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500482 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500483 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500484};
485
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500486static const struct opcode_info_t write_same_iarr[] = {
487 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500488 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500489 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500490};
491
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500492static const struct opcode_info_t reserve_iarr[] = {
493 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500494 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
495};
496
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500497static const struct opcode_info_t release_iarr[] = {
498 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500499 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
500};
501
502
503/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
504 * plus the terminating elements for logic that scans this table such as
505 * REPORT SUPPORTED OPERATION CODES. */
506static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
507/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500508 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500509 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500510 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500511 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
512 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
513 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500514 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500515 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
516 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
517 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
518 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500519/* 5 */
520 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
521 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
522 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
523 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
524 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
525 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
526 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500527 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
528 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500529 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500530 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
531 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500532 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
533 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
534 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500535/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500536 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
537 resp_write_dt0, write_iarr, /* WRITE(16) */
538 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
539 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* WRITE(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500540 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
541 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500542 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
543 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
544 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
545 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500546 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
547 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
548 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500549 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
550 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
551 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
552 0xff, 0, 0xc7, 0, 0, 0, 0} },
553/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500554 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
555 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500556 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500557 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
558 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500559 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
560 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
561 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
562 0xff, 0xff} },
563 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
564 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500565 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
566 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500567 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
568 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500569 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
570 0} },
571/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500572 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
573 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500574 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
575 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
576 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
577 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
578 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
579 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500580 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500581 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500582/* 25 */
583 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500584 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500585 0, 0, 0, 0, 0, 0} }, /* XDWRITEREAD(10) */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500586 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
587 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
588 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500589 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
590 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
591 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
592 0, 0, 0, 0, 0} },
593 {0, 0x35, 0, F_DELAY_OVERR | FF_MEDIA_IO, NULL, NULL, /* SYNC_CACHE */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500594 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500595 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500596 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500597 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500598 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500599
600/* 30 */
601 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
602 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
603};
604
Douglas Gilbert773642d2016-04-25 12:16:28 -0400605static int sdebug_add_host = DEF_NUM_HOST;
606static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500607static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400608static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400609static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
610static int sdebug_dif = DEF_DIF;
611static int sdebug_dix = DEF_DIX;
612static int sdebug_dsense = DEF_D_SENSE;
613static int sdebug_every_nth = DEF_EVERY_NTH;
614static int sdebug_fake_rw = DEF_FAKE_RW;
615static unsigned int sdebug_guard = DEF_GUARD;
616static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
617static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400618static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400619static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400620static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400621static int sdebug_no_lun_0 = DEF_NO_LUN_0;
622static int sdebug_no_uld;
623static int sdebug_num_parts = DEF_NUM_PARTS;
624static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
625static int sdebug_opt_blks = DEF_OPT_BLKS;
626static int sdebug_opts = DEF_OPTS;
627static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100628static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400629static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400630static int sdebug_scsi_level = DEF_SCSI_LEVEL;
631static int sdebug_sector_size = DEF_SECTOR_SIZE;
632static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
633static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
634static unsigned int sdebug_lbpu = DEF_LBPU;
635static unsigned int sdebug_lbpws = DEF_LBPWS;
636static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
637static unsigned int sdebug_lbprz = DEF_LBPRZ;
638static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
639static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
640static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
641static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
642static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400643static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400644static bool sdebug_removable = DEF_REMOVABLE;
645static bool sdebug_clustering;
646static bool sdebug_host_lock = DEF_HOST_LOCK;
647static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500648static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400649static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400650static bool have_dif_prot;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400651static bool sdebug_statistics = DEF_STATISTICS;
652static bool sdebug_mq_active;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400654static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655static sector_t sdebug_capacity; /* in sectors */
656
657/* old BIOS stuff, kernel may get rid of them but some mode sense pages
658 may still need them */
659static int sdebug_heads; /* heads per disk */
660static int sdebug_cylinders_per; /* cylinders per surface */
661static int sdebug_sectors_per; /* sectors per cylinder */
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663static LIST_HEAD(sdebug_host_list);
664static DEFINE_SPINLOCK(sdebug_host_list_lock);
665
Douglas Gilbertfd321192016-04-25 12:16:33 -0400666static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200667static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400668static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Martin K. Petersen44d92692009-10-15 14:45:27 -0400670static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400671static int num_aborts;
672static int num_dev_resets;
673static int num_target_resets;
674static int num_bus_resets;
675static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500676static int dix_writes;
677static int dix_reads;
678static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Douglas Gilbertc4837392016-05-06 00:40:26 -0400680static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
681static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683static DEFINE_RWLOCK(atomic_rw);
684
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400685static char sdebug_proc_name[] = MY_NAME;
686static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688static struct bus_type pseudo_lld_bus;
689
690static struct device_driver sdebug_driverfs_driver = {
691 .name = sdebug_proc_name,
692 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693};
694
695static const int check_condition_result =
696 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
697
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500698static const int illegal_condition_result =
699 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
700
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400701static const int device_qfull_result =
702 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
703
Douglas Gilbertfd321192016-04-25 12:16:33 -0400704
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400705/* Only do the extra work involved in logical block provisioning if one or
706 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
707 * real reads and writes (i.e. not skipping them for speed).
708 */
709static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400710{
711 return 0 == sdebug_fake_rw &&
712 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
713}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400714
Akinobu Mita14faa942013-09-18 21:27:24 +0900715static void *fake_store(unsigned long long lba)
716{
717 lba = do_div(lba, sdebug_store_sectors);
718
Douglas Gilbert773642d2016-04-25 12:16:28 -0400719 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900720}
721
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200722static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900723{
Arnd Bergmann49413112015-11-20 17:38:28 +0100724 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900725
726 return dif_storep + sector;
727}
728
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900729static void sdebug_max_tgts_luns(void)
730{
731 struct sdebug_host_info *sdbg_host;
732 struct Scsi_Host *hpnt;
733
734 spin_lock(&sdebug_host_list_lock);
735 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
736 hpnt = sdbg_host->shost;
737 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400738 (sdebug_num_tgts > hpnt->this_id))
739 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900740 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400741 hpnt->max_id = sdebug_num_tgts;
742 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300743 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900744 }
745 spin_unlock(&sdebug_host_list_lock);
746}
747
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500748enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
749
750/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400751static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
752 enum sdeb_cmd_data c_d,
753 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500754{
755 unsigned char *sbuff;
756 u8 sks[4];
757 int sl, asc;
758
759 sbuff = scp->sense_buffer;
760 if (!sbuff) {
761 sdev_printk(KERN_ERR, scp->device,
762 "%s: sense_buffer is NULL\n", __func__);
763 return;
764 }
765 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
766 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400767 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500768 memset(sks, 0, sizeof(sks));
769 sks[0] = 0x80;
770 if (c_d)
771 sks[0] |= 0x40;
772 if (in_bit >= 0) {
773 sks[0] |= 0x8;
774 sks[0] |= 0x7 & in_bit;
775 }
776 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400777 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500778 sl = sbuff[7] + 8;
779 sbuff[7] = sl;
780 sbuff[sl] = 0x2;
781 sbuff[sl + 1] = 0x6;
782 memcpy(sbuff + sl + 4, sks, 3);
783 } else
784 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400785 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500786 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
787 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
788 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
789}
790
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400791static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900792{
793 unsigned char *sbuff;
794
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400795 sbuff = scp->sense_buffer;
796 if (!sbuff) {
797 sdev_printk(KERN_ERR, scp->device,
798 "%s: sense_buffer is NULL\n", __func__);
799 return;
800 }
801 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900802
Douglas Gilbert773642d2016-04-25 12:16:28 -0400803 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900804
Douglas Gilbert773642d2016-04-25 12:16:28 -0400805 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400806 sdev_printk(KERN_INFO, scp->device,
807 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
808 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900809}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Douglas Gilbertfd321192016-04-25 12:16:33 -0400811static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500812{
813 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
814}
815
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
817{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400818 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400819 if (0x1261 == cmd)
820 sdev_printk(KERN_INFO, dev,
821 "%s: BLKFLSBUF [0x1261]\n", __func__);
822 else if (0x5331 == cmd)
823 sdev_printk(KERN_INFO, dev,
824 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
825 __func__);
826 else
827 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
828 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
830 return -EINVAL;
831 /* return -ENOTTY; // correct return but upsets fdisk */
832}
833
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500834static void config_cdb_len(struct scsi_device *sdev)
835{
836 switch (sdebug_cdb_len) {
837 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
838 sdev->use_10_for_rw = false;
839 sdev->use_16_for_rw = false;
840 sdev->use_10_for_ms = false;
841 break;
842 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
843 sdev->use_10_for_rw = true;
844 sdev->use_16_for_rw = false;
845 sdev->use_10_for_ms = false;
846 break;
847 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
848 sdev->use_10_for_rw = true;
849 sdev->use_16_for_rw = false;
850 sdev->use_10_for_ms = true;
851 break;
852 case 16:
853 sdev->use_10_for_rw = false;
854 sdev->use_16_for_rw = true;
855 sdev->use_10_for_ms = true;
856 break;
857 case 32: /* No knobs to suggest this so same as 16 for now */
858 sdev->use_10_for_rw = false;
859 sdev->use_16_for_rw = true;
860 sdev->use_10_for_ms = true;
861 break;
862 default:
863 pr_warn("unexpected cdb_len=%d, force to 10\n",
864 sdebug_cdb_len);
865 sdev->use_10_for_rw = true;
866 sdev->use_16_for_rw = false;
867 sdev->use_10_for_ms = false;
868 sdebug_cdb_len = 10;
869 break;
870 }
871}
872
873static void all_config_cdb_len(void)
874{
875 struct sdebug_host_info *sdbg_host;
876 struct Scsi_Host *shost;
877 struct scsi_device *sdev;
878
879 spin_lock(&sdebug_host_list_lock);
880 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
881 shost = sdbg_host->shost;
882 shost_for_each_device(sdev, shost) {
883 config_cdb_len(sdev);
884 }
885 }
886 spin_unlock(&sdebug_host_list_lock);
887}
888
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500889static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
890{
891 struct sdebug_host_info *sdhp;
892 struct sdebug_dev_info *dp;
893
894 spin_lock(&sdebug_host_list_lock);
895 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
896 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
897 if ((devip->sdbg_host == dp->sdbg_host) &&
898 (devip->target == dp->target))
899 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
900 }
901 }
902 spin_unlock(&sdebug_host_list_lock);
903}
904
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400905static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400907 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400908
909 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
910 if (k != SDEBUG_NUM_UAS) {
911 const char *cp = NULL;
912
913 switch (k) {
914 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400915 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
916 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400917 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400918 cp = "power on reset";
919 break;
920 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400921 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
922 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400923 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400924 cp = "bus reset";
925 break;
926 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400927 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
928 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400929 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400930 cp = "mode parameters changed";
931 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500932 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400933 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
934 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400935 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500936 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500937 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500938 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400939 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400940 TARGET_CHANGED_ASC,
941 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400942 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500943 cp = "microcode has been changed";
944 break;
945 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400946 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500947 TARGET_CHANGED_ASC,
948 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400949 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500950 cp = "microcode has been changed without reset";
951 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500952 case SDEBUG_UA_LUNS_CHANGED:
953 /*
954 * SPC-3 behavior is to report a UNIT ATTENTION with
955 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
956 * on the target, until a REPORT LUNS command is
957 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400958 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500959 * values as struct scsi_device->scsi_level.
960 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400961 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500962 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400963 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500964 TARGET_CHANGED_ASC,
965 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400966 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500967 cp = "reported luns data has changed";
968 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400969 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400970 pr_warn("unexpected unit attention code=%d\n", k);
971 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400972 cp = "unknown";
973 break;
974 }
975 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400976 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400977 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400978 "%s reports: Unit attention: %s\n",
979 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 return check_condition_result;
981 }
982 return 0;
983}
984
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400985/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900986static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 int arr_len)
988{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900989 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900990 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900992 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900994 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400995 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900996
997 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
998 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700999 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 return 0;
1002}
1003
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001004/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1005 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1006 * calls, not required to write in ascending offset order. Assumes resid
1007 * set to scsi_bufflen() prior to any calls.
1008 */
1009static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1010 int arr_len, unsigned int off_dst)
1011{
1012 int act_len, n;
1013 struct scsi_data_buffer *sdb = scsi_in(scp);
1014 off_t skip = off_dst;
1015
1016 if (sdb->length <= off_dst)
1017 return 0;
1018 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1019 return DID_ERROR << 16;
1020
1021 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1022 arr, arr_len, skip);
1023 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1024 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1025 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1026 sdb->resid = min(sdb->resid, n);
1027 return 0;
1028}
1029
1030/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1031 * 'arr' or -1 if error.
1032 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001033static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1034 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001036 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001038 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001040
1041 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042}
1043
1044
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001045static char sdebug_inq_vendor_id[9] = "Linux ";
1046static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001047static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001048/* Use some locally assigned NAAs for SAS addresses. */
1049static const u64 naa3_comp_a = 0x3222222000000000ULL;
1050static const u64 naa3_comp_b = 0x3333333000000000ULL;
1051static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001053/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001054static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1055 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001056 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001057 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001059 int num, port_a;
1060 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001062 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 /* T10 vendor identifier field format (faked) */
1064 arr[0] = 0x2; /* ASCII */
1065 arr[1] = 0x1;
1066 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001067 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1068 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1070 num = 8 + 16 + dev_id_str_len;
1071 arr[3] = num;
1072 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001073 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001074 if (sdebug_uuid_ctl) {
1075 /* Locally assigned UUID */
1076 arr[num++] = 0x1; /* binary (not necessarily sas) */
1077 arr[num++] = 0xa; /* PIV=0, lu, naa */
1078 arr[num++] = 0x0;
1079 arr[num++] = 0x12;
1080 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1081 arr[num++] = 0x0;
1082 memcpy(arr + num, lu_name, 16);
1083 num += 16;
1084 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001085 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001086 arr[num++] = 0x1; /* binary (not necessarily sas) */
1087 arr[num++] = 0x3; /* PIV=0, lu, naa */
1088 arr[num++] = 0x0;
1089 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001090 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001091 num += 8;
1092 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001093 /* Target relative port number */
1094 arr[num++] = 0x61; /* proto=sas, binary */
1095 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1096 arr[num++] = 0x0; /* reserved */
1097 arr[num++] = 0x4; /* length */
1098 arr[num++] = 0x0; /* reserved */
1099 arr[num++] = 0x0; /* reserved */
1100 arr[num++] = 0x0;
1101 arr[num++] = 0x1; /* relative port A */
1102 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001103 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001104 arr[num++] = 0x61; /* proto=sas, binary */
1105 arr[num++] = 0x93; /* piv=1, target port, naa */
1106 arr[num++] = 0x0;
1107 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001108 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001109 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001110 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001111 arr[num++] = 0x61; /* proto=sas, binary */
1112 arr[num++] = 0x95; /* piv=1, target port group id */
1113 arr[num++] = 0x0;
1114 arr[num++] = 0x4;
1115 arr[num++] = 0;
1116 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001117 put_unaligned_be16(port_group_id, arr + num);
1118 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001119 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001120 arr[num++] = 0x61; /* proto=sas, binary */
1121 arr[num++] = 0xa3; /* piv=1, target device, naa */
1122 arr[num++] = 0x0;
1123 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001124 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001125 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001126 /* SCSI name string: Target device identifier */
1127 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1128 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1129 arr[num++] = 0x0;
1130 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001131 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001132 num += 12;
1133 snprintf(b, sizeof(b), "%08X", target_dev_id);
1134 memcpy(arr + num, b, 8);
1135 num += 8;
1136 memset(arr + num, 0, 4);
1137 num += 4;
1138 return num;
1139}
1140
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001141static unsigned char vpd84_data[] = {
1142/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1143 0x22,0x22,0x22,0x0,0xbb,0x1,
1144 0x22,0x22,0x22,0x0,0xbb,0x2,
1145};
1146
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001147/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001148static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001149{
1150 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1151 return sizeof(vpd84_data);
1152}
1153
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001154/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001155static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001156{
1157 int num = 0;
1158 const char * na1 = "https://www.kernel.org/config";
1159 const char * na2 = "http://www.kernel.org/log";
1160 int plen, olen;
1161
1162 arr[num++] = 0x1; /* lu, storage config */
1163 arr[num++] = 0x0; /* reserved */
1164 arr[num++] = 0x0;
1165 olen = strlen(na1);
1166 plen = olen + 1;
1167 if (plen % 4)
1168 plen = ((plen / 4) + 1) * 4;
1169 arr[num++] = plen; /* length, null termianted, padded */
1170 memcpy(arr + num, na1, olen);
1171 memset(arr + num + olen, 0, plen - olen);
1172 num += plen;
1173
1174 arr[num++] = 0x4; /* lu, logging */
1175 arr[num++] = 0x0; /* reserved */
1176 arr[num++] = 0x0;
1177 olen = strlen(na2);
1178 plen = olen + 1;
1179 if (plen % 4)
1180 plen = ((plen / 4) + 1) * 4;
1181 arr[num++] = plen; /* length, null terminated, padded */
1182 memcpy(arr + num, na2, olen);
1183 memset(arr + num + olen, 0, plen - olen);
1184 num += plen;
1185
1186 return num;
1187}
1188
1189/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001190static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001191{
1192 int num = 0;
1193 int port_a, port_b;
1194
1195 port_a = target_dev_id + 1;
1196 port_b = port_a + 1;
1197 arr[num++] = 0x0; /* reserved */
1198 arr[num++] = 0x0; /* reserved */
1199 arr[num++] = 0x0;
1200 arr[num++] = 0x1; /* relative port 1 (primary) */
1201 memset(arr + num, 0, 6);
1202 num += 6;
1203 arr[num++] = 0x0;
1204 arr[num++] = 12; /* length tp descriptor */
1205 /* naa-5 target port identifier (A) */
1206 arr[num++] = 0x61; /* proto=sas, binary */
1207 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1208 arr[num++] = 0x0; /* reserved */
1209 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001210 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001211 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001212 arr[num++] = 0x0; /* reserved */
1213 arr[num++] = 0x0; /* reserved */
1214 arr[num++] = 0x0;
1215 arr[num++] = 0x2; /* relative port 2 (secondary) */
1216 memset(arr + num, 0, 6);
1217 num += 6;
1218 arr[num++] = 0x0;
1219 arr[num++] = 12; /* length tp descriptor */
1220 /* naa-5 target port identifier (B) */
1221 arr[num++] = 0x61; /* proto=sas, binary */
1222 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1223 arr[num++] = 0x0; /* reserved */
1224 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001225 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001226 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001227
1228 return num;
1229}
1230
1231
1232static unsigned char vpd89_data[] = {
1233/* from 4th byte */ 0,0,0,0,
1234'l','i','n','u','x',' ',' ',' ',
1235'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1236'1','2','3','4',
12370x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12380xec,0,0,0,
12390x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12400,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12410x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12420x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12430x53,0x41,
12440x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12450x20,0x20,
12460x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12470x10,0x80,
12480,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12490x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12500x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12510,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12520x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12530x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12540,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12550,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12570,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12580x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12590,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12600xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12610,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
12620,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12640,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12690,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12730,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1274};
1275
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001276/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001277static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001278{
1279 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1280 return sizeof(vpd89_data);
1281}
1282
1283
1284static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001285 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1286 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1287 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1288 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001289};
1290
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001291/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001292static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001293{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001294 unsigned int gran;
1295
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001296 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001297
1298 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001299 if (sdebug_opt_xferlen_exp != 0 &&
1300 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1301 gran = 1 << sdebug_opt_xferlen_exp;
1302 else
1303 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001304 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001305
1306 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001307 if (sdebug_store_sectors > 0x400)
1308 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001309
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001310 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001311 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001312
Douglas Gilbert773642d2016-04-25 12:16:28 -04001313 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001314 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001315 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001316
1317 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001318 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001319 }
1320
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001321 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001322 if (sdebug_unmap_alignment) {
1323 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001324 arr[28] |= 0x80; /* UGAVALID */
1325 }
1326
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001327 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001328 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001329
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001330 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001331 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001332
1333 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001334
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001335 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336}
1337
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001338/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001339static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001340{
1341 memset(arr, 0, 0x3c);
1342 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001343 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1344 arr[2] = 0;
1345 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001346
1347 return 0x3c;
1348}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001350/* Logical block provisioning VPD page (SBC-4) */
1351static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001352{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001353 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001354 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001355 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001356 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001357 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001358 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001359 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001360 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001361 if (sdebug_lbprz && scsi_debug_lbp())
1362 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1363 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1364 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1365 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001366 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001367}
1368
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001370#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001372static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
1374 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001375 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001376 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001377 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001378 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Douglas Gilbert773642d2016-04-25 12:16:28 -04001380 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001381 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1382 if (! arr)
1383 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001384 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001385 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001386 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001387 pq_pdt = TYPE_WLUN; /* present, wlun */
1388 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1389 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001390 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001391 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 arr[0] = pq_pdt;
1393 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001394 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001395 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 return check_condition_result;
1397 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001398 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001399 char lu_id_str[6];
1400 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001402 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1403 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001404 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001405 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001406 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001407 (devip->target * 1000) + devip->lun);
1408 target_dev_id = ((host_no + 1) * 2000) +
1409 (devip->target * 1000) - 3;
1410 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001412 arr[1] = cmd[2]; /*sanity */
1413 n = 4;
1414 arr[n++] = 0x0; /* this page */
1415 arr[n++] = 0x80; /* unit serial number */
1416 arr[n++] = 0x83; /* device identification */
1417 arr[n++] = 0x84; /* software interface ident. */
1418 arr[n++] = 0x85; /* management network addresses */
1419 arr[n++] = 0x86; /* extended inquiry */
1420 arr[n++] = 0x87; /* mode page policy */
1421 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001422 if (is_disk) { /* SBC only */
1423 arr[n++] = 0x89; /* ATA information */
1424 arr[n++] = 0xb0; /* Block limits */
1425 arr[n++] = 0xb1; /* Block characteristics */
1426 arr[n++] = 0xb2; /* Logical Block Prov */
1427 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001428 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001430 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001432 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001434 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001435 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1436 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001437 lu_id_str, len,
1438 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001439 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1440 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001441 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001442 } else if (0x85 == cmd[2]) { /* Management network addresses */
1443 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001444 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001445 } else if (0x86 == cmd[2]) { /* extended inquiry */
1446 arr[1] = cmd[2]; /*sanity */
1447 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001448 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001449 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001450 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001451 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1452 else
1453 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001454 arr[5] = 0x7; /* head of q, ordered + simple q's */
1455 } else if (0x87 == cmd[2]) { /* mode page policy */
1456 arr[1] = cmd[2]; /*sanity */
1457 arr[3] = 0x8; /* number of following entries */
1458 arr[4] = 0x2; /* disconnect-reconnect mp */
1459 arr[6] = 0x80; /* mlus, shared */
1460 arr[8] = 0x18; /* protocol specific lu */
1461 arr[10] = 0x82; /* mlus, per initiator port */
1462 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1463 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001464 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1465 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001466 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001467 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001468 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001469 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001470 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001471 arr[3] = inquiry_vpd_b0(&arr[4]);
1472 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001473 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001474 arr[3] = inquiry_vpd_b1(&arr[4]);
1475 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001476 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001477 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001479 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001480 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 return check_condition_result;
1482 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001483 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001484 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001485 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001486 kfree(arr);
1487 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 }
1489 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001490 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1491 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 arr[3] = 2; /* response_data_format==2 */
1493 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001494 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001495 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001496 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001497 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001499 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001500 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1501 memcpy(&arr[16], sdebug_inq_product_id, 16);
1502 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001503 /* Use Vendor Specific area to place driver date in ASCII hex */
1504 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001506 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1507 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001508 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001509 if (is_disk) { /* SBC-4 no version claimed */
1510 put_unaligned_be16(0x600, arr + n);
1511 n += 2;
1512 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1513 put_unaligned_be16(0x525, arr + n);
1514 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001516 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001517 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001519 kfree(arr);
1520 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521}
1522
Douglas Gilbertfd321192016-04-25 12:16:33 -04001523static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1524 0, 0, 0x0, 0x0};
1525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526static int resp_requests(struct scsi_cmnd * scp,
1527 struct sdebug_dev_info * devip)
1528{
1529 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001530 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001531 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001532 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 int len = 18;
1534
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001535 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001536 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001537 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001538 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001539 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001540 arr[0] = 0x72;
1541 arr[1] = 0x0; /* NO_SENSE in sense_key */
1542 arr[2] = THRESHOLD_EXCEEDED;
1543 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001544 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001545 } else {
1546 arr[0] = 0x70;
1547 arr[2] = 0x0; /* NO_SENSE in sense_key */
1548 arr[7] = 0xa; /* 18 byte sense buffer */
1549 arr[12] = THRESHOLD_EXCEEDED;
1550 arr[13] = 0xff; /* TEST set and MRIE==6 */
1551 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001552 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001553 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001554 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001555 ; /* have sense and formats match */
1556 else if (arr[0] <= 0x70) {
1557 if (dsense) {
1558 memset(arr, 0, 8);
1559 arr[0] = 0x72;
1560 len = 8;
1561 } else {
1562 memset(arr, 0, 18);
1563 arr[0] = 0x70;
1564 arr[7] = 0xa;
1565 }
1566 } else if (dsense) {
1567 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001568 arr[0] = 0x72;
1569 arr[1] = sbuff[2]; /* sense key */
1570 arr[2] = sbuff[12]; /* asc */
1571 arr[3] = sbuff[13]; /* ascq */
1572 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001573 } else {
1574 memset(arr, 0, 18);
1575 arr[0] = 0x70;
1576 arr[2] = sbuff[1];
1577 arr[7] = 0xa;
1578 arr[12] = sbuff[1];
1579 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001580 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001581
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001582 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001583 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 return fill_from_dev_buffer(scp, arr, len);
1585}
1586
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001587static int resp_start_stop(struct scsi_cmnd * scp,
1588 struct sdebug_dev_info * devip)
1589{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001590 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001591 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001592
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001593 power_cond = (cmd[4] & 0xf0) >> 4;
1594 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001595 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001596 return check_condition_result;
1597 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001598 stop = !(cmd[4] & 1);
1599 atomic_xchg(&devip->stopped, stop);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001600 return 0;
1601}
1602
FUJITA Tomonori28898872008-03-30 00:59:55 +09001603static sector_t get_sdebug_capacity(void)
1604{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001605 static const unsigned int gibibyte = 1073741824;
1606
1607 if (sdebug_virtual_gb > 0)
1608 return (sector_t)sdebug_virtual_gb *
1609 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001610 else
1611 return sdebug_store_sectors;
1612}
1613
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614#define SDEBUG_READCAP_ARR_SZ 8
1615static int resp_readcap(struct scsi_cmnd * scp,
1616 struct sdebug_dev_info * devip)
1617{
1618 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001619 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001621 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001622 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001624 if (sdebug_capacity < 0xffffffff) {
1625 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001626 put_unaligned_be32(capac, arr + 0);
1627 } else
1628 put_unaligned_be32(0xffffffff, arr + 0);
1629 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1631}
1632
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001633#define SDEBUG_READCAP16_ARR_SZ 32
1634static int resp_readcap16(struct scsi_cmnd * scp,
1635 struct sdebug_dev_info * devip)
1636{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001637 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001638 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001639 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001640
Douglas Gilbert773642d2016-04-25 12:16:28 -04001641 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001642 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001643 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001644 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001645 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1646 put_unaligned_be32(sdebug_sector_size, arr + 8);
1647 arr[13] = sdebug_physblk_exp & 0xf;
1648 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001649
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001650 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001651 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001652 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1653 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1654 * in the wider field maps to 0 in this field.
1655 */
1656 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1657 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001658 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001659
Douglas Gilbert773642d2016-04-25 12:16:28 -04001660 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001661
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001662 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001663 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001664 arr[12] |= 1; /* PROT_EN */
1665 }
1666
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001667 return fill_from_dev_buffer(scp, arr,
1668 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1669}
1670
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001671#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1672
1673static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1674 struct sdebug_dev_info * devip)
1675{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001676 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001677 unsigned char * arr;
1678 int host_no = devip->sdbg_host->shost->host_no;
1679 int n, ret, alen, rlen;
1680 int port_group_a, port_group_b, port_a, port_b;
1681
Douglas Gilbert773642d2016-04-25 12:16:28 -04001682 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001683 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1684 if (! arr)
1685 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001686 /*
1687 * EVPD page 0x88 states we have two ports, one
1688 * real and a fake port with no device connected.
1689 * So we create two port groups with one port each
1690 * and set the group with port B to unavailable.
1691 */
1692 port_a = 0x1; /* relative port A */
1693 port_b = 0x2; /* relative port B */
1694 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001695 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001696 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001697 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001698
1699 /*
1700 * The asymmetric access state is cycled according to the host_id.
1701 */
1702 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001703 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001704 arr[n++] = host_no % 3; /* Asymm access state */
1705 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001706 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001707 arr[n++] = 0x0; /* Active/Optimized path */
1708 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001709 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001710 put_unaligned_be16(port_group_a, arr + n);
1711 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001712 arr[n++] = 0; /* Reserved */
1713 arr[n++] = 0; /* Status code */
1714 arr[n++] = 0; /* Vendor unique */
1715 arr[n++] = 0x1; /* One port per group */
1716 arr[n++] = 0; /* Reserved */
1717 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001718 put_unaligned_be16(port_a, arr + n);
1719 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001720 arr[n++] = 3; /* Port unavailable */
1721 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001722 put_unaligned_be16(port_group_b, arr + n);
1723 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001724 arr[n++] = 0; /* Reserved */
1725 arr[n++] = 0; /* Status code */
1726 arr[n++] = 0; /* Vendor unique */
1727 arr[n++] = 0x1; /* One port per group */
1728 arr[n++] = 0; /* Reserved */
1729 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001730 put_unaligned_be16(port_b, arr + n);
1731 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001732
1733 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001734 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001735
1736 /*
1737 * Return the smallest value of either
1738 * - The allocated length
1739 * - The constructed command length
1740 * - The maximum array size
1741 */
1742 rlen = min(alen,n);
1743 ret = fill_from_dev_buffer(scp, arr,
1744 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1745 kfree(arr);
1746 return ret;
1747}
1748
Douglas Gilbertfd321192016-04-25 12:16:33 -04001749static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1750 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001751{
1752 bool rctd;
1753 u8 reporting_opts, req_opcode, sdeb_i, supp;
1754 u16 req_sa, u;
1755 u32 alloc_len, a_len;
1756 int k, offset, len, errsts, count, bump, na;
1757 const struct opcode_info_t *oip;
1758 const struct opcode_info_t *r_oip;
1759 u8 *arr;
1760 u8 *cmd = scp->cmnd;
1761
1762 rctd = !!(cmd[2] & 0x80);
1763 reporting_opts = cmd[2] & 0x7;
1764 req_opcode = cmd[3];
1765 req_sa = get_unaligned_be16(cmd + 4);
1766 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001767 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001768 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1769 return check_condition_result;
1770 }
1771 if (alloc_len > 8192)
1772 a_len = 8192;
1773 else
1774 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001775 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001776 if (NULL == arr) {
1777 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1778 INSUFF_RES_ASCQ);
1779 return check_condition_result;
1780 }
1781 switch (reporting_opts) {
1782 case 0: /* all commands */
1783 /* count number of commands */
1784 for (count = 0, oip = opcode_info_arr;
1785 oip->num_attached != 0xff; ++oip) {
1786 if (F_INV_OP & oip->flags)
1787 continue;
1788 count += (oip->num_attached + 1);
1789 }
1790 bump = rctd ? 20 : 8;
1791 put_unaligned_be32(count * bump, arr);
1792 for (offset = 4, oip = opcode_info_arr;
1793 oip->num_attached != 0xff && offset < a_len; ++oip) {
1794 if (F_INV_OP & oip->flags)
1795 continue;
1796 na = oip->num_attached;
1797 arr[offset] = oip->opcode;
1798 put_unaligned_be16(oip->sa, arr + offset + 2);
1799 if (rctd)
1800 arr[offset + 5] |= 0x2;
1801 if (FF_SA & oip->flags)
1802 arr[offset + 5] |= 0x1;
1803 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1804 if (rctd)
1805 put_unaligned_be16(0xa, arr + offset + 8);
1806 r_oip = oip;
1807 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1808 if (F_INV_OP & oip->flags)
1809 continue;
1810 offset += bump;
1811 arr[offset] = oip->opcode;
1812 put_unaligned_be16(oip->sa, arr + offset + 2);
1813 if (rctd)
1814 arr[offset + 5] |= 0x2;
1815 if (FF_SA & oip->flags)
1816 arr[offset + 5] |= 0x1;
1817 put_unaligned_be16(oip->len_mask[0],
1818 arr + offset + 6);
1819 if (rctd)
1820 put_unaligned_be16(0xa,
1821 arr + offset + 8);
1822 }
1823 oip = r_oip;
1824 offset += bump;
1825 }
1826 break;
1827 case 1: /* one command: opcode only */
1828 case 2: /* one command: opcode plus service action */
1829 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1830 sdeb_i = opcode_ind_arr[req_opcode];
1831 oip = &opcode_info_arr[sdeb_i];
1832 if (F_INV_OP & oip->flags) {
1833 supp = 1;
1834 offset = 4;
1835 } else {
1836 if (1 == reporting_opts) {
1837 if (FF_SA & oip->flags) {
1838 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1839 2, 2);
1840 kfree(arr);
1841 return check_condition_result;
1842 }
1843 req_sa = 0;
1844 } else if (2 == reporting_opts &&
1845 0 == (FF_SA & oip->flags)) {
1846 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1847 kfree(arr); /* point at requested sa */
1848 return check_condition_result;
1849 }
1850 if (0 == (FF_SA & oip->flags) &&
1851 req_opcode == oip->opcode)
1852 supp = 3;
1853 else if (0 == (FF_SA & oip->flags)) {
1854 na = oip->num_attached;
1855 for (k = 0, oip = oip->arrp; k < na;
1856 ++k, ++oip) {
1857 if (req_opcode == oip->opcode)
1858 break;
1859 }
1860 supp = (k >= na) ? 1 : 3;
1861 } else if (req_sa != oip->sa) {
1862 na = oip->num_attached;
1863 for (k = 0, oip = oip->arrp; k < na;
1864 ++k, ++oip) {
1865 if (req_sa == oip->sa)
1866 break;
1867 }
1868 supp = (k >= na) ? 1 : 3;
1869 } else
1870 supp = 3;
1871 if (3 == supp) {
1872 u = oip->len_mask[0];
1873 put_unaligned_be16(u, arr + 2);
1874 arr[4] = oip->opcode;
1875 for (k = 1; k < u; ++k)
1876 arr[4 + k] = (k < 16) ?
1877 oip->len_mask[k] : 0xff;
1878 offset = 4 + u;
1879 } else
1880 offset = 4;
1881 }
1882 arr[1] = (rctd ? 0x80 : 0) | supp;
1883 if (rctd) {
1884 put_unaligned_be16(0xa, arr + offset);
1885 offset += 12;
1886 }
1887 break;
1888 default:
1889 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1890 kfree(arr);
1891 return check_condition_result;
1892 }
1893 offset = (offset < a_len) ? offset : a_len;
1894 len = (offset < alloc_len) ? offset : alloc_len;
1895 errsts = fill_from_dev_buffer(scp, arr, len);
1896 kfree(arr);
1897 return errsts;
1898}
1899
Douglas Gilbertfd321192016-04-25 12:16:33 -04001900static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1901 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001902{
1903 bool repd;
1904 u32 alloc_len, len;
1905 u8 arr[16];
1906 u8 *cmd = scp->cmnd;
1907
1908 memset(arr, 0, sizeof(arr));
1909 repd = !!(cmd[2] & 0x80);
1910 alloc_len = get_unaligned_be32(cmd + 6);
1911 if (alloc_len < 4) {
1912 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1913 return check_condition_result;
1914 }
1915 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1916 arr[1] = 0x1; /* ITNRS */
1917 if (repd) {
1918 arr[3] = 0xc;
1919 len = 16;
1920 } else
1921 len = 4;
1922
1923 len = (len < alloc_len) ? len : alloc_len;
1924 return fill_from_dev_buffer(scp, arr, len);
1925}
1926
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927/* <<Following mode page info copied from ST318451LW>> */
1928
1929static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1930{ /* Read-Write Error Recovery page for mode_sense */
1931 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1932 5, 0, 0xff, 0xff};
1933
1934 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1935 if (1 == pcontrol)
1936 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1937 return sizeof(err_recov_pg);
1938}
1939
1940static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1941{ /* Disconnect-Reconnect page for mode_sense */
1942 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1943 0, 0, 0, 0, 0, 0, 0, 0};
1944
1945 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1946 if (1 == pcontrol)
1947 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1948 return sizeof(disconnect_pg);
1949}
1950
1951static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1952{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001953 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1954 0, 0, 0, 0, 0, 0, 0, 0,
1955 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Martin K. Petersen597136a2008-06-05 00:12:59 -04001957 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001958 put_unaligned_be16(sdebug_sectors_per, p + 10);
1959 put_unaligned_be16(sdebug_sector_size, p + 12);
1960 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001961 p[20] |= 0x20; /* should agree with INQUIRY */
1962 if (1 == pcontrol)
1963 memset(p + 2, 0, sizeof(format_pg) - 2);
1964 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965}
1966
Douglas Gilbertfd321192016-04-25 12:16:33 -04001967static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1968 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1969 0, 0, 0, 0};
1970
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1972{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001973 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1974 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1975 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1977
Douglas Gilbert773642d2016-04-25 12:16:28 -04001978 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001979 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 memcpy(p, caching_pg, sizeof(caching_pg));
1981 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001982 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1983 else if (2 == pcontrol)
1984 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 return sizeof(caching_pg);
1986}
1987
Douglas Gilbertfd321192016-04-25 12:16:33 -04001988static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1989 0, 0, 0x2, 0x4b};
1990
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1992{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001993 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05001994 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001995 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 0, 0, 0x2, 0x4b};
1997
Douglas Gilbert773642d2016-04-25 12:16:28 -04001998 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002000 else
2001 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002002
Douglas Gilbert773642d2016-04-25 12:16:28 -04002003 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002004 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2005
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2007 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002008 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2009 else if (2 == pcontrol)
2010 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 return sizeof(ctrl_m_pg);
2012}
2013
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
2016{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002017 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2018 0, 0, 0x0, 0x0};
2019 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2020 0, 0, 0x0, 0x0};
2021
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2023 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002024 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2025 else if (2 == pcontrol)
2026 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 return sizeof(iec_m_pg);
2028}
2029
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002030static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
2031{ /* SAS SSP mode page - short format for mode_sense */
2032 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2033 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2034
2035 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2036 if (1 == pcontrol)
2037 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2038 return sizeof(sas_sf_m_pg);
2039}
2040
2041
2042static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
2043 int target_dev_id)
2044{ /* SAS phy control and discover mode page for mode_sense */
2045 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2046 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002047 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2048 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002049 0x2, 0, 0, 0, 0, 0, 0, 0,
2050 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2051 0, 0, 0, 0, 0, 0, 0, 0,
2052 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002053 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2054 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002055 0x3, 0, 0, 0, 0, 0, 0, 0,
2056 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2057 0, 0, 0, 0, 0, 0, 0, 0,
2058 };
2059 int port_a, port_b;
2060
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002061 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2062 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2063 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2064 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002065 port_a = target_dev_id + 1;
2066 port_b = port_a + 1;
2067 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002068 put_unaligned_be32(port_a, p + 20);
2069 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002070 if (1 == pcontrol)
2071 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2072 return sizeof(sas_pcd_m_pg);
2073}
2074
2075static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
2076{ /* SAS SSP shared protocol specific port mode subpage */
2077 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2078 0, 0, 0, 0, 0, 0, 0, 0,
2079 };
2080
2081 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2082 if (1 == pcontrol)
2083 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2084 return sizeof(sas_sha_m_pg);
2085}
2086
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087#define SDEBUG_MAX_MSENSE_SZ 256
2088
Douglas Gilbertfd321192016-04-25 12:16:33 -04002089static int resp_mode_sense(struct scsi_cmnd *scp,
2090 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091{
Douglas Gilbert23183912006-09-16 20:30:47 -04002092 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002094 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002095 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 unsigned char * ap;
2097 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002098 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002099 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002101 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 pcontrol = (cmd[2] & 0xc0) >> 6;
2103 pcode = cmd[2] & 0x3f;
2104 subpcode = cmd[3];
2105 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002106 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2107 is_disk = (sdebug_ptype == TYPE_DISK);
2108 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002109 bd_len = llbaa ? 16 : 8;
2110 else
2111 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002112 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2114 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002115 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 return check_condition_result;
2117 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002118 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2119 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002120 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002121 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002122 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002123 else
2124 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 if (msense_6) {
2126 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002127 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 offset = 4;
2129 } else {
2130 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002131 if (16 == bd_len)
2132 arr[4] = 0x1; /* set LONGLBA bit */
2133 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 offset = 8;
2135 }
2136 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002137 if ((bd_len > 0) && (!sdebug_capacity))
2138 sdebug_capacity = get_sdebug_capacity();
2139
Douglas Gilbert23183912006-09-16 20:30:47 -04002140 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002141 if (sdebug_capacity > 0xfffffffe)
2142 put_unaligned_be32(0xffffffff, ap + 0);
2143 else
2144 put_unaligned_be32(sdebug_capacity, ap + 0);
2145 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002146 offset += bd_len;
2147 ap = arr + offset;
2148 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002149 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2150 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002151 offset += bd_len;
2152 ap = arr + offset;
2153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002155 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2156 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002157 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 return check_condition_result;
2159 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002160 bad_pcode = false;
2161
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 switch (pcode) {
2163 case 0x1: /* Read-Write error recovery page, direct access */
2164 len = resp_err_recov_pg(ap, pcontrol, target);
2165 offset += len;
2166 break;
2167 case 0x2: /* Disconnect-Reconnect page, all devices */
2168 len = resp_disconnect_pg(ap, pcontrol, target);
2169 offset += len;
2170 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002171 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002172 if (is_disk) {
2173 len = resp_format_pg(ap, pcontrol, target);
2174 offset += len;
2175 } else
2176 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002177 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002179 if (is_disk) {
2180 len = resp_caching_pg(ap, pcontrol, target);
2181 offset += len;
2182 } else
2183 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 break;
2185 case 0xa: /* Control Mode page, all devices */
2186 len = resp_ctrl_m_pg(ap, pcontrol, target);
2187 offset += len;
2188 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002189 case 0x19: /* if spc==1 then sas phy, control+discover */
2190 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002191 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002192 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002193 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002194 len = 0;
2195 if ((0x0 == subpcode) || (0xff == subpcode))
2196 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2197 if ((0x1 == subpcode) || (0xff == subpcode))
2198 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2199 target_dev_id);
2200 if ((0x2 == subpcode) || (0xff == subpcode))
2201 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2202 offset += len;
2203 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 case 0x1c: /* Informational Exceptions Mode page, all devices */
2205 len = resp_iec_m_pg(ap, pcontrol, target);
2206 offset += len;
2207 break;
2208 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002209 if ((0 == subpcode) || (0xff == subpcode)) {
2210 len = resp_err_recov_pg(ap, pcontrol, target);
2211 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002212 if (is_disk) {
2213 len += resp_format_pg(ap + len, pcontrol,
2214 target);
2215 len += resp_caching_pg(ap + len, pcontrol,
2216 target);
2217 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002218 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2219 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2220 if (0xff == subpcode) {
2221 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2222 target, target_dev_id);
2223 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2224 }
2225 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002226 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002227 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002228 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002229 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 break;
2232 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002233 bad_pcode = true;
2234 break;
2235 }
2236 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002237 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 return check_condition_result;
2239 }
2240 if (msense_6)
2241 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002242 else
2243 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2245}
2246
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002247#define SDEBUG_MAX_MSELECT_SZ 512
2248
Douglas Gilbertfd321192016-04-25 12:16:33 -04002249static int resp_mode_select(struct scsi_cmnd *scp,
2250 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002251{
2252 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002253 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002254 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002255 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002256 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002257
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002258 memset(arr, 0, sizeof(arr));
2259 pf = cmd[1] & 0x10;
2260 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002261 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002263 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002264 return check_condition_result;
2265 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002266 res = fetch_to_dev_buffer(scp, arr, param_len);
2267 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002268 return DID_ERROR << 16;
2269 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002270 sdev_printk(KERN_INFO, scp->device,
2271 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2272 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002273 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2274 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002275 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002276 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002277 return check_condition_result;
2278 }
2279 off = bd_len + (mselect6 ? 4 : 8);
2280 mpage = arr[off] & 0x3f;
2281 ps = !!(arr[off] & 0x80);
2282 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002283 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002284 return check_condition_result;
2285 }
2286 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002287 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002288 (arr[off + 1] + 2);
2289 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002290 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002291 PARAMETER_LIST_LENGTH_ERR, 0);
2292 return check_condition_result;
2293 }
2294 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002295 case 0x8: /* Caching Mode page */
2296 if (caching_pg[1] == arr[off + 1]) {
2297 memcpy(caching_pg + 2, arr + off + 2,
2298 sizeof(caching_pg) - 2);
2299 goto set_mode_changed_ua;
2300 }
2301 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002302 case 0xa: /* Control Mode page */
2303 if (ctrl_m_pg[1] == arr[off + 1]) {
2304 memcpy(ctrl_m_pg + 2, arr + off + 2,
2305 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002306 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002307 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002308 }
2309 break;
2310 case 0x1c: /* Informational Exceptions Mode page */
2311 if (iec_m_pg[1] == arr[off + 1]) {
2312 memcpy(iec_m_pg + 2, arr + off + 2,
2313 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002314 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002315 }
2316 break;
2317 default:
2318 break;
2319 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002320 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002321 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002322set_mode_changed_ua:
2323 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2324 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002325}
2326
2327static int resp_temp_l_pg(unsigned char * arr)
2328{
2329 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2330 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2331 };
2332
Douglas Gilbert9a051012017-12-23 12:48:10 -05002333 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2334 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002335}
2336
2337static int resp_ie_l_pg(unsigned char * arr)
2338{
2339 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2340 };
2341
Douglas Gilbert9a051012017-12-23 12:48:10 -05002342 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002343 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2344 arr[4] = THRESHOLD_EXCEEDED;
2345 arr[5] = 0xff;
2346 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002347 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002348}
2349
2350#define SDEBUG_MAX_LSENSE_SZ 512
2351
Douglas Gilbert9a051012017-12-23 12:48:10 -05002352static int resp_log_sense(struct scsi_cmnd *scp,
2353 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002354{
Bart Van Asscheab172412017-08-25 13:46:42 -07002355 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002356 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002357 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002358
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002359 memset(arr, 0, sizeof(arr));
2360 ppc = cmd[1] & 0x2;
2361 sp = cmd[1] & 0x1;
2362 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002363 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002364 return check_condition_result;
2365 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002366 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002367 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002368 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002369 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002370 if (0 == subpcode) {
2371 switch (pcode) {
2372 case 0x0: /* Supported log pages log page */
2373 n = 4;
2374 arr[n++] = 0x0; /* this page */
2375 arr[n++] = 0xd; /* Temperature */
2376 arr[n++] = 0x2f; /* Informational exceptions */
2377 arr[3] = n - 4;
2378 break;
2379 case 0xd: /* Temperature log page */
2380 arr[3] = resp_temp_l_pg(arr + 4);
2381 break;
2382 case 0x2f: /* Informational exceptions log page */
2383 arr[3] = resp_ie_l_pg(arr + 4);
2384 break;
2385 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002386 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002387 return check_condition_result;
2388 }
2389 } else if (0xff == subpcode) {
2390 arr[0] |= 0x40;
2391 arr[1] = subpcode;
2392 switch (pcode) {
2393 case 0x0: /* Supported log pages and subpages log page */
2394 n = 4;
2395 arr[n++] = 0x0;
2396 arr[n++] = 0x0; /* 0,0 page */
2397 arr[n++] = 0x0;
2398 arr[n++] = 0xff; /* this page */
2399 arr[n++] = 0xd;
2400 arr[n++] = 0x0; /* Temperature */
2401 arr[n++] = 0x2f;
2402 arr[n++] = 0x0; /* Informational exceptions */
2403 arr[3] = n - 4;
2404 break;
2405 case 0xd: /* Temperature subpages */
2406 n = 4;
2407 arr[n++] = 0xd;
2408 arr[n++] = 0x0; /* Temperature */
2409 arr[3] = n - 4;
2410 break;
2411 case 0x2f: /* Informational exceptions subpages */
2412 n = 4;
2413 arr[n++] = 0x2f;
2414 arr[n++] = 0x0; /* Informational exceptions */
2415 arr[3] = n - 4;
2416 break;
2417 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002418 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002419 return check_condition_result;
2420 }
2421 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002422 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002423 return check_condition_result;
2424 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002425 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002426 return fill_from_dev_buffer(scp, arr,
2427 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2428}
2429
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002430static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002431 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002433 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002434 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 return check_condition_result;
2436 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002437 /* transfer length excessive (tie in to block limits VPD page) */
2438 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002439 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002440 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002441 return check_condition_result;
2442 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002443 return 0;
2444}
2445
Akinobu Mitaa4517512013-07-08 16:01:57 -07002446/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002447static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2448 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002449{
2450 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002451 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002452 struct scsi_data_buffer *sdb;
2453 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002454
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002455 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002456 sdb = scsi_out(scmd);
2457 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002458 } else {
2459 sdb = scsi_in(scmd);
2460 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002461 }
2462
2463 if (!sdb->length)
2464 return 0;
2465 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2466 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002467
2468 block = do_div(lba, sdebug_store_sectors);
2469 if (block + num > sdebug_store_sectors)
2470 rest = block + num - sdebug_store_sectors;
2471
Dave Gordon386ecb12015-06-30 14:58:57 -07002472 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002473 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002474 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002475 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002476 return ret;
2477
2478 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002479 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002480 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002481 sg_skip + ((num - rest) * sdebug_sector_size),
2482 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002483 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002484
2485 return ret;
2486}
2487
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002488/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2489 * arr into fake_store(lba,num) and return true. If comparison fails then
2490 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002491static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002492{
2493 bool res;
2494 u64 block, rest = 0;
2495 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002496 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002497
2498 block = do_div(lba, store_blks);
2499 if (block + num > store_blks)
2500 rest = block + num - store_blks;
2501
2502 res = !memcmp(fake_storep + (block * lb_size), arr,
2503 (num - rest) * lb_size);
2504 if (!res)
2505 return res;
2506 if (rest)
2507 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2508 rest * lb_size);
2509 if (!res)
2510 return res;
2511 arr += num * lb_size;
2512 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2513 if (rest)
2514 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2515 rest * lb_size);
2516 return res;
2517}
2518
Akinobu Mita51d648a2013-09-18 21:27:28 +09002519static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002520{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002521 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002522
Douglas Gilbert773642d2016-04-25 12:16:28 -04002523 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002524 csum = (__force __be16)ip_compute_csum(buf, len);
2525 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002526 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002527
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002528 return csum;
2529}
2530
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002531static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002532 sector_t sector, u32 ei_lba)
2533{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002534 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002535
2536 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002537 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002538 (unsigned long)sector,
2539 be16_to_cpu(sdt->guard_tag),
2540 be16_to_cpu(csum));
2541 return 0x01;
2542 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002543 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002544 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002545 pr_err("REF check failed on sector %lu\n",
2546 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002547 return 0x03;
2548 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002549 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002550 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002551 pr_err("REF check failed on sector %lu\n",
2552 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002553 return 0x03;
2554 }
2555 return 0;
2556}
2557
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002558static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002559 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002560{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002561 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002562 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002563 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002564 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002565
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002566 /* Bytes of protection data to copy into sgl */
2567 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002568
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002569 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2570 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2571 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2572
2573 while (sg_miter_next(&miter) && resid > 0) {
2574 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002575 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002576 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002577
2578 if (dif_store_end < start + len)
2579 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002580
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002581 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002582
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002583 if (read)
2584 memcpy(paddr, start, len - rest);
2585 else
2586 memcpy(start, paddr, len - rest);
2587
2588 if (rest) {
2589 if (read)
2590 memcpy(paddr + len - rest, dif_storep, rest);
2591 else
2592 memcpy(dif_storep, paddr + len - rest, rest);
2593 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002594
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002595 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002596 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002597 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002598 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002599}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002600
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002601static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2602 unsigned int sectors, u32 ei_lba)
2603{
2604 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002605 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002606 sector_t sector;
2607
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002608 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002609 int ret;
2610
2611 sector = start_sec + i;
2612 sdt = dif_store(sector);
2613
Akinobu Mita51d648a2013-09-18 21:27:28 +09002614 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002615 continue;
2616
2617 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2618 if (ret) {
2619 dif_errors++;
2620 return ret;
2621 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002622 }
2623
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002624 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002625 dix_reads++;
2626
2627 return 0;
2628}
2629
Douglas Gilbertfd321192016-04-25 12:16:33 -04002630static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002631{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002632 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002633 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002634 u64 lba;
2635 u32 num;
2636 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002637 unsigned long iflags;
2638 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002639 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002640
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002641 switch (cmd[0]) {
2642 case READ_16:
2643 ei_lba = 0;
2644 lba = get_unaligned_be64(cmd + 2);
2645 num = get_unaligned_be32(cmd + 10);
2646 check_prot = true;
2647 break;
2648 case READ_10:
2649 ei_lba = 0;
2650 lba = get_unaligned_be32(cmd + 2);
2651 num = get_unaligned_be16(cmd + 7);
2652 check_prot = true;
2653 break;
2654 case READ_6:
2655 ei_lba = 0;
2656 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2657 (u32)(cmd[1] & 0x1f) << 16;
2658 num = (0 == cmd[4]) ? 256 : cmd[4];
2659 check_prot = true;
2660 break;
2661 case READ_12:
2662 ei_lba = 0;
2663 lba = get_unaligned_be32(cmd + 2);
2664 num = get_unaligned_be32(cmd + 6);
2665 check_prot = true;
2666 break;
2667 case XDWRITEREAD_10:
2668 ei_lba = 0;
2669 lba = get_unaligned_be32(cmd + 2);
2670 num = get_unaligned_be16(cmd + 7);
2671 check_prot = false;
2672 break;
2673 default: /* assume READ(32) */
2674 lba = get_unaligned_be64(cmd + 12);
2675 ei_lba = get_unaligned_be32(cmd + 20);
2676 num = get_unaligned_be32(cmd + 28);
2677 check_prot = false;
2678 break;
2679 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002680 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002681 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002682 (cmd[1] & 0xe0)) {
2683 mk_sense_invalid_opcode(scp);
2684 return check_condition_result;
2685 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002686 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2687 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002688 (cmd[1] & 0xe0) == 0)
2689 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2690 "to DIF device\n");
2691 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002692 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002693 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002694
Douglas Gilbertc4837392016-05-06 00:40:26 -04002695 if (sqcp) {
2696 if (sqcp->inj_short)
2697 num /= 2;
2698 }
2699 } else
2700 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002701
2702 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002703 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002704 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2705 return check_condition_result;
2706 }
2707 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002708 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002709 /* needs work to find which cdb byte 'num' comes from */
2710 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2711 return check_condition_result;
2712 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002713
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002714 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2715 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2716 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002717 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002718 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002719 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002720 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2721 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002722 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2723 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002724 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002725 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002726 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 return check_condition_result;
2728 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002729
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002730 read_lock_irqsave(&atomic_rw, iflags);
2731
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002732 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002733 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002734 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002735
2736 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002737 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002738 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002739 return illegal_condition_result;
2740 }
2741 }
2742
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002743 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002745 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002746 return DID_ERROR << 16;
2747
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002748 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002749
Douglas Gilbertc4837392016-05-06 00:40:26 -04002750 if (unlikely(sqcp)) {
2751 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002752 mk_sense_buffer(scp, RECOVERED_ERROR,
2753 THRESHOLD_EXCEEDED, 0);
2754 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002755 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002756 mk_sense_buffer(scp, ABORTED_COMMAND,
2757 TRANSPORT_PROBLEM, ACK_NAK_TO);
2758 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002759 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002760 /* Logical block guard check failed */
2761 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2762 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002763 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002764 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2765 return illegal_condition_result;
2766 }
2767 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002768 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769}
2770
Tomas Winkler58a86352015-07-28 16:54:23 +03002771static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002772{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002773 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002774
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002775 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002776 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002777 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002778
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002779 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002780 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002781
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002782 if (c >= 0x20 && c < 0x7e)
2783 n += scnprintf(b + n, sizeof(b) - n,
2784 " %c ", buf[i+j]);
2785 else
2786 n += scnprintf(b + n, sizeof(b) - n,
2787 "%02x ", buf[i+j]);
2788 }
2789 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002790 }
2791}
2792
2793static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002794 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002795{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002796 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002797 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002798 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002799 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002800 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002801 int dpage_offset;
2802 struct sg_mapping_iter diter;
2803 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002804
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002805 BUG_ON(scsi_sg_count(SCpnt) == 0);
2806 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2807
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002808 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2809 scsi_prot_sg_count(SCpnt),
2810 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2811 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2812 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002813
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002814 /* For each protection page */
2815 while (sg_miter_next(&piter)) {
2816 dpage_offset = 0;
2817 if (WARN_ON(!sg_miter_next(&diter))) {
2818 ret = 0x01;
2819 goto out;
2820 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002821
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002822 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002823 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002824 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002825 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002826 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002827 if (dpage_offset >= diter.length) {
2828 if (WARN_ON(!sg_miter_next(&diter))) {
2829 ret = 0x01;
2830 goto out;
2831 }
2832 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002833 }
2834
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002835 sdt = piter.addr + ppage_offset;
2836 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002837
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002838 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002839 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002840 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002841 goto out;
2842 }
2843
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002844 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002845 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002846 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002847 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002848 diter.consumed = dpage_offset;
2849 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002850 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002851 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002852
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002853 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002854 dix_writes++;
2855
2856 return 0;
2857
2858out:
2859 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002860 sg_miter_stop(&diter);
2861 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002862 return ret;
2863}
2864
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002865static unsigned long lba_to_map_index(sector_t lba)
2866{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002867 if (sdebug_unmap_alignment)
2868 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2869 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002870 return lba;
2871}
2872
2873static sector_t map_index_to_lba(unsigned long index)
2874{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002875 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002876
Douglas Gilbert773642d2016-04-25 12:16:28 -04002877 if (sdebug_unmap_alignment)
2878 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002879 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002880}
2881
Martin K. Petersen44d92692009-10-15 14:45:27 -04002882static unsigned int map_state(sector_t lba, unsigned int *num)
2883{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002884 sector_t end;
2885 unsigned int mapped;
2886 unsigned long index;
2887 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002888
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002889 index = lba_to_map_index(lba);
2890 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002891
2892 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002893 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002894 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002895 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002896
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002897 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002898 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002899 return mapped;
2900}
2901
2902static void map_region(sector_t lba, unsigned int len)
2903{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002904 sector_t end = lba + len;
2905
Martin K. Petersen44d92692009-10-15 14:45:27 -04002906 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002907 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002908
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002909 if (index < map_size)
2910 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002911
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002912 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002913 }
2914}
2915
2916static void unmap_region(sector_t lba, unsigned int len)
2917{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002918 sector_t end = lba + len;
2919
Martin K. Petersen44d92692009-10-15 14:45:27 -04002920 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002921 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002922
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002923 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002924 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002925 index < map_size) {
2926 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002927 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002928 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002929 lba * sdebug_sector_size,
2930 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002931 sdebug_sector_size *
2932 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002933 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002934 if (dif_storep) {
2935 memset(dif_storep + lba, 0xff,
2936 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002937 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002938 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002939 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002940 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002941 }
2942}
2943
Douglas Gilbertfd321192016-04-25 12:16:33 -04002944static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002946 u8 *cmd = scp->cmnd;
2947 u64 lba;
2948 u32 num;
2949 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002951 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002952 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002954 switch (cmd[0]) {
2955 case WRITE_16:
2956 ei_lba = 0;
2957 lba = get_unaligned_be64(cmd + 2);
2958 num = get_unaligned_be32(cmd + 10);
2959 check_prot = true;
2960 break;
2961 case WRITE_10:
2962 ei_lba = 0;
2963 lba = get_unaligned_be32(cmd + 2);
2964 num = get_unaligned_be16(cmd + 7);
2965 check_prot = true;
2966 break;
2967 case WRITE_6:
2968 ei_lba = 0;
2969 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2970 (u32)(cmd[1] & 0x1f) << 16;
2971 num = (0 == cmd[4]) ? 256 : cmd[4];
2972 check_prot = true;
2973 break;
2974 case WRITE_12:
2975 ei_lba = 0;
2976 lba = get_unaligned_be32(cmd + 2);
2977 num = get_unaligned_be32(cmd + 6);
2978 check_prot = true;
2979 break;
2980 case 0x53: /* XDWRITEREAD(10) */
2981 ei_lba = 0;
2982 lba = get_unaligned_be32(cmd + 2);
2983 num = get_unaligned_be16(cmd + 7);
2984 check_prot = false;
2985 break;
2986 default: /* assume WRITE(32) */
2987 lba = get_unaligned_be64(cmd + 12);
2988 ei_lba = get_unaligned_be32(cmd + 20);
2989 num = get_unaligned_be32(cmd + 28);
2990 check_prot = false;
2991 break;
2992 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002993 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002994 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002995 (cmd[1] & 0xe0)) {
2996 mk_sense_invalid_opcode(scp);
2997 return check_condition_result;
2998 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002999 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3000 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003001 (cmd[1] & 0xe0) == 0)
3002 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3003 "to DIF device\n");
3004 }
3005
3006 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003007 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003008 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3009 return check_condition_result;
3010 }
3011 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003012 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003013 /* needs work to find which cdb byte 'num' comes from */
3014 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3015 return check_condition_result;
3016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003018 write_lock_irqsave(&atomic_rw, iflags);
3019
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003020 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003021 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003022 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003023
3024 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003025 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003026 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003027 return illegal_condition_result;
3028 }
3029 }
3030
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003031 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003032 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003033 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003035 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003036 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003037 else if (unlikely(sdebug_verbose &&
3038 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003039 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003040 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003041 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003042
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003043 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003044 struct sdebug_queued_cmd *sqcp =
3045 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003046
Douglas Gilbertc4837392016-05-06 00:40:26 -04003047 if (sqcp) {
3048 if (sqcp->inj_recovered) {
3049 mk_sense_buffer(scp, RECOVERED_ERROR,
3050 THRESHOLD_EXCEEDED, 0);
3051 return check_condition_result;
3052 } else if (sqcp->inj_dif) {
3053 /* Logical block guard check failed */
3054 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3055 return illegal_condition_result;
3056 } else if (sqcp->inj_dix) {
3057 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3058 return illegal_condition_result;
3059 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003060 }
3061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 return 0;
3063}
3064
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003065/*
3066 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3067 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3068 */
3069static int resp_write_scat(struct scsi_cmnd *scp,
3070 struct sdebug_dev_info *devip)
3071{
3072 u8 *cmd = scp->cmnd;
3073 u8 *lrdp = NULL;
3074 u8 *up;
3075 u8 wrprotect;
3076 u16 lbdof, num_lrd, k;
3077 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3078 u32 lb_size = sdebug_sector_size;
3079 u32 ei_lba;
3080 u64 lba;
3081 unsigned long iflags;
3082 int ret, res;
3083 bool is_16;
3084 static const u32 lrd_size = 32; /* + parameter list header size */
3085
3086 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3087 is_16 = false;
3088 wrprotect = (cmd[10] >> 5) & 0x7;
3089 lbdof = get_unaligned_be16(cmd + 12);
3090 num_lrd = get_unaligned_be16(cmd + 16);
3091 bt_len = get_unaligned_be32(cmd + 28);
3092 } else { /* that leaves WRITE SCATTERED(16) */
3093 is_16 = true;
3094 wrprotect = (cmd[2] >> 5) & 0x7;
3095 lbdof = get_unaligned_be16(cmd + 4);
3096 num_lrd = get_unaligned_be16(cmd + 8);
3097 bt_len = get_unaligned_be32(cmd + 10);
3098 if (unlikely(have_dif_prot)) {
3099 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3100 wrprotect) {
3101 mk_sense_invalid_opcode(scp);
3102 return illegal_condition_result;
3103 }
3104 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3105 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3106 wrprotect == 0)
3107 sdev_printk(KERN_ERR, scp->device,
3108 "Unprotected WR to DIF device\n");
3109 }
3110 }
3111 if ((num_lrd == 0) || (bt_len == 0))
3112 return 0; /* T10 says these do-nothings are not errors */
3113 if (lbdof == 0) {
3114 if (sdebug_verbose)
3115 sdev_printk(KERN_INFO, scp->device,
3116 "%s: %s: LB Data Offset field bad\n",
3117 my_name, __func__);
3118 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3119 return illegal_condition_result;
3120 }
3121 lbdof_blen = lbdof * lb_size;
3122 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3123 if (sdebug_verbose)
3124 sdev_printk(KERN_INFO, scp->device,
3125 "%s: %s: LBA range descriptors don't fit\n",
3126 my_name, __func__);
3127 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3128 return illegal_condition_result;
3129 }
3130 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3131 if (lrdp == NULL)
3132 return SCSI_MLQUEUE_HOST_BUSY;
3133 if (sdebug_verbose)
3134 sdev_printk(KERN_INFO, scp->device,
3135 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3136 my_name, __func__, lbdof_blen);
3137 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3138 if (res == -1) {
3139 ret = DID_ERROR << 16;
3140 goto err_out;
3141 }
3142
3143 write_lock_irqsave(&atomic_rw, iflags);
3144 sg_off = lbdof_blen;
3145 /* Spec says Buffer xfer Length field in number of LBs in dout */
3146 cum_lb = 0;
3147 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3148 lba = get_unaligned_be64(up + 0);
3149 num = get_unaligned_be32(up + 8);
3150 if (sdebug_verbose)
3151 sdev_printk(KERN_INFO, scp->device,
3152 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3153 my_name, __func__, k, lba, num, sg_off);
3154 if (num == 0)
3155 continue;
3156 ret = check_device_access_params(scp, lba, num);
3157 if (ret)
3158 goto err_out_unlock;
3159 num_by = num * lb_size;
3160 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3161
3162 if ((cum_lb + num) > bt_len) {
3163 if (sdebug_verbose)
3164 sdev_printk(KERN_INFO, scp->device,
3165 "%s: %s: sum of blocks > data provided\n",
3166 my_name, __func__);
3167 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3168 0);
3169 ret = illegal_condition_result;
3170 goto err_out_unlock;
3171 }
3172
3173 /* DIX + T10 DIF */
3174 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3175 int prot_ret = prot_verify_write(scp, lba, num,
3176 ei_lba);
3177
3178 if (prot_ret) {
3179 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3180 prot_ret);
3181 ret = illegal_condition_result;
3182 goto err_out_unlock;
3183 }
3184 }
3185
3186 ret = do_device_access(scp, sg_off, lba, num, true);
3187 if (unlikely(scsi_debug_lbp()))
3188 map_region(lba, num);
3189 if (unlikely(-1 == ret)) {
3190 ret = DID_ERROR << 16;
3191 goto err_out_unlock;
3192 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3193 sdev_printk(KERN_INFO, scp->device,
3194 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3195 my_name, num_by, ret);
3196
3197 if (unlikely(sdebug_any_injecting_opt)) {
3198 struct sdebug_queued_cmd *sqcp =
3199 (struct sdebug_queued_cmd *)scp->host_scribble;
3200
3201 if (sqcp) {
3202 if (sqcp->inj_recovered) {
3203 mk_sense_buffer(scp, RECOVERED_ERROR,
3204 THRESHOLD_EXCEEDED, 0);
3205 ret = illegal_condition_result;
3206 goto err_out_unlock;
3207 } else if (sqcp->inj_dif) {
3208 /* Logical block guard check failed */
3209 mk_sense_buffer(scp, ABORTED_COMMAND,
3210 0x10, 1);
3211 ret = illegal_condition_result;
3212 goto err_out_unlock;
3213 } else if (sqcp->inj_dix) {
3214 mk_sense_buffer(scp, ILLEGAL_REQUEST,
3215 0x10, 1);
3216 ret = illegal_condition_result;
3217 goto err_out_unlock;
3218 }
3219 }
3220 }
3221 sg_off += num_by;
3222 cum_lb += num;
3223 }
3224 ret = 0;
3225err_out_unlock:
3226 write_unlock_irqrestore(&atomic_rw, iflags);
3227err_out:
3228 kfree(lrdp);
3229 return ret;
3230}
3231
Douglas Gilbertfd321192016-04-25 12:16:33 -04003232static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3233 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003234{
3235 unsigned long iflags;
3236 unsigned long long i;
3237 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003238 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003239
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003240 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003241 if (ret)
3242 return ret;
3243
3244 write_lock_irqsave(&atomic_rw, iflags);
3245
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003246 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003247 unmap_region(lba, num);
3248 goto out;
3249 }
3250
Douglas Gilbert773642d2016-04-25 12:16:28 -04003251 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003252 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3253 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003254 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003255 ret = 0;
3256 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003257 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3258 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003259
3260 if (-1 == ret) {
3261 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003262 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003263 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003264 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003265 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003266 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003267 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003268
3269 /* Copy first sector to remaining blocks */
3270 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003271 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3272 fake_storep + lba_off,
3273 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003274
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003275 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003276 map_region(lba, num);
3277out:
3278 write_unlock_irqrestore(&atomic_rw, iflags);
3279
3280 return 0;
3281}
3282
Douglas Gilbertfd321192016-04-25 12:16:33 -04003283static int resp_write_same_10(struct scsi_cmnd *scp,
3284 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003285{
3286 u8 *cmd = scp->cmnd;
3287 u32 lba;
3288 u16 num;
3289 u32 ei_lba = 0;
3290 bool unmap = false;
3291
3292 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003293 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003294 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3295 return check_condition_result;
3296 } else
3297 unmap = true;
3298 }
3299 lba = get_unaligned_be32(cmd + 2);
3300 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003301 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003302 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3303 return check_condition_result;
3304 }
3305 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3306}
3307
Douglas Gilbertfd321192016-04-25 12:16:33 -04003308static int resp_write_same_16(struct scsi_cmnd *scp,
3309 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003310{
3311 u8 *cmd = scp->cmnd;
3312 u64 lba;
3313 u32 num;
3314 u32 ei_lba = 0;
3315 bool unmap = false;
3316 bool ndob = false;
3317
3318 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003319 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003320 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3321 return check_condition_result;
3322 } else
3323 unmap = true;
3324 }
3325 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3326 ndob = true;
3327 lba = get_unaligned_be64(cmd + 2);
3328 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003329 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003330 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3331 return check_condition_result;
3332 }
3333 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3334}
3335
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003336/* Note the mode field is in the same position as the (lower) service action
3337 * field. For the Report supported operation codes command, SPC-4 suggests
3338 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003339static int resp_write_buffer(struct scsi_cmnd *scp,
3340 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003341{
3342 u8 *cmd = scp->cmnd;
3343 struct scsi_device *sdp = scp->device;
3344 struct sdebug_dev_info *dp;
3345 u8 mode;
3346
3347 mode = cmd[1] & 0x1f;
3348 switch (mode) {
3349 case 0x4: /* download microcode (MC) and activate (ACT) */
3350 /* set UAs on this device only */
3351 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3352 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3353 break;
3354 case 0x5: /* download MC, save and ACT */
3355 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3356 break;
3357 case 0x6: /* download MC with offsets and ACT */
3358 /* set UAs on most devices (LUs) in this target */
3359 list_for_each_entry(dp,
3360 &devip->sdbg_host->dev_info_list,
3361 dev_list)
3362 if (dp->target == sdp->id) {
3363 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3364 if (devip != dp)
3365 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3366 dp->uas_bm);
3367 }
3368 break;
3369 case 0x7: /* download MC with offsets, save, and ACT */
3370 /* set UA on all devices (LUs) in this target */
3371 list_for_each_entry(dp,
3372 &devip->sdbg_host->dev_info_list,
3373 dev_list)
3374 if (dp->target == sdp->id)
3375 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3376 dp->uas_bm);
3377 break;
3378 default:
3379 /* do nothing for this command for other mode values */
3380 break;
3381 }
3382 return 0;
3383}
3384
Douglas Gilbertfd321192016-04-25 12:16:33 -04003385static int resp_comp_write(struct scsi_cmnd *scp,
3386 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003387{
3388 u8 *cmd = scp->cmnd;
3389 u8 *arr;
3390 u8 *fake_storep_hold;
3391 u64 lba;
3392 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003393 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003394 u8 num;
3395 unsigned long iflags;
3396 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003397 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003398
Douglas Gilbertd467d312014-11-26 12:33:48 -05003399 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003400 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3401 if (0 == num)
3402 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003403 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003404 (cmd[1] & 0xe0)) {
3405 mk_sense_invalid_opcode(scp);
3406 return check_condition_result;
3407 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003408 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3409 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003410 (cmd[1] & 0xe0) == 0)
3411 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3412 "to DIF device\n");
3413
3414 /* inline check_device_access_params() */
3415 if (lba + num > sdebug_capacity) {
3416 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3417 return check_condition_result;
3418 }
3419 /* transfer length excessive (tie in to block limits VPD page) */
3420 if (num > sdebug_store_sectors) {
3421 /* needs work to find which cdb byte 'num' comes from */
3422 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3423 return check_condition_result;
3424 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003425 dnum = 2 * num;
3426 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3427 if (NULL == arr) {
3428 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3429 INSUFF_RES_ASCQ);
3430 return check_condition_result;
3431 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003432
3433 write_lock_irqsave(&atomic_rw, iflags);
3434
3435 /* trick do_device_access() to fetch both compare and write buffers
3436 * from data-in into arr. Safe (atomic) since write_lock held. */
3437 fake_storep_hold = fake_storep;
3438 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003439 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003440 fake_storep = fake_storep_hold;
3441 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003442 retval = DID_ERROR << 16;
3443 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003444 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003445 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3446 "indicated=%u, IO sent=%d bytes\n", my_name,
3447 dnum * lb_size, ret);
3448 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003449 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003450 retval = check_condition_result;
3451 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003452 }
3453 if (scsi_debug_lbp())
3454 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003455cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003456 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003457 kfree(arr);
3458 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003459}
3460
Martin K. Petersen44d92692009-10-15 14:45:27 -04003461struct unmap_block_desc {
3462 __be64 lba;
3463 __be32 blocks;
3464 __be32 __reserved;
3465};
3466
Douglas Gilbertfd321192016-04-25 12:16:33 -04003467static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003468{
3469 unsigned char *buf;
3470 struct unmap_block_desc *desc;
3471 unsigned int i, payload_len, descriptors;
3472 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003473 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003474
Martin K. Petersen44d92692009-10-15 14:45:27 -04003475
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003476 if (!scsi_debug_lbp())
3477 return 0; /* fib and say its done */
3478 payload_len = get_unaligned_be16(scp->cmnd + 7);
3479 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003480
3481 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003482 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003483 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003484 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003485 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003486
Douglas Gilbertb333a812016-04-25 12:16:30 -04003487 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003488 if (!buf) {
3489 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3490 INSUFF_RES_ASCQ);
3491 return check_condition_result;
3492 }
3493
3494 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003495
3496 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3497 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3498
3499 desc = (void *)&buf[8];
3500
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003501 write_lock_irqsave(&atomic_rw, iflags);
3502
Martin K. Petersen44d92692009-10-15 14:45:27 -04003503 for (i = 0 ; i < descriptors ; i++) {
3504 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3505 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3506
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003507 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003508 if (ret)
3509 goto out;
3510
3511 unmap_region(lba, num);
3512 }
3513
3514 ret = 0;
3515
3516out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003517 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003518 kfree(buf);
3519
3520 return ret;
3521}
3522
3523#define SDEBUG_GET_LBA_STATUS_LEN 32
3524
Douglas Gilbertfd321192016-04-25 12:16:33 -04003525static int resp_get_lba_status(struct scsi_cmnd *scp,
3526 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003527{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003528 u8 *cmd = scp->cmnd;
3529 u64 lba;
3530 u32 alloc_len, mapped, num;
3531 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003532 int ret;
3533
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003534 lba = get_unaligned_be64(cmd + 2);
3535 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003536
3537 if (alloc_len < 24)
3538 return 0;
3539
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003540 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003541 if (ret)
3542 return ret;
3543
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003544 if (scsi_debug_lbp())
3545 mapped = map_state(lba, &num);
3546 else {
3547 mapped = 1;
3548 /* following just in case virtual_gb changed */
3549 sdebug_capacity = get_sdebug_capacity();
3550 if (sdebug_capacity - lba <= 0xffffffff)
3551 num = sdebug_capacity - lba;
3552 else
3553 num = 0xffffffff;
3554 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003555
3556 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003557 put_unaligned_be32(20, arr); /* Parameter Data Length */
3558 put_unaligned_be64(lba, arr + 8); /* LBA */
3559 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3560 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003561
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003562 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003563}
3564
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003565#define RL_BUCKET_ELEMS 8
3566
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003567/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3568 * (W-LUN), the normal Linux scanning logic does not associate it with a
3569 * device (e.g. /dev/sg7). The following magic will make that association:
3570 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3571 * where <n> is a host number. If there are multiple targets in a host then
3572 * the above will associate a W-LUN to each target. To only get a W-LUN
3573 * for target 2, then use "echo '- 2 49409' > scan" .
3574 */
3575static int resp_report_luns(struct scsi_cmnd *scp,
3576 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003578 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003579 unsigned int alloc_len;
3580 unsigned char select_report;
3581 u64 lun;
3582 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003583 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003584 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3585 unsigned int wlun_cnt; /* report luns W-LUN count */
3586 unsigned int tlun_cnt; /* total LUN count */
3587 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003588 int k, j, n, res;
3589 unsigned int off_rsp = 0;
3590 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003592 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003593
3594 select_report = cmd[2];
3595 alloc_len = get_unaligned_be32(cmd + 6);
3596
3597 if (alloc_len < 4) {
3598 pr_err("alloc len too small %d\n", alloc_len);
3599 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 return check_condition_result;
3601 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003602
3603 switch (select_report) {
3604 case 0: /* all LUNs apart from W-LUNs */
3605 lun_cnt = sdebug_max_luns;
3606 wlun_cnt = 0;
3607 break;
3608 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003609 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003610 wlun_cnt = 1;
3611 break;
3612 case 2: /* all LUNs */
3613 lun_cnt = sdebug_max_luns;
3614 wlun_cnt = 1;
3615 break;
3616 case 0x10: /* only administrative LUs */
3617 case 0x11: /* see SPC-5 */
3618 case 0x12: /* only subsiduary LUs owned by referenced LU */
3619 default:
3620 pr_debug("select report invalid %d\n", select_report);
3621 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3622 return check_condition_result;
3623 }
3624
3625 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003626 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003627
3628 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003629 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3630 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003631 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3632 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3633
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003634 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003635 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003636 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3637 memset(arr, 0, sizeof(arr));
3638 lun_p = (struct scsi_lun *)&arr[0];
3639 if (k == 0) {
3640 put_unaligned_be32(rlen, &arr[0]);
3641 ++lun_p;
3642 j = 1;
3643 }
3644 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3645 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3646 break;
3647 int_to_scsilun(lun++, lun_p);
3648 }
3649 if (j < RL_BUCKET_ELEMS)
3650 break;
3651 n = j * sz_lun;
3652 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3653 if (res)
3654 return res;
3655 off_rsp += n;
3656 }
3657 if (wlun_cnt) {
3658 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3659 ++j;
3660 }
3661 if (j > 0)
3662 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003663 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664}
3665
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003666static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3667 unsigned int num, struct sdebug_dev_info *devip)
3668{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003669 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003670 unsigned char *kaddr, *buf;
3671 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003672 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003673 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003674
3675 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003676 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003677 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003678 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3679 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003680 return check_condition_result;
3681 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003682
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003683 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003684
3685 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003686 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3687 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003688
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003689 while (sg_miter_next(&miter)) {
3690 kaddr = miter.addr;
3691 for (j = 0; j < miter.length; j++)
3692 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003693
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003694 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003695 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003696 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003697 kfree(buf);
3698
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003699 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003700}
3701
Douglas Gilbertfd321192016-04-25 12:16:33 -04003702static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3703 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003704{
3705 u8 *cmd = scp->cmnd;
3706 u64 lba;
3707 u32 num;
3708 int errsts;
3709
3710 if (!scsi_bidi_cmnd(scp)) {
3711 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3712 INSUFF_RES_ASCQ);
3713 return check_condition_result;
3714 }
3715 errsts = resp_read_dt0(scp, devip);
3716 if (errsts)
3717 return errsts;
3718 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3719 errsts = resp_write_dt0(scp, devip);
3720 if (errsts)
3721 return errsts;
3722 }
3723 lba = get_unaligned_be32(cmd + 2);
3724 num = get_unaligned_be16(cmd + 7);
3725 return resp_xdwriteread(scp, lba, num, devip);
3726}
3727
Douglas Gilbertc4837392016-05-06 00:40:26 -04003728static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3729{
3730 struct sdebug_queue *sqp = sdebug_q_arr;
3731
3732 if (sdebug_mq_active) {
3733 u32 tag = blk_mq_unique_tag(cmnd->request);
3734 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3735
3736 if (unlikely(hwq >= submit_queues)) {
3737 pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3738 hwq %= submit_queues;
3739 }
3740 pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3741 return sqp + hwq;
3742 } else
3743 return sqp;
3744}
3745
3746/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003747static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003749 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003750 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003752 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003753 struct sdebug_queued_cmd *sqcp;
3754 struct scsi_cmnd *scp;
3755 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
Douglas Gilbert10bde982018-01-10 16:57:31 -05003757 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003758 qc_idx = sd_dp->qc_idx;
3759 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3760 if (sdebug_statistics) {
3761 atomic_inc(&sdebug_completions);
3762 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3763 atomic_inc(&sdebug_miss_cpus);
3764 }
3765 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3766 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 return;
3768 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003769 spin_lock_irqsave(&sqp->qc_lock, iflags);
3770 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003771 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003772 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003773 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3774 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3775 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 return;
3777 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003778 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003779 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003780 atomic_dec(&devip->num_in_q);
3781 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003782 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003783 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003784 retiring = 1;
3785
3786 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003787 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3788 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003789 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003790 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003792
3793 if (unlikely(retiring)) { /* user has reduced max_queue */
3794 int k, retval;
3795
3796 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003797 if (qc_idx >= retval) {
3798 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003799 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003800 return;
3801 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003802 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003803 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003804 atomic_set(&retired_max_queue, 0);
3805 else
3806 atomic_set(&retired_max_queue, k + 1);
3807 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003808 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003809 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810}
3811
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003812/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003813static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003814{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003815 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3816 hrt);
3817 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003818 return HRTIMER_NORESTART;
3819}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820
Douglas Gilberta10bc122016-04-25 12:16:32 -04003821/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003822static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003823{
3824 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3825 ew.work);
3826 sdebug_q_cmd_complete(sd_dp);
3827}
3828
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003829static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003830static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003831
Douglas Gilbertfd321192016-04-25 12:16:33 -04003832static struct sdebug_dev_info *sdebug_device_create(
3833 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003834{
3835 struct sdebug_dev_info *devip;
3836
3837 devip = kzalloc(sizeof(*devip), flags);
3838 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003839 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003840 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003841 else if (sdebug_uuid_ctl == 2) {
3842 if (got_shared_uuid)
3843 devip->lu_name = shared_uuid;
3844 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003845 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003846 got_shared_uuid = true;
3847 devip->lu_name = shared_uuid;
3848 }
3849 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003850 devip->sdbg_host = sdbg_host;
3851 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3852 }
3853 return devip;
3854}
3855
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003856static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003858 struct sdebug_host_info *sdbg_host;
3859 struct sdebug_dev_info *open_devip = NULL;
3860 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003862 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3863 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003864 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3868 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003869 (devip->target == sdev->id) &&
3870 (devip->lun == sdev->lun))
3871 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 else {
3873 if ((!devip->used) && (!open_devip))
3874 open_devip = devip;
3875 }
3876 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003877 if (!open_devip) { /* try and make a new one */
3878 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3879 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003880 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 return NULL;
3882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003884
3885 open_devip->channel = sdev->channel;
3886 open_devip->target = sdev->id;
3887 open_devip->lun = sdev->lun;
3888 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003889 atomic_set(&open_devip->num_in_q, 0);
3890 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003891 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003892 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893}
3894
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003895static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003897 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003898 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003899 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Bart Van Assche8b904b52018-03-07 17:10:10 -08003900 blk_queue_flag_set(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003901 return 0;
3902}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003904static int scsi_debug_slave_configure(struct scsi_device *sdp)
3905{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003906 struct sdebug_dev_info *devip =
3907 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003908
Douglas Gilbert773642d2016-04-25 12:16:28 -04003909 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003910 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003911 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003912 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3913 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3914 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003915 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003916 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003917 return 1; /* no resources, will be marked offline */
3918 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003919 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003920 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003921 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003922 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003923 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003924 return 0;
3925}
3926
3927static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3928{
3929 struct sdebug_dev_info *devip =
3930 (struct sdebug_dev_info *)sdp->hostdata;
3931
Douglas Gilbert773642d2016-04-25 12:16:28 -04003932 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003933 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003934 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3935 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003936 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003937 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003938 sdp->hostdata = NULL;
3939 }
3940}
3941
Douglas Gilbert10bde982018-01-10 16:57:31 -05003942static void stop_qc_helper(struct sdebug_defer *sd_dp,
3943 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003944{
3945 if (!sd_dp)
3946 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003947 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003948 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003949 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003950 cancel_work_sync(&sd_dp->ew.work);
3951}
3952
Douglas Gilberta10bc122016-04-25 12:16:32 -04003953/* If @cmnd found deletes its timer or work queue and returns true; else
3954 returns false */
3955static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003956{
3957 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003958 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003959 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003960 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003961 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003962 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003963 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003964
Douglas Gilbertc4837392016-05-06 00:40:26 -04003965 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3966 spin_lock_irqsave(&sqp->qc_lock, iflags);
3967 qmax = sdebug_max_queue;
3968 r_qmax = atomic_read(&retired_max_queue);
3969 if (r_qmax > qmax)
3970 qmax = r_qmax;
3971 for (k = 0; k < qmax; ++k) {
3972 if (test_bit(k, sqp->in_use_bm)) {
3973 sqcp = &sqp->qc_arr[k];
3974 if (cmnd != sqcp->a_cmnd)
3975 continue;
3976 /* found */
3977 devip = (struct sdebug_dev_info *)
3978 cmnd->device->hostdata;
3979 if (devip)
3980 atomic_dec(&devip->num_in_q);
3981 sqcp->a_cmnd = NULL;
3982 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003983 if (sd_dp) {
3984 l_defer_t = sd_dp->defer_t;
3985 sd_dp->defer_t = SDEB_DEFER_NONE;
3986 } else
3987 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003988 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003989 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003990 clear_bit(k, sqp->in_use_bm);
3991 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003992 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003993 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003994 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003995 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003996 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003997}
3998
Douglas Gilberta10bc122016-04-25 12:16:32 -04003999/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004000static void stop_all_queued(void)
4001{
4002 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004003 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004004 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004005 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004006 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004007 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004008 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004009
Douglas Gilbertc4837392016-05-06 00:40:26 -04004010 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4011 spin_lock_irqsave(&sqp->qc_lock, iflags);
4012 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4013 if (test_bit(k, sqp->in_use_bm)) {
4014 sqcp = &sqp->qc_arr[k];
4015 if (sqcp->a_cmnd == NULL)
4016 continue;
4017 devip = (struct sdebug_dev_info *)
4018 sqcp->a_cmnd->device->hostdata;
4019 if (devip)
4020 atomic_dec(&devip->num_in_q);
4021 sqcp->a_cmnd = NULL;
4022 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004023 if (sd_dp) {
4024 l_defer_t = sd_dp->defer_t;
4025 sd_dp->defer_t = SDEB_DEFER_NONE;
4026 } else
4027 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004028 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004029 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004030 clear_bit(k, sqp->in_use_bm);
4031 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004032 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004033 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004034 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036}
4037
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004038/* Free queued command memory on heap */
4039static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004041 int j, k;
4042 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004043 struct sdebug_queued_cmd *sqcp;
4044
Douglas Gilbertc4837392016-05-06 00:40:26 -04004045 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4046 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4047 sqcp = &sqp->qc_arr[k];
4048 kfree(sqcp->sd_dp);
4049 sqcp->sd_dp = NULL;
4050 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052}
4053
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004054static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004056 bool ok;
4057
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004058 ++num_aborts;
4059 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004060 ok = stop_queued_cmnd(SCpnt);
4061 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4062 sdev_printk(KERN_INFO, SCpnt->device,
4063 "%s: command%s found\n", __func__,
4064 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004066 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067}
4068
4069static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
4070{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004072 if (SCpnt && SCpnt->device) {
4073 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004074 struct sdebug_dev_info *devip =
4075 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004076
Douglas Gilbert773642d2016-04-25 12:16:28 -04004077 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004078 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004080 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 }
4082 return SUCCESS;
4083}
4084
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004085static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4086{
4087 struct sdebug_host_info *sdbg_host;
4088 struct sdebug_dev_info *devip;
4089 struct scsi_device *sdp;
4090 struct Scsi_Host *hp;
4091 int k = 0;
4092
4093 ++num_target_resets;
4094 if (!SCpnt)
4095 goto lie;
4096 sdp = SCpnt->device;
4097 if (!sdp)
4098 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004099 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004100 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4101 hp = sdp->host;
4102 if (!hp)
4103 goto lie;
4104 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4105 if (sdbg_host) {
4106 list_for_each_entry(devip,
4107 &sdbg_host->dev_info_list,
4108 dev_list)
4109 if (devip->target == sdp->id) {
4110 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4111 ++k;
4112 }
4113 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004114 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004115 sdev_printk(KERN_INFO, sdp,
4116 "%s: %d device(s) found in target\n", __func__, k);
4117lie:
4118 return SUCCESS;
4119}
4120
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
4122{
4123 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004124 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004125 struct scsi_device *sdp;
4126 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004127 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004130 if (!(SCpnt && SCpnt->device))
4131 goto lie;
4132 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004133 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004134 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4135 hp = sdp->host;
4136 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004137 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004139 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05004140 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004141 dev_list) {
4142 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4143 ++k;
4144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 }
4146 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004147 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004148 sdev_printk(KERN_INFO, sdp,
4149 "%s: %d device(s) found in host\n", __func__, k);
4150lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 return SUCCESS;
4152}
4153
4154static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
4155{
4156 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004157 struct sdebug_dev_info *devip;
4158 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004161 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004162 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05004163 spin_lock(&sdebug_host_list_lock);
4164 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004165 list_for_each_entry(devip, &sdbg_host->dev_info_list,
4166 dev_list) {
4167 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4168 ++k;
4169 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05004170 }
4171 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004173 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004174 sdev_printk(KERN_INFO, SCpnt->device,
4175 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 return SUCCESS;
4177}
4178
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09004179static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004180 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181{
4182 struct partition * pp;
4183 int starts[SDEBUG_MAX_PARTS + 2];
4184 int sectors_per_part, num_sectors, k;
4185 int heads_by_sects, start_sec, end_sec;
4186
4187 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004188 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004190 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4191 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03004192 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004194 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004196 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004198 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004199 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4201 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004202 starts[sdebug_num_parts] = num_sectors;
4203 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204
4205 ramp[510] = 0x55; /* magic partition markings */
4206 ramp[511] = 0xAA;
4207 pp = (struct partition *)(ramp + 0x1be);
4208 for (k = 0; starts[k + 1]; ++k, ++pp) {
4209 start_sec = starts[k];
4210 end_sec = starts[k + 1] - 1;
4211 pp->boot_ind = 0;
4212
4213 pp->cyl = start_sec / heads_by_sects;
4214 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4215 / sdebug_sectors_per;
4216 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4217
4218 pp->end_cyl = end_sec / heads_by_sects;
4219 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4220 / sdebug_sectors_per;
4221 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4222
Akinobu Mita150c3542013-08-26 22:08:40 +09004223 pp->start_sect = cpu_to_le32(start_sec);
4224 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 pp->sys_ind = 0x83; /* plain Linux partition */
4226 }
4227}
4228
Douglas Gilbertc4837392016-05-06 00:40:26 -04004229static void block_unblock_all_queues(bool block)
4230{
4231 int j;
4232 struct sdebug_queue *sqp;
4233
4234 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4235 atomic_set(&sqp->blocked, (int)block);
4236}
4237
4238/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4239 * commands will be processed normally before triggers occur.
4240 */
4241static void tweak_cmnd_count(void)
4242{
4243 int count, modulo;
4244
4245 modulo = abs(sdebug_every_nth);
4246 if (modulo < 2)
4247 return;
4248 block_unblock_all_queues(true);
4249 count = atomic_read(&sdebug_cmnd_count);
4250 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4251 block_unblock_all_queues(false);
4252}
4253
4254static void clear_queue_stats(void)
4255{
4256 atomic_set(&sdebug_cmnd_count, 0);
4257 atomic_set(&sdebug_completions, 0);
4258 atomic_set(&sdebug_miss_cpus, 0);
4259 atomic_set(&sdebug_a_tsf, 0);
4260}
4261
4262static void setup_inject(struct sdebug_queue *sqp,
4263 struct sdebug_queued_cmd *sqcp)
4264{
4265 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4266 return;
4267 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4268 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4269 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4270 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4271 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004272 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004273}
4274
4275/* Complete the processing of the thread that queued a SCSI command to this
4276 * driver. It either completes the command by calling cmnd_done() or
4277 * schedules a hr timer or work queue then returns 0. Returns
4278 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4279 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004280static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Douglas Gilbert10bde982018-01-10 16:57:31 -05004281 int scsi_result, int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004283 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004284 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004285 struct sdebug_queue *sqp;
4286 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004287 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004288 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004290 if (unlikely(devip == NULL)) {
4291 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004292 scsi_result = DID_NO_CONNECT << 16;
4293 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004295 sdp = cmnd->device;
4296
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004297 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004298 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4299 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004300 if (delta_jiff == 0)
4301 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004303 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004304 sqp = get_queue(cmnd);
4305 spin_lock_irqsave(&sqp->qc_lock, iflags);
4306 if (unlikely(atomic_read(&sqp->blocked))) {
4307 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4308 return SCSI_MLQUEUE_HOST_BUSY;
4309 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004310 num_in_q = atomic_read(&devip->num_in_q);
4311 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004312 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004313 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004314 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004315 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004316 goto respond_in_thread;
4317 } else
4318 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004319 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004320 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4321 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004322 if ((num_in_q == (qdepth - 1)) &&
4323 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004324 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004325 atomic_set(&sdebug_a_tsf, 0);
4326 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004327 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004329 }
4330
Douglas Gilbertc4837392016-05-06 00:40:26 -04004331 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004332 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004333 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004334 if (scsi_result)
4335 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004336 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004337 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004338 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004339 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004340 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004341 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004342 (scsi_result ? "status: TASK SET FULL" :
4343 "report: host busy"));
4344 if (scsi_result)
4345 goto respond_in_thread;
4346 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004347 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004349 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004350 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004351 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004352 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004353 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004354 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004355 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004356 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4357 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4358 setup_inject(sqp, sqcp);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004359 if (sd_dp == NULL) {
4360 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4361 if (sd_dp == NULL)
4362 return SCSI_MLQUEUE_HOST_BUSY;
4363 }
4364 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004365 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004366
Douglas Gilbertb333a812016-04-25 12:16:30 -04004367 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004368 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004369 } else
Douglas Gilbert10bde982018-01-10 16:57:31 -05004370 kt = ndelay;
4371 if (!sd_dp->init_hrt) {
4372 sd_dp->init_hrt = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004373 sqcp->sd_dp = sd_dp;
4374 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004375 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004376 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004377 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4378 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004379 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004380 if (sdebug_statistics)
4381 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004382 sd_dp->defer_t = SDEB_DEFER_HRT;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004383 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4384 } else { /* jdelay < 0, use work queue */
Douglas Gilbert10bde982018-01-10 16:57:31 -05004385 if (!sd_dp->init_wq) {
4386 sd_dp->init_wq = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004387 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004388 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4389 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004390 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004391 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004392 if (sdebug_statistics)
4393 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004394 sd_dp->defer_t = SDEB_DEFER_WQ;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004395 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004396 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004397 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4398 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004399 sdev_printk(KERN_INFO, sdp,
4400 "%s: num_in_q=%d +1, %s%s\n", __func__,
4401 num_in_q, (inject ? "<inject> " : ""),
4402 "status: TASK SET FULL");
4403 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004404
4405respond_in_thread: /* call back to mid-layer using invocation thread */
4406 cmnd->result = scsi_result;
4407 cmnd->scsi_done(cmnd);
4408 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004410
Douglas Gilbert23183912006-09-16 20:30:47 -04004411/* Note: The following macros create attribute files in the
4412 /sys/module/scsi_debug/parameters directory. Unfortunately this
4413 driver is unaware of a change and cannot trigger auxiliary actions
4414 as it can when the corresponding attribute in the
4415 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4416 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004417module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4418module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004419module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004420module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004421module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004422module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4423module_param_named(dif, sdebug_dif, int, S_IRUGO);
4424module_param_named(dix, sdebug_dix, int, S_IRUGO);
4425module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4426module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4427module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4428module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4429module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004430module_param_string(inq_vendor, sdebug_inq_vendor_id,
4431 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4432module_param_string(inq_product, sdebug_inq_product_id,
4433 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4434module_param_string(inq_rev, sdebug_inq_product_rev,
4435 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004436module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4437module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4438module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4439module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4440module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4441module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4442module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4443module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4444module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4445module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4446module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4447module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4448module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4449module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4450module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004451module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004452module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4453module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4454module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4455module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004456module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004457module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004458module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004459module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4460module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4461module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4462module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4463module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004464module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004465module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004466 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004467module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004468 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469
4470MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4471MODULE_DESCRIPTION("SCSI debug adapter driver");
4472MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004473MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474
4475MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004476MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004477MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004478MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004479MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004480MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004481MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4482MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004483MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004484MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004485MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004486MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004487MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004488MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4489MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004490MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4491 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004492MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4493MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4494MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004495MODULE_PARM_DESC(lbprz,
4496 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004497MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004498MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004499MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4500MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004501MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004502MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004504MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004505MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004506MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004507MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004508MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004510MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004511MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004512MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004513MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004514MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004515MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004516MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4517MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004518MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4519MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004520MODULE_PARM_DESC(uuid_ctl,
4521 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004522MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004523MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4524MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004526#define SDEBUG_INFO_LEN 256
4527static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528
4529static const char * scsi_debug_info(struct Scsi_Host * shp)
4530{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004531 int k;
4532
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004533 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4534 my_name, SDEBUG_VERSION, sdebug_version_date);
4535 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004536 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004537 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4538 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4539 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4540 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 return sdebug_info;
4542}
4543
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004544/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004545static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4546 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547{
Al Viroc8ed5552013-03-31 01:46:06 -04004548 char arr[16];
4549 int opts;
4550 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
Al Viroc8ed5552013-03-31 01:46:06 -04004552 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4553 return -EACCES;
4554 memcpy(arr, buffer, minLen);
4555 arr[minLen] = '\0';
4556 if (1 != sscanf(arr, "%d", &opts))
4557 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004558 sdebug_opts = opts;
4559 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4560 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4561 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004562 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004563 return length;
4564}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004566/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4567 * same for each scsi_debug host (if more than one). Some of the counters
4568 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004569static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4570{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004571 int f, j, l;
4572 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004573
Douglas Gilbertc4837392016-05-06 00:40:26 -04004574 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4575 SDEBUG_VERSION, sdebug_version_date);
4576 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4577 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4578 sdebug_opts, sdebug_every_nth);
4579 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4580 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4581 sdebug_sector_size, "bytes");
4582 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4583 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4584 num_aborts);
4585 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4586 num_dev_resets, num_target_resets, num_bus_resets,
4587 num_host_resets);
4588 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4589 dix_reads, dix_writes, dif_errors);
4590 seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4591 TICK_NSEC / 1000, "statistics", sdebug_statistics,
4592 sdebug_mq_active);
4593 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4594 atomic_read(&sdebug_cmnd_count),
4595 atomic_read(&sdebug_completions),
4596 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4597 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004598
Douglas Gilbertc4837392016-05-06 00:40:26 -04004599 seq_printf(m, "submit_queues=%d\n", submit_queues);
4600 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4601 seq_printf(m, " queue %d:\n", j);
4602 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4603 if (f != sdebug_max_queue) {
4604 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4605 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4606 "first,last bits", f, l);
4607 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004608 }
Al Viroc8ed5552013-03-31 01:46:06 -04004609 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610}
4611
Akinobu Mita82069372013-10-14 22:48:04 +09004612static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004614 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004616/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4617 * of delay is jiffies.
4618 */
Akinobu Mita82069372013-10-14 22:48:04 +09004619static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4620 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004622 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004624 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004625 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004626 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004627 int j, k;
4628 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004629
Douglas Gilbertc4837392016-05-06 00:40:26 -04004630 block_unblock_all_queues(true);
4631 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4632 ++j, ++sqp) {
4633 k = find_first_bit(sqp->in_use_bm,
4634 sdebug_max_queue);
4635 if (k != sdebug_max_queue) {
4636 res = -EBUSY; /* queued commands */
4637 break;
4638 }
4639 }
4640 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04004641 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004642 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004643 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004644 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004646 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 }
4648 return -EINVAL;
4649}
Akinobu Mita82069372013-10-14 22:48:04 +09004650static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004652static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4653{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004654 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004655}
4656/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004657/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004658static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004659 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004660{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004661 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004662
4663 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004664 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004665 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004666 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004667 int j, k;
4668 struct sdebug_queue *sqp;
4669
4670 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 Gilbert773642d2016-04-25 12:16:28 -04004681 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004682 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4683 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004684 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004685 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004686 }
4687 return res;
4688 }
4689 return -EINVAL;
4690}
4691static DRIVER_ATTR_RW(ndelay);
4692
Akinobu Mita82069372013-10-14 22:48:04 +09004693static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004695 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696}
4697
Akinobu Mita82069372013-10-14 22:48:04 +09004698static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4699 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004701 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 char work[20];
4703
Douglas Gilbert9a051012017-12-23 12:48:10 -05004704 if (sscanf(buf, "%10s", work) == 1) {
4705 if (strncasecmp(work, "0x", 2) == 0) {
4706 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 goto opts_done;
4708 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004709 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 goto opts_done;
4711 }
4712 }
4713 return -EINVAL;
4714opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004715 sdebug_opts = opts;
4716 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4717 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004718 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 return count;
4720}
Akinobu Mita82069372013-10-14 22:48:04 +09004721static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
Akinobu Mita82069372013-10-14 22:48:04 +09004723static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004725 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726}
Akinobu Mita82069372013-10-14 22:48:04 +09004727static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4728 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004730 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731
4732 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004733 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 return count;
4735 }
4736 return -EINVAL;
4737}
Akinobu Mita82069372013-10-14 22:48:04 +09004738static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739
Akinobu Mita82069372013-10-14 22:48:04 +09004740static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004742 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743}
Akinobu Mita82069372013-10-14 22:48:04 +09004744static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4745 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004747 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
4749 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004750 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 return count;
4752 }
4753 return -EINVAL;
4754}
Akinobu Mita82069372013-10-14 22:48:04 +09004755static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756
Akinobu Mita82069372013-10-14 22:48:04 +09004757static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004758{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004759 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004760}
Akinobu Mita82069372013-10-14 22:48:04 +09004761static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4762 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004763{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004764 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004765
4766 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004767 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004768 sdebug_fake_rw = (sdebug_fake_rw > 0);
4769 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004770 if ((0 == n) && (NULL == fake_storep)) {
4771 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004772 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004773 1048576;
4774
4775 fake_storep = vmalloc(sz);
4776 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004777 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004778 return -ENOMEM;
4779 }
4780 memset(fake_storep, 0, sz);
4781 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004782 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004783 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004784 return count;
4785 }
4786 return -EINVAL;
4787}
Akinobu Mita82069372013-10-14 22:48:04 +09004788static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004789
Akinobu Mita82069372013-10-14 22:48:04 +09004790static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004791{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004792 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004793}
Akinobu Mita82069372013-10-14 22:48:04 +09004794static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4795 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004796{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004797 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004798
4799 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004800 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004801 return count;
4802 }
4803 return -EINVAL;
4804}
Akinobu Mita82069372013-10-14 22:48:04 +09004805static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004806
Akinobu Mita82069372013-10-14 22:48:04 +09004807static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004809 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810}
Akinobu Mita82069372013-10-14 22:48:04 +09004811static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4812 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004814 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815
4816 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004817 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 sdebug_max_tgts_luns();
4819 return count;
4820 }
4821 return -EINVAL;
4822}
Akinobu Mita82069372013-10-14 22:48:04 +09004823static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824
Akinobu Mita82069372013-10-14 22:48:04 +09004825static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004827 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828}
Akinobu Mita82069372013-10-14 22:48:04 +09004829static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830
Akinobu Mita82069372013-10-14 22:48:04 +09004831static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004833 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834}
Akinobu Mita82069372013-10-14 22:48:04 +09004835static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
Akinobu Mita82069372013-10-14 22:48:04 +09004837static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004839 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840}
Akinobu Mita82069372013-10-14 22:48:04 +09004841static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4842 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004844 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845
4846 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004847 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004848 if (nth && !sdebug_statistics) {
4849 pr_info("every_nth needs statistics=1, set it\n");
4850 sdebug_statistics = true;
4851 }
4852 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 return count;
4854 }
4855 return -EINVAL;
4856}
Akinobu Mita82069372013-10-14 22:48:04 +09004857static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858
Akinobu Mita82069372013-10-14 22:48:04 +09004859static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004861 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862}
Akinobu Mita82069372013-10-14 22:48:04 +09004863static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4864 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004866 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004867 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868
4869 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004870 if (n > 256) {
4871 pr_warn("max_luns can be no more than 256\n");
4872 return -EINVAL;
4873 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004874 changed = (sdebug_max_luns != n);
4875 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004877 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004878 struct sdebug_host_info *sdhp;
4879 struct sdebug_dev_info *dp;
4880
4881 spin_lock(&sdebug_host_list_lock);
4882 list_for_each_entry(sdhp, &sdebug_host_list,
4883 host_list) {
4884 list_for_each_entry(dp, &sdhp->dev_info_list,
4885 dev_list) {
4886 set_bit(SDEBUG_UA_LUNS_CHANGED,
4887 dp->uas_bm);
4888 }
4889 }
4890 spin_unlock(&sdebug_host_list_lock);
4891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 return count;
4893 }
4894 return -EINVAL;
4895}
Akinobu Mita82069372013-10-14 22:48:04 +09004896static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897
Akinobu Mita82069372013-10-14 22:48:04 +09004898static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004899{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004900 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004901}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004902/* N.B. max_queue can be changed while there are queued commands. In flight
4903 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004904static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4905 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004906{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004907 int j, n, k, a;
4908 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004909
4910 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004911 (n <= SDEBUG_CANQUEUE)) {
4912 block_unblock_all_queues(true);
4913 k = 0;
4914 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4915 ++j, ++sqp) {
4916 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4917 if (a > k)
4918 k = a;
4919 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004920 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004921 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004922 atomic_set(&retired_max_queue, 0);
4923 else if (k >= n)
4924 atomic_set(&retired_max_queue, k + 1);
4925 else
4926 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004927 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004928 return count;
4929 }
4930 return -EINVAL;
4931}
Akinobu Mita82069372013-10-14 22:48:04 +09004932static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004933
Akinobu Mita82069372013-10-14 22:48:04 +09004934static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004935{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004936 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004937}
Akinobu Mita82069372013-10-14 22:48:04 +09004938static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004939
Akinobu Mita82069372013-10-14 22:48:04 +09004940static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004942 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943}
Akinobu Mita82069372013-10-14 22:48:04 +09004944static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945
Akinobu Mita82069372013-10-14 22:48:04 +09004946static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004947{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004948 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004949}
Akinobu Mita82069372013-10-14 22:48:04 +09004950static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4951 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004952{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004953 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004954 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004955
4956 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004957 changed = (sdebug_virtual_gb != n);
4958 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004959 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004960 if (changed) {
4961 struct sdebug_host_info *sdhp;
4962 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004963
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004964 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004965 list_for_each_entry(sdhp, &sdebug_host_list,
4966 host_list) {
4967 list_for_each_entry(dp, &sdhp->dev_info_list,
4968 dev_list) {
4969 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4970 dp->uas_bm);
4971 }
4972 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004973 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004974 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004975 return count;
4976 }
4977 return -EINVAL;
4978}
Akinobu Mita82069372013-10-14 22:48:04 +09004979static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004980
Akinobu Mita82069372013-10-14 22:48:04 +09004981static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004983 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984}
4985
Douglas Gilbertfd321192016-04-25 12:16:33 -04004986static int sdebug_add_adapter(void);
4987static void sdebug_remove_adapter(void);
4988
Akinobu Mita82069372013-10-14 22:48:04 +09004989static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4990 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004992 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004994 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 if (delta_hosts > 0) {
4997 do {
4998 sdebug_add_adapter();
4999 } while (--delta_hosts);
5000 } else if (delta_hosts < 0) {
5001 do {
5002 sdebug_remove_adapter();
5003 } while (++delta_hosts);
5004 }
5005 return count;
5006}
Akinobu Mita82069372013-10-14 22:48:04 +09005007static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008
Akinobu Mita82069372013-10-14 22:48:04 +09005009static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04005010{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005011 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005012}
Akinobu Mita82069372013-10-14 22:48:04 +09005013static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
5014 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04005015{
5016 int n;
5017
5018 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005019 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04005020 return count;
5021 }
5022 return -EINVAL;
5023}
Akinobu Mita82069372013-10-14 22:48:04 +09005024static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005025
Douglas Gilbertc4837392016-05-06 00:40:26 -04005026static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5027{
5028 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5029}
5030static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5031 size_t count)
5032{
5033 int n;
5034
5035 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5036 if (n > 0)
5037 sdebug_statistics = true;
5038 else {
5039 clear_queue_stats();
5040 sdebug_statistics = false;
5041 }
5042 return count;
5043 }
5044 return -EINVAL;
5045}
5046static DRIVER_ATTR_RW(statistics);
5047
Akinobu Mita82069372013-10-14 22:48:04 +09005048static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04005049{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005050 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005051}
Akinobu Mita82069372013-10-14 22:48:04 +09005052static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005053
Douglas Gilbertc4837392016-05-06 00:40:26 -04005054static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5055{
5056 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5057}
5058static DRIVER_ATTR_RO(submit_queues);
5059
Akinobu Mita82069372013-10-14 22:48:04 +09005060static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005061{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005062 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005063}
Akinobu Mita82069372013-10-14 22:48:04 +09005064static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005065
Akinobu Mita82069372013-10-14 22:48:04 +09005066static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005067{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005068 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005069}
Akinobu Mita82069372013-10-14 22:48:04 +09005070static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005071
Akinobu Mita82069372013-10-14 22:48:04 +09005072static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005073{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005074 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005075}
Akinobu Mita82069372013-10-14 22:48:04 +09005076static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005077
Akinobu Mita82069372013-10-14 22:48:04 +09005078static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005079{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005080 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005081}
Akinobu Mita82069372013-10-14 22:48:04 +09005082static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005083
Akinobu Mita82069372013-10-14 22:48:04 +09005084static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005085{
5086 ssize_t count;
5087
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005088 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04005089 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
5090 sdebug_store_sectors);
5091
Tejun Heoc7badc92015-02-13 14:37:51 -08005092 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5093 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005094 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08005095 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04005096
5097 return count;
5098}
Akinobu Mita82069372013-10-14 22:48:04 +09005099static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005100
Akinobu Mita82069372013-10-14 22:48:04 +09005101static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02005102{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005103 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02005104}
Akinobu Mita82069372013-10-14 22:48:04 +09005105static ssize_t removable_store(struct device_driver *ddp, const char *buf,
5106 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02005107{
5108 int n;
5109
5110 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005111 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02005112 return count;
5113 }
5114 return -EINVAL;
5115}
Akinobu Mita82069372013-10-14 22:48:04 +09005116static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02005117
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005118static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5119{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005120 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005121}
Douglas Gilbert185dd232016-04-25 12:16:29 -04005122/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005123static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5124 size_t count)
5125{
Douglas Gilbert185dd232016-04-25 12:16:29 -04005126 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005127
5128 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04005129 sdebug_host_lock = (n > 0);
5130 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005131 }
5132 return -EINVAL;
5133}
5134static DRIVER_ATTR_RW(host_lock);
5135
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005136static ssize_t strict_show(struct device_driver *ddp, char *buf)
5137{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005138 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005139}
5140static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5141 size_t count)
5142{
5143 int n;
5144
5145 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005146 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005147 return count;
5148 }
5149 return -EINVAL;
5150}
5151static DRIVER_ATTR_RW(strict);
5152
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005153static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
5154{
5155 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
5156}
5157static DRIVER_ATTR_RO(uuid_ctl);
5158
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005159static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
5160{
5161 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
5162}
5163static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
5164 size_t count)
5165{
5166 int ret, n;
5167
5168 ret = kstrtoint(buf, 0, &n);
5169 if (ret)
5170 return ret;
5171 sdebug_cdb_len = n;
5172 all_config_cdb_len();
5173 return count;
5174}
5175static DRIVER_ATTR_RW(cdb_len);
5176
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005177
Akinobu Mita82069372013-10-14 22:48:04 +09005178/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04005179 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
5180 files (over those found in the /sys/module/scsi_debug/parameters
5181 directory) is that auxiliary actions can be triggered when an attribute
5182 is changed. For example see: sdebug_add_host_store() above.
5183 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005184
Akinobu Mita82069372013-10-14 22:48:04 +09005185static struct attribute *sdebug_drv_attrs[] = {
5186 &driver_attr_delay.attr,
5187 &driver_attr_opts.attr,
5188 &driver_attr_ptype.attr,
5189 &driver_attr_dsense.attr,
5190 &driver_attr_fake_rw.attr,
5191 &driver_attr_no_lun_0.attr,
5192 &driver_attr_num_tgts.attr,
5193 &driver_attr_dev_size_mb.attr,
5194 &driver_attr_num_parts.attr,
5195 &driver_attr_every_nth.attr,
5196 &driver_attr_max_luns.attr,
5197 &driver_attr_max_queue.attr,
5198 &driver_attr_no_uld.attr,
5199 &driver_attr_scsi_level.attr,
5200 &driver_attr_virtual_gb.attr,
5201 &driver_attr_add_host.attr,
5202 &driver_attr_vpd_use_hostno.attr,
5203 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005204 &driver_attr_statistics.attr,
5205 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005206 &driver_attr_dix.attr,
5207 &driver_attr_dif.attr,
5208 &driver_attr_guard.attr,
5209 &driver_attr_ato.attr,
5210 &driver_attr_map.attr,
5211 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005212 &driver_attr_host_lock.attr,
5213 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005214 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005215 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005216 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005217 NULL,
5218};
5219ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005221static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005222
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223static int __init scsi_debug_init(void)
5224{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005225 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 int host_to_add;
5227 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005228 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005230 atomic_set(&retired_max_queue, 0);
5231
Douglas Gilbert773642d2016-04-25 12:16:28 -04005232 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005233 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005234 sdebug_ndelay = 0;
5235 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005236 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005237
Douglas Gilbert773642d2016-04-25 12:16:28 -04005238 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04005239 case 512:
5240 case 1024:
5241 case 2048:
5242 case 4096:
5243 break;
5244 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005245 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005246 return -EINVAL;
5247 }
5248
Douglas Gilbert773642d2016-04-25 12:16:28 -04005249 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005250 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005251 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005252 case T10_PI_TYPE1_PROTECTION:
5253 case T10_PI_TYPE2_PROTECTION:
5254 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005255 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005256 break;
5257
5258 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005259 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005260 return -EINVAL;
5261 }
5262
Douglas Gilbert773642d2016-04-25 12:16:28 -04005263 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005264 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005265 return -EINVAL;
5266 }
5267
Douglas Gilbert773642d2016-04-25 12:16:28 -04005268 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005269 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005270 return -EINVAL;
5271 }
5272
Douglas Gilbert773642d2016-04-25 12:16:28 -04005273 if (sdebug_physblk_exp > 15) {
5274 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005275 return -EINVAL;
5276 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005277 if (sdebug_max_luns > 256) {
5278 pr_warn("max_luns can be no more than 256, use default\n");
5279 sdebug_max_luns = DEF_MAX_LUNS;
5280 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005281
Douglas Gilbert773642d2016-04-25 12:16:28 -04005282 if (sdebug_lowest_aligned > 0x3fff) {
5283 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005284 return -EINVAL;
5285 }
5286
Douglas Gilbertc4837392016-05-06 00:40:26 -04005287 if (submit_queues < 1) {
5288 pr_err("submit_queues must be 1 or more\n");
5289 return -EINVAL;
5290 }
5291 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5292 GFP_KERNEL);
5293 if (sdebug_q_arr == NULL)
5294 return -ENOMEM;
5295 for (k = 0; k < submit_queues; ++k)
5296 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5297
Douglas Gilbert773642d2016-04-25 12:16:28 -04005298 if (sdebug_dev_size_mb < 1)
5299 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5300 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5301 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005302 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303
5304 /* play around with geometry, don't waste too much on track 0 */
5305 sdebug_heads = 8;
5306 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005307 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005309 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005310 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5312 (sdebug_sectors_per * sdebug_heads);
5313 if (sdebug_cylinders_per >= 1024) {
5314 /* other LLDs do this; implies >= 1GB ram disk ... */
5315 sdebug_heads = 255;
5316 sdebug_sectors_per = 63;
5317 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5318 (sdebug_sectors_per * sdebug_heads);
5319 }
5320
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005321 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005322 fake_storep = vmalloc(sz);
5323 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005324 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005325 ret = -ENOMEM;
5326 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005327 }
5328 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005329 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005330 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332
Douglas Gilbert773642d2016-04-25 12:16:28 -04005333 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005334 int dif_size;
5335
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005336 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005337 dif_storep = vmalloc(dif_size);
5338
Tomas Winklerc12879702015-07-28 16:54:20 +03005339 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005340
5341 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005342 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005343 ret = -ENOMEM;
5344 goto free_vm;
5345 }
5346
5347 memset(dif_storep, 0xff, dif_size);
5348 }
5349
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005350 /* Logical Block Provisioning */
5351 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005352 sdebug_unmap_max_blocks =
5353 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005354
Douglas Gilbert773642d2016-04-25 12:16:28 -04005355 sdebug_unmap_max_desc =
5356 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005357
Douglas Gilbert773642d2016-04-25 12:16:28 -04005358 sdebug_unmap_granularity =
5359 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005360
Douglas Gilbert773642d2016-04-25 12:16:28 -04005361 if (sdebug_unmap_alignment &&
5362 sdebug_unmap_granularity <=
5363 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005364 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005365 ret = -EINVAL;
5366 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005367 }
5368
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005369 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5370 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005371
Tomas Winklerc12879702015-07-28 16:54:20 +03005372 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005373
5374 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005375 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005376 ret = -ENOMEM;
5377 goto free_vm;
5378 }
5379
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005380 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005381
5382 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005383 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005384 map_region(0, 2);
5385 }
5386
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005387 pseudo_primary = root_device_register("pseudo_0");
5388 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005389 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005390 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005391 goto free_vm;
5392 }
5393 ret = bus_register(&pseudo_lld_bus);
5394 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005395 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005396 goto dev_unreg;
5397 }
5398 ret = driver_register(&sdebug_driverfs_driver);
5399 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005400 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005401 goto bus_unreg;
5402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403
Douglas Gilbert773642d2016-04-25 12:16:28 -04005404 host_to_add = sdebug_add_host;
5405 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406
Douglas Gilbert9a051012017-12-23 12:48:10 -05005407 for (k = 0; k < host_to_add; k++) {
5408 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005409 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005410 break;
5411 }
5412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413
Douglas Gilbert773642d2016-04-25 12:16:28 -04005414 if (sdebug_verbose)
5415 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005416
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005418
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005419bus_unreg:
5420 bus_unregister(&pseudo_lld_bus);
5421dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005422 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005423free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005424 vfree(map_storep);
5425 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005426 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005427free_q_arr:
5428 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005429 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430}
5431
5432static void __exit scsi_debug_exit(void)
5433{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005434 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435
5436 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005437 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 for (; k; k--)
5439 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 driver_unregister(&sdebug_driverfs_driver);
5441 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005442 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005444 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005445 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005447 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448}
5449
5450device_initcall(scsi_debug_init);
5451module_exit(scsi_debug_exit);
5452
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453static void sdebug_release_adapter(struct device * dev)
5454{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005455 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456
5457 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005458 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459}
5460
5461static int sdebug_add_adapter(void)
5462{
5463 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005464 int error = 0;
5465 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005466 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467
Douglas Gilbert9a051012017-12-23 12:48:10 -05005468 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5469 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005470 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005471 return -ENOMEM;
5472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473
Douglas Gilbert9a051012017-12-23 12:48:10 -05005474 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475
Douglas Gilbert773642d2016-04-25 12:16:28 -04005476 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005477 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005478 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5479 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005480 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005481 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005483 }
5484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485
Douglas Gilbert9a051012017-12-23 12:48:10 -05005486 spin_lock(&sdebug_host_list_lock);
5487 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5488 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489
Douglas Gilbert9a051012017-12-23 12:48:10 -05005490 sdbg_host->dev.bus = &pseudo_lld_bus;
5491 sdbg_host->dev.parent = pseudo_primary;
5492 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005493 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494
Douglas Gilbert9a051012017-12-23 12:48:10 -05005495 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496
Douglas Gilbert9a051012017-12-23 12:48:10 -05005497 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 goto clean;
5499
Douglas Gilbert773642d2016-04-25 12:16:28 -04005500 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005501 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502
5503clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005504 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5505 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506 list_del(&sdbg_devinfo->dev_list);
5507 kfree(sdbg_devinfo);
5508 }
5509
5510 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005511 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512}
5513
5514static void sdebug_remove_adapter(void)
5515{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005516 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517
Douglas Gilbert9a051012017-12-23 12:48:10 -05005518 spin_lock(&sdebug_host_list_lock);
5519 if (!list_empty(&sdebug_host_list)) {
5520 sdbg_host = list_entry(sdebug_host_list.prev,
5521 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 list_del(&sdbg_host->host_list);
5523 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005524 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525
5526 if (!sdbg_host)
5527 return;
5528
Douglas Gilbert773642d2016-04-25 12:16:28 -04005529 device_unregister(&sdbg_host->dev);
5530 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531}
5532
Douglas Gilbertfd321192016-04-25 12:16:33 -04005533static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005534{
5535 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005536 struct sdebug_dev_info *devip;
5537
Douglas Gilbertc4837392016-05-06 00:40:26 -04005538 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005539 devip = (struct sdebug_dev_info *)sdev->hostdata;
5540 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005541 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005542 return -ENODEV;
5543 }
5544 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005545
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005546 if (qdepth < 1)
5547 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005548 /* allow to exceed max host qc_arr elements for testing */
5549 if (qdepth > SDEBUG_CANQUEUE + 10)
5550 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005551 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005552
Douglas Gilbert773642d2016-04-25 12:16:28 -04005553 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005554 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005555 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005556 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005557 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005558 return sdev->queue_depth;
5559}
5560
Douglas Gilbertc4837392016-05-06 00:40:26 -04005561static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005562{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005563 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005564 if (sdebug_every_nth < -1)
5565 sdebug_every_nth = -1;
5566 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005567 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005568 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005569 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005570 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005571 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005572 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005573}
5574
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005575static bool fake_host_busy(struct scsi_cmnd *scp)
5576{
5577 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5578 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5579}
5580
Douglas Gilbertfd321192016-04-25 12:16:33 -04005581static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5582 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005583{
5584 u8 sdeb_i;
5585 struct scsi_device *sdp = scp->device;
5586 const struct opcode_info_t *oip;
5587 const struct opcode_info_t *r_oip;
5588 struct sdebug_dev_info *devip;
5589 u8 *cmd = scp->cmnd;
5590 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5591 int k, na;
5592 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005593 u32 flags;
5594 u16 sa;
5595 u8 opcode = cmd[0];
5596 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005597
5598 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005599 if (sdebug_statistics)
5600 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005601 if (unlikely(sdebug_verbose &&
5602 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005603 char b[120];
5604 int n, len, sb;
5605
5606 len = scp->cmd_len;
5607 sb = (int)sizeof(b);
5608 if (len > 32)
5609 strcpy(b, "too long, over 32 bytes");
5610 else {
5611 for (k = 0, n = 0; k < len && n < sb; ++k)
5612 n += scnprintf(b + n, sb - n, "%02x ",
5613 (u32)cmd[k]);
5614 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005615 if (sdebug_mq_active)
5616 sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5617 my_name, blk_mq_unique_tag(scp->request),
5618 b);
5619 else
5620 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5621 b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005622 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005623 if (fake_host_busy(scp))
5624 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005625 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005626 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5627 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005628
5629 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5630 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5631 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005632 if (unlikely(!devip)) {
5633 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005634 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005635 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005636 }
5637 na = oip->num_attached;
5638 r_pfp = oip->pfp;
5639 if (na) { /* multiple commands with this opcode */
5640 r_oip = oip;
5641 if (FF_SA & r_oip->flags) {
5642 if (F_SA_LOW & oip->flags)
5643 sa = 0x1f & cmd[1];
5644 else
5645 sa = get_unaligned_be16(cmd + 8);
5646 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5647 if (opcode == oip->opcode && sa == oip->sa)
5648 break;
5649 }
5650 } else { /* since no service action only check opcode */
5651 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5652 if (opcode == oip->opcode)
5653 break;
5654 }
5655 }
5656 if (k > na) {
5657 if (F_SA_LOW & r_oip->flags)
5658 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5659 else if (F_SA_HIGH & r_oip->flags)
5660 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5661 else
5662 mk_sense_invalid_opcode(scp);
5663 goto check_cond;
5664 }
5665 } /* else (when na==0) we assume the oip is a match */
5666 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005667 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005668 mk_sense_invalid_opcode(scp);
5669 goto check_cond;
5670 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005671 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005672 if (sdebug_verbose)
5673 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5674 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005675 mk_sense_invalid_opcode(scp);
5676 goto check_cond;
5677 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005678 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005679 u8 rem;
5680 int j;
5681
5682 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5683 rem = ~oip->len_mask[k] & cmd[k];
5684 if (rem) {
5685 for (j = 7; j >= 0; --j, rem <<= 1) {
5686 if (0x80 & rem)
5687 break;
5688 }
5689 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5690 goto check_cond;
5691 }
5692 }
5693 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005694 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005695 find_first_bit(devip->uas_bm,
5696 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005697 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005698 if (errsts)
5699 goto check_cond;
5700 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005701 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005702 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005703 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005704 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5705 "%s\n", my_name, "initializing command "
5706 "required");
5707 errsts = check_condition_result;
5708 goto fini;
5709 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005710 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005711 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005712 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005713 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005714 return 0; /* ignore command: make trouble */
5715 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005716 if (likely(oip->pfp))
5717 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005718 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5719 errsts = r_pfp(scp, devip);
5720
5721fini:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005722 if (F_DELAY_OVERR & flags)
5723 return schedule_resp(scp, devip, errsts, 0, 0);
5724 else
5725 return schedule_resp(scp, devip, errsts, sdebug_jdelay,
5726 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005727check_cond:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005728 return schedule_resp(scp, devip, check_condition_result, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005729err_out:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005730 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005731}
5732
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005733static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005734 .show_info = scsi_debug_show_info,
5735 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005736 .proc_name = sdebug_proc_name,
5737 .name = "SCSI DEBUG",
5738 .info = scsi_debug_info,
5739 .slave_alloc = scsi_debug_slave_alloc,
5740 .slave_configure = scsi_debug_slave_configure,
5741 .slave_destroy = scsi_debug_slave_destroy,
5742 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005743 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005744 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005745 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005746 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005747 .eh_target_reset_handler = scsi_debug_target_reset,
5748 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005749 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005750 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005751 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005752 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005753 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005754 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005755 .use_clustering = DISABLE_CLUSTERING,
5756 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005757 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005758};
5759
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760static int sdebug_driver_probe(struct device * dev)
5761{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005762 int error = 0;
5763 struct sdebug_host_info *sdbg_host;
5764 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005765 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766
5767 sdbg_host = to_sdebug_host(dev);
5768
Douglas Gilbert773642d2016-04-25 12:16:28 -04005769 sdebug_driver_template.can_queue = sdebug_max_queue;
5770 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005771 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005772 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5773 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005774 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005775 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005777 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005778 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005779 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005780 my_name, submit_queues, nr_cpu_ids);
5781 submit_queues = nr_cpu_ids;
5782 }
5783 /* Decide whether to tell scsi subsystem that we want mq */
5784 /* Following should give the same answer for each host */
5785 sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5786 if (sdebug_mq_active)
5787 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005788
Douglas Gilbert9a051012017-12-23 12:48:10 -05005789 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005790 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005791 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5792 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005794 hpnt->max_id = sdebug_num_tgts;
5795 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005796 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005798 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005799
Douglas Gilbert773642d2016-04-25 12:16:28 -04005800 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005801
Christoph Hellwig8475c812016-09-11 19:35:41 +02005802 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005803 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005804 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005805 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005806 break;
5807
Christoph Hellwig8475c812016-09-11 19:35:41 +02005808 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005809 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005810 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005811 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005812 break;
5813
Christoph Hellwig8475c812016-09-11 19:35:41 +02005814 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005815 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005816 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005817 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005818 break;
5819
5820 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005821 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005822 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005823 break;
5824 }
5825
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005826 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005827
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005828 if (have_dif_prot || sdebug_dix)
5829 pr_info("host protection%s%s%s%s%s%s%s\n",
5830 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5831 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5832 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5833 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5834 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5835 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5836 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005837
Douglas Gilbert773642d2016-04-25 12:16:28 -04005838 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005839 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5840 else
5841 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5842
Douglas Gilbert773642d2016-04-25 12:16:28 -04005843 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5844 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005845 if (sdebug_every_nth) /* need stats counters for every_nth */
5846 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005847 error = scsi_add_host(hpnt, &sdbg_host->dev);
5848 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005849 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005850 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005852 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005853 scsi_scan_host(hpnt);
5854
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005855 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856}
5857
5858static int sdebug_driver_remove(struct device * dev)
5859{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005860 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005861 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
5863 sdbg_host = to_sdebug_host(dev);
5864
5865 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005866 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 return -ENODEV;
5868 }
5869
Douglas Gilbert9a051012017-12-23 12:48:10 -05005870 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005872 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5873 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005874 list_del(&sdbg_devinfo->dev_list);
5875 kfree(sdbg_devinfo);
5876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877
Douglas Gilbert9a051012017-12-23 12:48:10 -05005878 scsi_host_put(sdbg_host->shost);
5879 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880}
5881
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005882static int pseudo_lld_bus_match(struct device *dev,
5883 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005885 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005887
5888static struct bus_type pseudo_lld_bus = {
5889 .name = "pseudo",
5890 .match = pseudo_lld_bus_match,
5891 .probe = sdebug_driver_probe,
5892 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005893 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005894};