blob: 7d2ce0cc915a4d1401a51b7f37c291825035d0f3 [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400653static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654static sector_t sdebug_capacity; /* in sectors */
655
656/* old BIOS stuff, kernel may get rid of them but some mode sense pages
657 may still need them */
658static int sdebug_heads; /* heads per disk */
659static int sdebug_cylinders_per; /* cylinders per surface */
660static int sdebug_sectors_per; /* sectors per cylinder */
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662static LIST_HEAD(sdebug_host_list);
663static DEFINE_SPINLOCK(sdebug_host_list_lock);
664
Douglas Gilbertfd321192016-04-25 12:16:33 -0400665static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200666static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400667static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Martin K. Petersen44d92692009-10-15 14:45:27 -0400669static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400670static int num_aborts;
671static int num_dev_resets;
672static int num_target_resets;
673static int num_bus_resets;
674static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500675static int dix_writes;
676static int dix_reads;
677static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Douglas Gilbertc4837392016-05-06 00:40:26 -0400679static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
680static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682static DEFINE_RWLOCK(atomic_rw);
683
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400684static char sdebug_proc_name[] = MY_NAME;
685static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687static struct bus_type pseudo_lld_bus;
688
689static struct device_driver sdebug_driverfs_driver = {
690 .name = sdebug_proc_name,
691 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692};
693
694static const int check_condition_result =
695 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
696
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500697static const int illegal_condition_result =
698 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
699
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400700static const int device_qfull_result =
701 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
702
Douglas Gilbertfd321192016-04-25 12:16:33 -0400703
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400704/* Only do the extra work involved in logical block provisioning if one or
705 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
706 * real reads and writes (i.e. not skipping them for speed).
707 */
708static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400709{
710 return 0 == sdebug_fake_rw &&
711 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
712}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400713
Akinobu Mita14faa942013-09-18 21:27:24 +0900714static void *fake_store(unsigned long long lba)
715{
716 lba = do_div(lba, sdebug_store_sectors);
717
Douglas Gilbert773642d2016-04-25 12:16:28 -0400718 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900719}
720
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200721static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900722{
Arnd Bergmann49413112015-11-20 17:38:28 +0100723 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900724
725 return dif_storep + sector;
726}
727
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900728static void sdebug_max_tgts_luns(void)
729{
730 struct sdebug_host_info *sdbg_host;
731 struct Scsi_Host *hpnt;
732
733 spin_lock(&sdebug_host_list_lock);
734 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
735 hpnt = sdbg_host->shost;
736 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400737 (sdebug_num_tgts > hpnt->this_id))
738 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900739 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400740 hpnt->max_id = sdebug_num_tgts;
741 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300742 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900743 }
744 spin_unlock(&sdebug_host_list_lock);
745}
746
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500747enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
748
749/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400750static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
751 enum sdeb_cmd_data c_d,
752 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500753{
754 unsigned char *sbuff;
755 u8 sks[4];
756 int sl, asc;
757
758 sbuff = scp->sense_buffer;
759 if (!sbuff) {
760 sdev_printk(KERN_ERR, scp->device,
761 "%s: sense_buffer is NULL\n", __func__);
762 return;
763 }
764 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
765 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400766 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500767 memset(sks, 0, sizeof(sks));
768 sks[0] = 0x80;
769 if (c_d)
770 sks[0] |= 0x40;
771 if (in_bit >= 0) {
772 sks[0] |= 0x8;
773 sks[0] |= 0x7 & in_bit;
774 }
775 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400776 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500777 sl = sbuff[7] + 8;
778 sbuff[7] = sl;
779 sbuff[sl] = 0x2;
780 sbuff[sl + 1] = 0x6;
781 memcpy(sbuff + sl + 4, sks, 3);
782 } else
783 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400784 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500785 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
786 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
787 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
788}
789
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400790static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900791{
792 unsigned char *sbuff;
793
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400794 sbuff = scp->sense_buffer;
795 if (!sbuff) {
796 sdev_printk(KERN_ERR, scp->device,
797 "%s: sense_buffer is NULL\n", __func__);
798 return;
799 }
800 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900801
Douglas Gilbert773642d2016-04-25 12:16:28 -0400802 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900803
Douglas Gilbert773642d2016-04-25 12:16:28 -0400804 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400805 sdev_printk(KERN_INFO, scp->device,
806 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
807 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900808}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Douglas Gilbertfd321192016-04-25 12:16:33 -0400810static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500811{
812 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
813}
814
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
816{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400817 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400818 if (0x1261 == cmd)
819 sdev_printk(KERN_INFO, dev,
820 "%s: BLKFLSBUF [0x1261]\n", __func__);
821 else if (0x5331 == cmd)
822 sdev_printk(KERN_INFO, dev,
823 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
824 __func__);
825 else
826 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
827 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
829 return -EINVAL;
830 /* return -ENOTTY; // correct return but upsets fdisk */
831}
832
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500833static void config_cdb_len(struct scsi_device *sdev)
834{
835 switch (sdebug_cdb_len) {
836 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
837 sdev->use_10_for_rw = false;
838 sdev->use_16_for_rw = false;
839 sdev->use_10_for_ms = false;
840 break;
841 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
842 sdev->use_10_for_rw = true;
843 sdev->use_16_for_rw = false;
844 sdev->use_10_for_ms = false;
845 break;
846 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
847 sdev->use_10_for_rw = true;
848 sdev->use_16_for_rw = false;
849 sdev->use_10_for_ms = true;
850 break;
851 case 16:
852 sdev->use_10_for_rw = false;
853 sdev->use_16_for_rw = true;
854 sdev->use_10_for_ms = true;
855 break;
856 case 32: /* No knobs to suggest this so same as 16 for now */
857 sdev->use_10_for_rw = false;
858 sdev->use_16_for_rw = true;
859 sdev->use_10_for_ms = true;
860 break;
861 default:
862 pr_warn("unexpected cdb_len=%d, force to 10\n",
863 sdebug_cdb_len);
864 sdev->use_10_for_rw = true;
865 sdev->use_16_for_rw = false;
866 sdev->use_10_for_ms = false;
867 sdebug_cdb_len = 10;
868 break;
869 }
870}
871
872static void all_config_cdb_len(void)
873{
874 struct sdebug_host_info *sdbg_host;
875 struct Scsi_Host *shost;
876 struct scsi_device *sdev;
877
878 spin_lock(&sdebug_host_list_lock);
879 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
880 shost = sdbg_host->shost;
881 shost_for_each_device(sdev, shost) {
882 config_cdb_len(sdev);
883 }
884 }
885 spin_unlock(&sdebug_host_list_lock);
886}
887
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500888static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
889{
890 struct sdebug_host_info *sdhp;
891 struct sdebug_dev_info *dp;
892
893 spin_lock(&sdebug_host_list_lock);
894 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
895 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
896 if ((devip->sdbg_host == dp->sdbg_host) &&
897 (devip->target == dp->target))
898 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
899 }
900 }
901 spin_unlock(&sdebug_host_list_lock);
902}
903
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400904static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400906 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400907
908 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
909 if (k != SDEBUG_NUM_UAS) {
910 const char *cp = NULL;
911
912 switch (k) {
913 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400914 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
915 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400916 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400917 cp = "power on reset";
918 break;
919 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400920 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
921 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400922 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400923 cp = "bus reset";
924 break;
925 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400926 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
927 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400928 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400929 cp = "mode parameters changed";
930 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500931 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400932 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
933 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400934 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500935 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500936 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500937 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400938 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400939 TARGET_CHANGED_ASC,
940 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400941 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500942 cp = "microcode has been changed";
943 break;
944 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400945 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500946 TARGET_CHANGED_ASC,
947 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400948 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500949 cp = "microcode has been changed without reset";
950 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500951 case SDEBUG_UA_LUNS_CHANGED:
952 /*
953 * SPC-3 behavior is to report a UNIT ATTENTION with
954 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
955 * on the target, until a REPORT LUNS command is
956 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400957 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500958 * values as struct scsi_device->scsi_level.
959 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400960 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500961 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400962 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500963 TARGET_CHANGED_ASC,
964 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400965 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500966 cp = "reported luns data has changed";
967 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400968 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400969 pr_warn("unexpected unit attention code=%d\n", k);
970 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400971 cp = "unknown";
972 break;
973 }
974 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400975 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400976 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400977 "%s reports: Unit attention: %s\n",
978 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return check_condition_result;
980 }
981 return 0;
982}
983
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400984/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900985static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 int arr_len)
987{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900988 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900989 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900991 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900993 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400994 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900995
996 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
997 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700998 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 return 0;
1001}
1002
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001003/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1004 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1005 * calls, not required to write in ascending offset order. Assumes resid
1006 * set to scsi_bufflen() prior to any calls.
1007 */
1008static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1009 int arr_len, unsigned int off_dst)
1010{
1011 int act_len, n;
1012 struct scsi_data_buffer *sdb = scsi_in(scp);
1013 off_t skip = off_dst;
1014
1015 if (sdb->length <= off_dst)
1016 return 0;
1017 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1018 return DID_ERROR << 16;
1019
1020 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1021 arr, arr_len, skip);
1022 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1023 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1024 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1025 sdb->resid = min(sdb->resid, n);
1026 return 0;
1027}
1028
1029/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1030 * 'arr' or -1 if error.
1031 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001032static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1033 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001035 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001037 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001039
1040 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041}
1042
1043
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001044static char sdebug_inq_vendor_id[9] = "Linux ";
1045static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001046static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001047/* Use some locally assigned NAAs for SAS addresses. */
1048static const u64 naa3_comp_a = 0x3222222000000000ULL;
1049static const u64 naa3_comp_b = 0x3333333000000000ULL;
1050static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001052/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001053static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1054 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001055 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001056 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001058 int num, port_a;
1059 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001061 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 /* T10 vendor identifier field format (faked) */
1063 arr[0] = 0x2; /* ASCII */
1064 arr[1] = 0x1;
1065 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001066 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1067 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1069 num = 8 + 16 + dev_id_str_len;
1070 arr[3] = num;
1071 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001072 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001073 if (sdebug_uuid_ctl) {
1074 /* Locally assigned UUID */
1075 arr[num++] = 0x1; /* binary (not necessarily sas) */
1076 arr[num++] = 0xa; /* PIV=0, lu, naa */
1077 arr[num++] = 0x0;
1078 arr[num++] = 0x12;
1079 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1080 arr[num++] = 0x0;
1081 memcpy(arr + num, lu_name, 16);
1082 num += 16;
1083 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001084 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001085 arr[num++] = 0x1; /* binary (not necessarily sas) */
1086 arr[num++] = 0x3; /* PIV=0, lu, naa */
1087 arr[num++] = 0x0;
1088 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001089 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001090 num += 8;
1091 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001092 /* Target relative port number */
1093 arr[num++] = 0x61; /* proto=sas, binary */
1094 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1095 arr[num++] = 0x0; /* reserved */
1096 arr[num++] = 0x4; /* length */
1097 arr[num++] = 0x0; /* reserved */
1098 arr[num++] = 0x0; /* reserved */
1099 arr[num++] = 0x0;
1100 arr[num++] = 0x1; /* relative port A */
1101 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001102 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001103 arr[num++] = 0x61; /* proto=sas, binary */
1104 arr[num++] = 0x93; /* piv=1, target port, naa */
1105 arr[num++] = 0x0;
1106 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001107 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001108 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001109 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001110 arr[num++] = 0x61; /* proto=sas, binary */
1111 arr[num++] = 0x95; /* piv=1, target port group id */
1112 arr[num++] = 0x0;
1113 arr[num++] = 0x4;
1114 arr[num++] = 0;
1115 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001116 put_unaligned_be16(port_group_id, arr + num);
1117 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001118 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001119 arr[num++] = 0x61; /* proto=sas, binary */
1120 arr[num++] = 0xa3; /* piv=1, target device, naa */
1121 arr[num++] = 0x0;
1122 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001123 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001124 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001125 /* SCSI name string: Target device identifier */
1126 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1127 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1128 arr[num++] = 0x0;
1129 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001130 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001131 num += 12;
1132 snprintf(b, sizeof(b), "%08X", target_dev_id);
1133 memcpy(arr + num, b, 8);
1134 num += 8;
1135 memset(arr + num, 0, 4);
1136 num += 4;
1137 return num;
1138}
1139
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001140static unsigned char vpd84_data[] = {
1141/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1142 0x22,0x22,0x22,0x0,0xbb,0x1,
1143 0x22,0x22,0x22,0x0,0xbb,0x2,
1144};
1145
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001146/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001147static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001148{
1149 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1150 return sizeof(vpd84_data);
1151}
1152
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001153/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001154static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001155{
1156 int num = 0;
1157 const char * na1 = "https://www.kernel.org/config";
1158 const char * na2 = "http://www.kernel.org/log";
1159 int plen, olen;
1160
1161 arr[num++] = 0x1; /* lu, storage config */
1162 arr[num++] = 0x0; /* reserved */
1163 arr[num++] = 0x0;
1164 olen = strlen(na1);
1165 plen = olen + 1;
1166 if (plen % 4)
1167 plen = ((plen / 4) + 1) * 4;
1168 arr[num++] = plen; /* length, null termianted, padded */
1169 memcpy(arr + num, na1, olen);
1170 memset(arr + num + olen, 0, plen - olen);
1171 num += plen;
1172
1173 arr[num++] = 0x4; /* lu, logging */
1174 arr[num++] = 0x0; /* reserved */
1175 arr[num++] = 0x0;
1176 olen = strlen(na2);
1177 plen = olen + 1;
1178 if (plen % 4)
1179 plen = ((plen / 4) + 1) * 4;
1180 arr[num++] = plen; /* length, null terminated, padded */
1181 memcpy(arr + num, na2, olen);
1182 memset(arr + num + olen, 0, plen - olen);
1183 num += plen;
1184
1185 return num;
1186}
1187
1188/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001189static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001190{
1191 int num = 0;
1192 int port_a, port_b;
1193
1194 port_a = target_dev_id + 1;
1195 port_b = port_a + 1;
1196 arr[num++] = 0x0; /* reserved */
1197 arr[num++] = 0x0; /* reserved */
1198 arr[num++] = 0x0;
1199 arr[num++] = 0x1; /* relative port 1 (primary) */
1200 memset(arr + num, 0, 6);
1201 num += 6;
1202 arr[num++] = 0x0;
1203 arr[num++] = 12; /* length tp descriptor */
1204 /* naa-5 target port identifier (A) */
1205 arr[num++] = 0x61; /* proto=sas, binary */
1206 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1207 arr[num++] = 0x0; /* reserved */
1208 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001209 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001210 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001211 arr[num++] = 0x0; /* reserved */
1212 arr[num++] = 0x0; /* reserved */
1213 arr[num++] = 0x0;
1214 arr[num++] = 0x2; /* relative port 2 (secondary) */
1215 memset(arr + num, 0, 6);
1216 num += 6;
1217 arr[num++] = 0x0;
1218 arr[num++] = 12; /* length tp descriptor */
1219 /* naa-5 target port identifier (B) */
1220 arr[num++] = 0x61; /* proto=sas, binary */
1221 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1222 arr[num++] = 0x0; /* reserved */
1223 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001224 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001225 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001226
1227 return num;
1228}
1229
1230
1231static unsigned char vpd89_data[] = {
1232/* from 4th byte */ 0,0,0,0,
1233'l','i','n','u','x',' ',' ',' ',
1234'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1235'1','2','3','4',
12360x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12370xec,0,0,0,
12380x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12390,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12400x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12410x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12420x53,0x41,
12430x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12440x20,0x20,
12450x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12460x10,0x80,
12470,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12480x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12490x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12500,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12510x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12520x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12530,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12540,0,0,0,0,0,0,0,0,0,0,0,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,
12570x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12580,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12590xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12600,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
12610,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1273};
1274
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001275/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001276static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001277{
1278 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1279 return sizeof(vpd89_data);
1280}
1281
1282
1283static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001284 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1285 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
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,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001288};
1289
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001290/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001291static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001292{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001293 unsigned int gran;
1294
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001295 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001296
1297 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001298 if (sdebug_opt_xferlen_exp != 0 &&
1299 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1300 gran = 1 << sdebug_opt_xferlen_exp;
1301 else
1302 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001303 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001304
1305 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001306 if (sdebug_store_sectors > 0x400)
1307 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001308
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001309 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001310 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001311
Douglas Gilbert773642d2016-04-25 12:16:28 -04001312 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001313 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001314 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001315
1316 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001317 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001318 }
1319
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001320 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001321 if (sdebug_unmap_alignment) {
1322 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001323 arr[28] |= 0x80; /* UGAVALID */
1324 }
1325
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001326 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001327 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001328
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001329 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001330 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001331
1332 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001333
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001334 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335}
1336
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001337/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001338static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001339{
1340 memset(arr, 0, 0x3c);
1341 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001342 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1343 arr[2] = 0;
1344 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001345
1346 return 0x3c;
1347}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001349/* Logical block provisioning VPD page (SBC-4) */
1350static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001351{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001352 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001353 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001354 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001355 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001356 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001357 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001358 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001359 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001360 if (sdebug_lbprz && scsi_debug_lbp())
1361 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1362 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1363 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1364 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001365 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001366}
1367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001369#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001371static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372{
1373 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001374 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001375 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001376 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001377 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Douglas Gilbert773642d2016-04-25 12:16:28 -04001379 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001380 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1381 if (! arr)
1382 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001383 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001384 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001385 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001386 pq_pdt = TYPE_WLUN; /* present, wlun */
1387 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1388 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001389 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001390 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 arr[0] = pq_pdt;
1392 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001393 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001394 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 return check_condition_result;
1396 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001397 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001398 char lu_id_str[6];
1399 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001401 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1402 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001403 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001404 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001405 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001406 (devip->target * 1000) + devip->lun);
1407 target_dev_id = ((host_no + 1) * 2000) +
1408 (devip->target * 1000) - 3;
1409 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001411 arr[1] = cmd[2]; /*sanity */
1412 n = 4;
1413 arr[n++] = 0x0; /* this page */
1414 arr[n++] = 0x80; /* unit serial number */
1415 arr[n++] = 0x83; /* device identification */
1416 arr[n++] = 0x84; /* software interface ident. */
1417 arr[n++] = 0x85; /* management network addresses */
1418 arr[n++] = 0x86; /* extended inquiry */
1419 arr[n++] = 0x87; /* mode page policy */
1420 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001421 if (is_disk) { /* SBC only */
1422 arr[n++] = 0x89; /* ATA information */
1423 arr[n++] = 0xb0; /* Block limits */
1424 arr[n++] = 0xb1; /* Block characteristics */
1425 arr[n++] = 0xb2; /* Logical Block Prov */
1426 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001427 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001429 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001431 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001433 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001434 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1435 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001436 lu_id_str, len,
1437 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001438 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1439 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001440 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001441 } else if (0x85 == cmd[2]) { /* Management network addresses */
1442 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001443 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001444 } else if (0x86 == cmd[2]) { /* extended inquiry */
1445 arr[1] = cmd[2]; /*sanity */
1446 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001447 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001448 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001449 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001450 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1451 else
1452 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001453 arr[5] = 0x7; /* head of q, ordered + simple q's */
1454 } else if (0x87 == cmd[2]) { /* mode page policy */
1455 arr[1] = cmd[2]; /*sanity */
1456 arr[3] = 0x8; /* number of following entries */
1457 arr[4] = 0x2; /* disconnect-reconnect mp */
1458 arr[6] = 0x80; /* mlus, shared */
1459 arr[8] = 0x18; /* protocol specific lu */
1460 arr[10] = 0x82; /* mlus, per initiator port */
1461 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1462 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001463 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1464 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001465 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001466 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001467 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001468 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001469 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001470 arr[3] = inquiry_vpd_b0(&arr[4]);
1471 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001472 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001473 arr[3] = inquiry_vpd_b1(&arr[4]);
1474 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001475 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001476 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001478 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001479 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 return check_condition_result;
1481 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001482 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001483 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001485 kfree(arr);
1486 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 }
1488 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001489 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1490 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 arr[3] = 2; /* response_data_format==2 */
1492 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001493 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001494 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001495 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001498 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001499 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1500 memcpy(&arr[16], sdebug_inq_product_id, 16);
1501 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001502 /* Use Vendor Specific area to place driver date in ASCII hex */
1503 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001505 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1506 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001507 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001508 if (is_disk) { /* SBC-4 no version claimed */
1509 put_unaligned_be16(0x600, arr + n);
1510 n += 2;
1511 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1512 put_unaligned_be16(0x525, arr + n);
1513 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001515 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001516 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001518 kfree(arr);
1519 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520}
1521
Douglas Gilbertfd321192016-04-25 12:16:33 -04001522static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1523 0, 0, 0x0, 0x0};
1524
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525static int resp_requests(struct scsi_cmnd * scp,
1526 struct sdebug_dev_info * devip)
1527{
1528 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001529 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001530 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001531 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 int len = 18;
1533
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001534 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001535 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001536 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001537 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001538 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001539 arr[0] = 0x72;
1540 arr[1] = 0x0; /* NO_SENSE in sense_key */
1541 arr[2] = THRESHOLD_EXCEEDED;
1542 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001543 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001544 } else {
1545 arr[0] = 0x70;
1546 arr[2] = 0x0; /* NO_SENSE in sense_key */
1547 arr[7] = 0xa; /* 18 byte sense buffer */
1548 arr[12] = THRESHOLD_EXCEEDED;
1549 arr[13] = 0xff; /* TEST set and MRIE==6 */
1550 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001551 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001552 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001553 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001554 ; /* have sense and formats match */
1555 else if (arr[0] <= 0x70) {
1556 if (dsense) {
1557 memset(arr, 0, 8);
1558 arr[0] = 0x72;
1559 len = 8;
1560 } else {
1561 memset(arr, 0, 18);
1562 arr[0] = 0x70;
1563 arr[7] = 0xa;
1564 }
1565 } else if (dsense) {
1566 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001567 arr[0] = 0x72;
1568 arr[1] = sbuff[2]; /* sense key */
1569 arr[2] = sbuff[12]; /* asc */
1570 arr[3] = sbuff[13]; /* ascq */
1571 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001572 } else {
1573 memset(arr, 0, 18);
1574 arr[0] = 0x70;
1575 arr[2] = sbuff[1];
1576 arr[7] = 0xa;
1577 arr[12] = sbuff[1];
1578 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001579 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001580
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001581 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001582 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 return fill_from_dev_buffer(scp, arr, len);
1584}
1585
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001586static int resp_start_stop(struct scsi_cmnd * scp,
1587 struct sdebug_dev_info * devip)
1588{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001589 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001590 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001591
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001592 power_cond = (cmd[4] & 0xf0) >> 4;
1593 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001594 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001595 return check_condition_result;
1596 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001597 stop = !(cmd[4] & 1);
1598 atomic_xchg(&devip->stopped, stop);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001599 return 0;
1600}
1601
FUJITA Tomonori28898872008-03-30 00:59:55 +09001602static sector_t get_sdebug_capacity(void)
1603{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001604 static const unsigned int gibibyte = 1073741824;
1605
1606 if (sdebug_virtual_gb > 0)
1607 return (sector_t)sdebug_virtual_gb *
1608 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001609 else
1610 return sdebug_store_sectors;
1611}
1612
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613#define SDEBUG_READCAP_ARR_SZ 8
1614static int resp_readcap(struct scsi_cmnd * scp,
1615 struct sdebug_dev_info * devip)
1616{
1617 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001618 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001620 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001621 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001623 if (sdebug_capacity < 0xffffffff) {
1624 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001625 put_unaligned_be32(capac, arr + 0);
1626 } else
1627 put_unaligned_be32(0xffffffff, arr + 0);
1628 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1630}
1631
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001632#define SDEBUG_READCAP16_ARR_SZ 32
1633static int resp_readcap16(struct scsi_cmnd * scp,
1634 struct sdebug_dev_info * devip)
1635{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001636 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001637 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001638 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001639
Douglas Gilbert773642d2016-04-25 12:16:28 -04001640 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001641 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001642 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001643 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001644 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1645 put_unaligned_be32(sdebug_sector_size, arr + 8);
1646 arr[13] = sdebug_physblk_exp & 0xf;
1647 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001648
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001649 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001650 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001651 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1652 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1653 * in the wider field maps to 0 in this field.
1654 */
1655 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1656 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001657 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001658
Douglas Gilbert773642d2016-04-25 12:16:28 -04001659 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001660
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001661 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001662 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001663 arr[12] |= 1; /* PROT_EN */
1664 }
1665
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001666 return fill_from_dev_buffer(scp, arr,
1667 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1668}
1669
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001670#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1671
1672static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1673 struct sdebug_dev_info * devip)
1674{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001675 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001676 unsigned char * arr;
1677 int host_no = devip->sdbg_host->shost->host_no;
1678 int n, ret, alen, rlen;
1679 int port_group_a, port_group_b, port_a, port_b;
1680
Douglas Gilbert773642d2016-04-25 12:16:28 -04001681 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001682 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1683 if (! arr)
1684 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001685 /*
1686 * EVPD page 0x88 states we have two ports, one
1687 * real and a fake port with no device connected.
1688 * So we create two port groups with one port each
1689 * and set the group with port B to unavailable.
1690 */
1691 port_a = 0x1; /* relative port A */
1692 port_b = 0x2; /* relative port B */
1693 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001694 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001695 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001696 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001697
1698 /*
1699 * The asymmetric access state is cycled according to the host_id.
1700 */
1701 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001702 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001703 arr[n++] = host_no % 3; /* Asymm access state */
1704 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001705 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001706 arr[n++] = 0x0; /* Active/Optimized path */
1707 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001708 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001709 put_unaligned_be16(port_group_a, arr + n);
1710 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001711 arr[n++] = 0; /* Reserved */
1712 arr[n++] = 0; /* Status code */
1713 arr[n++] = 0; /* Vendor unique */
1714 arr[n++] = 0x1; /* One port per group */
1715 arr[n++] = 0; /* Reserved */
1716 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001717 put_unaligned_be16(port_a, arr + n);
1718 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001719 arr[n++] = 3; /* Port unavailable */
1720 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001721 put_unaligned_be16(port_group_b, arr + n);
1722 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001723 arr[n++] = 0; /* Reserved */
1724 arr[n++] = 0; /* Status code */
1725 arr[n++] = 0; /* Vendor unique */
1726 arr[n++] = 0x1; /* One port per group */
1727 arr[n++] = 0; /* Reserved */
1728 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001729 put_unaligned_be16(port_b, arr + n);
1730 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001731
1732 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001733 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001734
1735 /*
1736 * Return the smallest value of either
1737 * - The allocated length
1738 * - The constructed command length
1739 * - The maximum array size
1740 */
1741 rlen = min(alen,n);
1742 ret = fill_from_dev_buffer(scp, arr,
1743 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1744 kfree(arr);
1745 return ret;
1746}
1747
Douglas Gilbertfd321192016-04-25 12:16:33 -04001748static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1749 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001750{
1751 bool rctd;
1752 u8 reporting_opts, req_opcode, sdeb_i, supp;
1753 u16 req_sa, u;
1754 u32 alloc_len, a_len;
1755 int k, offset, len, errsts, count, bump, na;
1756 const struct opcode_info_t *oip;
1757 const struct opcode_info_t *r_oip;
1758 u8 *arr;
1759 u8 *cmd = scp->cmnd;
1760
1761 rctd = !!(cmd[2] & 0x80);
1762 reporting_opts = cmd[2] & 0x7;
1763 req_opcode = cmd[3];
1764 req_sa = get_unaligned_be16(cmd + 4);
1765 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001766 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001767 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1768 return check_condition_result;
1769 }
1770 if (alloc_len > 8192)
1771 a_len = 8192;
1772 else
1773 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001774 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001775 if (NULL == arr) {
1776 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1777 INSUFF_RES_ASCQ);
1778 return check_condition_result;
1779 }
1780 switch (reporting_opts) {
1781 case 0: /* all commands */
1782 /* count number of commands */
1783 for (count = 0, oip = opcode_info_arr;
1784 oip->num_attached != 0xff; ++oip) {
1785 if (F_INV_OP & oip->flags)
1786 continue;
1787 count += (oip->num_attached + 1);
1788 }
1789 bump = rctd ? 20 : 8;
1790 put_unaligned_be32(count * bump, arr);
1791 for (offset = 4, oip = opcode_info_arr;
1792 oip->num_attached != 0xff && offset < a_len; ++oip) {
1793 if (F_INV_OP & oip->flags)
1794 continue;
1795 na = oip->num_attached;
1796 arr[offset] = oip->opcode;
1797 put_unaligned_be16(oip->sa, arr + offset + 2);
1798 if (rctd)
1799 arr[offset + 5] |= 0x2;
1800 if (FF_SA & oip->flags)
1801 arr[offset + 5] |= 0x1;
1802 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1803 if (rctd)
1804 put_unaligned_be16(0xa, arr + offset + 8);
1805 r_oip = oip;
1806 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1807 if (F_INV_OP & oip->flags)
1808 continue;
1809 offset += bump;
1810 arr[offset] = oip->opcode;
1811 put_unaligned_be16(oip->sa, arr + offset + 2);
1812 if (rctd)
1813 arr[offset + 5] |= 0x2;
1814 if (FF_SA & oip->flags)
1815 arr[offset + 5] |= 0x1;
1816 put_unaligned_be16(oip->len_mask[0],
1817 arr + offset + 6);
1818 if (rctd)
1819 put_unaligned_be16(0xa,
1820 arr + offset + 8);
1821 }
1822 oip = r_oip;
1823 offset += bump;
1824 }
1825 break;
1826 case 1: /* one command: opcode only */
1827 case 2: /* one command: opcode plus service action */
1828 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1829 sdeb_i = opcode_ind_arr[req_opcode];
1830 oip = &opcode_info_arr[sdeb_i];
1831 if (F_INV_OP & oip->flags) {
1832 supp = 1;
1833 offset = 4;
1834 } else {
1835 if (1 == reporting_opts) {
1836 if (FF_SA & oip->flags) {
1837 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1838 2, 2);
1839 kfree(arr);
1840 return check_condition_result;
1841 }
1842 req_sa = 0;
1843 } else if (2 == reporting_opts &&
1844 0 == (FF_SA & oip->flags)) {
1845 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1846 kfree(arr); /* point at requested sa */
1847 return check_condition_result;
1848 }
1849 if (0 == (FF_SA & oip->flags) &&
1850 req_opcode == oip->opcode)
1851 supp = 3;
1852 else if (0 == (FF_SA & oip->flags)) {
1853 na = oip->num_attached;
1854 for (k = 0, oip = oip->arrp; k < na;
1855 ++k, ++oip) {
1856 if (req_opcode == oip->opcode)
1857 break;
1858 }
1859 supp = (k >= na) ? 1 : 3;
1860 } else if (req_sa != oip->sa) {
1861 na = oip->num_attached;
1862 for (k = 0, oip = oip->arrp; k < na;
1863 ++k, ++oip) {
1864 if (req_sa == oip->sa)
1865 break;
1866 }
1867 supp = (k >= na) ? 1 : 3;
1868 } else
1869 supp = 3;
1870 if (3 == supp) {
1871 u = oip->len_mask[0];
1872 put_unaligned_be16(u, arr + 2);
1873 arr[4] = oip->opcode;
1874 for (k = 1; k < u; ++k)
1875 arr[4 + k] = (k < 16) ?
1876 oip->len_mask[k] : 0xff;
1877 offset = 4 + u;
1878 } else
1879 offset = 4;
1880 }
1881 arr[1] = (rctd ? 0x80 : 0) | supp;
1882 if (rctd) {
1883 put_unaligned_be16(0xa, arr + offset);
1884 offset += 12;
1885 }
1886 break;
1887 default:
1888 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1889 kfree(arr);
1890 return check_condition_result;
1891 }
1892 offset = (offset < a_len) ? offset : a_len;
1893 len = (offset < alloc_len) ? offset : alloc_len;
1894 errsts = fill_from_dev_buffer(scp, arr, len);
1895 kfree(arr);
1896 return errsts;
1897}
1898
Douglas Gilbertfd321192016-04-25 12:16:33 -04001899static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1900 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001901{
1902 bool repd;
1903 u32 alloc_len, len;
1904 u8 arr[16];
1905 u8 *cmd = scp->cmnd;
1906
1907 memset(arr, 0, sizeof(arr));
1908 repd = !!(cmd[2] & 0x80);
1909 alloc_len = get_unaligned_be32(cmd + 6);
1910 if (alloc_len < 4) {
1911 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1912 return check_condition_result;
1913 }
1914 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1915 arr[1] = 0x1; /* ITNRS */
1916 if (repd) {
1917 arr[3] = 0xc;
1918 len = 16;
1919 } else
1920 len = 4;
1921
1922 len = (len < alloc_len) ? len : alloc_len;
1923 return fill_from_dev_buffer(scp, arr, len);
1924}
1925
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926/* <<Following mode page info copied from ST318451LW>> */
1927
1928static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1929{ /* Read-Write Error Recovery page for mode_sense */
1930 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1931 5, 0, 0xff, 0xff};
1932
1933 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1934 if (1 == pcontrol)
1935 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1936 return sizeof(err_recov_pg);
1937}
1938
1939static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1940{ /* Disconnect-Reconnect page for mode_sense */
1941 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1942 0, 0, 0, 0, 0, 0, 0, 0};
1943
1944 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1945 if (1 == pcontrol)
1946 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1947 return sizeof(disconnect_pg);
1948}
1949
1950static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1951{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001952 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1953 0, 0, 0, 0, 0, 0, 0, 0,
1954 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
Martin K. Petersen597136a2008-06-05 00:12:59 -04001956 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001957 put_unaligned_be16(sdebug_sectors_per, p + 10);
1958 put_unaligned_be16(sdebug_sector_size, p + 12);
1959 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001960 p[20] |= 0x20; /* should agree with INQUIRY */
1961 if (1 == pcontrol)
1962 memset(p + 2, 0, sizeof(format_pg) - 2);
1963 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964}
1965
Douglas Gilbertfd321192016-04-25 12:16:33 -04001966static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1967 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1968 0, 0, 0, 0};
1969
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1971{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001972 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1973 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1974 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1976
Douglas Gilbert773642d2016-04-25 12:16:28 -04001977 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001978 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 memcpy(p, caching_pg, sizeof(caching_pg));
1980 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001981 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1982 else if (2 == pcontrol)
1983 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 return sizeof(caching_pg);
1985}
1986
Douglas Gilbertfd321192016-04-25 12:16:33 -04001987static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1988 0, 0, 0x2, 0x4b};
1989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1991{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001992 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05001993 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001994 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 0, 0, 0x2, 0x4b};
1996
Douglas Gilbert773642d2016-04-25 12:16:28 -04001997 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001999 else
2000 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002001
Douglas Gilbert773642d2016-04-25 12:16:28 -04002002 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002003 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2006 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002007 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2008 else if (2 == pcontrol)
2009 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 return sizeof(ctrl_m_pg);
2011}
2012
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002013
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
2015{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002016 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2017 0, 0, 0x0, 0x0};
2018 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2019 0, 0, 0x0, 0x0};
2020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2022 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002023 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2024 else if (2 == pcontrol)
2025 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 return sizeof(iec_m_pg);
2027}
2028
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002029static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
2030{ /* SAS SSP mode page - short format for mode_sense */
2031 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2032 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2033
2034 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2035 if (1 == pcontrol)
2036 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2037 return sizeof(sas_sf_m_pg);
2038}
2039
2040
2041static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
2042 int target_dev_id)
2043{ /* SAS phy control and discover mode page for mode_sense */
2044 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2045 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002046 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2047 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002048 0x2, 0, 0, 0, 0, 0, 0, 0,
2049 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2050 0, 0, 0, 0, 0, 0, 0, 0,
2051 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002052 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2053 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002054 0x3, 0, 0, 0, 0, 0, 0, 0,
2055 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2056 0, 0, 0, 0, 0, 0, 0, 0,
2057 };
2058 int port_a, port_b;
2059
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002060 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2061 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2062 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2063 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002064 port_a = target_dev_id + 1;
2065 port_b = port_a + 1;
2066 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002067 put_unaligned_be32(port_a, p + 20);
2068 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002069 if (1 == pcontrol)
2070 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2071 return sizeof(sas_pcd_m_pg);
2072}
2073
2074static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
2075{ /* SAS SSP shared protocol specific port mode subpage */
2076 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2077 0, 0, 0, 0, 0, 0, 0, 0,
2078 };
2079
2080 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2081 if (1 == pcontrol)
2082 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2083 return sizeof(sas_sha_m_pg);
2084}
2085
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086#define SDEBUG_MAX_MSENSE_SZ 256
2087
Douglas Gilbertfd321192016-04-25 12:16:33 -04002088static int resp_mode_sense(struct scsi_cmnd *scp,
2089 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090{
Douglas Gilbert23183912006-09-16 20:30:47 -04002091 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002093 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002094 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 unsigned char * ap;
2096 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002097 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002098 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002100 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 pcontrol = (cmd[2] & 0xc0) >> 6;
2102 pcode = cmd[2] & 0x3f;
2103 subpcode = cmd[3];
2104 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002105 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2106 is_disk = (sdebug_ptype == TYPE_DISK);
2107 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002108 bd_len = llbaa ? 16 : 8;
2109 else
2110 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002111 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2113 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002114 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 return check_condition_result;
2116 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002117 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2118 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002119 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002120 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002121 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002122 else
2123 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 if (msense_6) {
2125 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002126 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 offset = 4;
2128 } else {
2129 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002130 if (16 == bd_len)
2131 arr[4] = 0x1; /* set LONGLBA bit */
2132 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 offset = 8;
2134 }
2135 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002136 if ((bd_len > 0) && (!sdebug_capacity))
2137 sdebug_capacity = get_sdebug_capacity();
2138
Douglas Gilbert23183912006-09-16 20:30:47 -04002139 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002140 if (sdebug_capacity > 0xfffffffe)
2141 put_unaligned_be32(0xffffffff, ap + 0);
2142 else
2143 put_unaligned_be32(sdebug_capacity, ap + 0);
2144 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002145 offset += bd_len;
2146 ap = arr + offset;
2147 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002148 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2149 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002150 offset += bd_len;
2151 ap = arr + offset;
2152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002154 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2155 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002156 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 return check_condition_result;
2158 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002159 bad_pcode = false;
2160
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 switch (pcode) {
2162 case 0x1: /* Read-Write error recovery page, direct access */
2163 len = resp_err_recov_pg(ap, pcontrol, target);
2164 offset += len;
2165 break;
2166 case 0x2: /* Disconnect-Reconnect page, all devices */
2167 len = resp_disconnect_pg(ap, pcontrol, target);
2168 offset += len;
2169 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002170 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002171 if (is_disk) {
2172 len = resp_format_pg(ap, pcontrol, target);
2173 offset += len;
2174 } else
2175 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002176 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002178 if (is_disk) {
2179 len = resp_caching_pg(ap, pcontrol, target);
2180 offset += len;
2181 } else
2182 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 break;
2184 case 0xa: /* Control Mode page, all devices */
2185 len = resp_ctrl_m_pg(ap, pcontrol, target);
2186 offset += len;
2187 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002188 case 0x19: /* if spc==1 then sas phy, control+discover */
2189 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002190 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002191 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002192 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002193 len = 0;
2194 if ((0x0 == subpcode) || (0xff == subpcode))
2195 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2196 if ((0x1 == subpcode) || (0xff == subpcode))
2197 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2198 target_dev_id);
2199 if ((0x2 == subpcode) || (0xff == subpcode))
2200 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2201 offset += len;
2202 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 case 0x1c: /* Informational Exceptions Mode page, all devices */
2204 len = resp_iec_m_pg(ap, pcontrol, target);
2205 offset += len;
2206 break;
2207 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002208 if ((0 == subpcode) || (0xff == subpcode)) {
2209 len = resp_err_recov_pg(ap, pcontrol, target);
2210 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002211 if (is_disk) {
2212 len += resp_format_pg(ap + len, pcontrol,
2213 target);
2214 len += resp_caching_pg(ap + len, pcontrol,
2215 target);
2216 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002217 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2218 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2219 if (0xff == subpcode) {
2220 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2221 target, target_dev_id);
2222 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2223 }
2224 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002225 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002226 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002227 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002228 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 break;
2231 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002232 bad_pcode = true;
2233 break;
2234 }
2235 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002236 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 return check_condition_result;
2238 }
2239 if (msense_6)
2240 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002241 else
2242 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2244}
2245
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002246#define SDEBUG_MAX_MSELECT_SZ 512
2247
Douglas Gilbertfd321192016-04-25 12:16:33 -04002248static int resp_mode_select(struct scsi_cmnd *scp,
2249 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002250{
2251 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002252 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002253 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002254 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002255 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002256
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002257 memset(arr, 0, sizeof(arr));
2258 pf = cmd[1] & 0x10;
2259 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002260 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002261 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002262 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002263 return check_condition_result;
2264 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002265 res = fetch_to_dev_buffer(scp, arr, param_len);
2266 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002267 return DID_ERROR << 16;
2268 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002269 sdev_printk(KERN_INFO, scp->device,
2270 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2271 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002272 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2273 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002274 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002275 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002276 return check_condition_result;
2277 }
2278 off = bd_len + (mselect6 ? 4 : 8);
2279 mpage = arr[off] & 0x3f;
2280 ps = !!(arr[off] & 0x80);
2281 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002282 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002283 return check_condition_result;
2284 }
2285 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002286 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002287 (arr[off + 1] + 2);
2288 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002289 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002290 PARAMETER_LIST_LENGTH_ERR, 0);
2291 return check_condition_result;
2292 }
2293 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002294 case 0x8: /* Caching Mode page */
2295 if (caching_pg[1] == arr[off + 1]) {
2296 memcpy(caching_pg + 2, arr + off + 2,
2297 sizeof(caching_pg) - 2);
2298 goto set_mode_changed_ua;
2299 }
2300 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002301 case 0xa: /* Control Mode page */
2302 if (ctrl_m_pg[1] == arr[off + 1]) {
2303 memcpy(ctrl_m_pg + 2, arr + off + 2,
2304 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002305 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002306 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002307 }
2308 break;
2309 case 0x1c: /* Informational Exceptions Mode page */
2310 if (iec_m_pg[1] == arr[off + 1]) {
2311 memcpy(iec_m_pg + 2, arr + off + 2,
2312 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002313 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002314 }
2315 break;
2316 default:
2317 break;
2318 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002319 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002320 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002321set_mode_changed_ua:
2322 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2323 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002324}
2325
2326static int resp_temp_l_pg(unsigned char * arr)
2327{
2328 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2329 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2330 };
2331
Douglas Gilbert9a051012017-12-23 12:48:10 -05002332 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2333 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002334}
2335
2336static int resp_ie_l_pg(unsigned char * arr)
2337{
2338 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2339 };
2340
Douglas Gilbert9a051012017-12-23 12:48:10 -05002341 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002342 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2343 arr[4] = THRESHOLD_EXCEEDED;
2344 arr[5] = 0xff;
2345 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002346 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002347}
2348
2349#define SDEBUG_MAX_LSENSE_SZ 512
2350
Douglas Gilbert9a051012017-12-23 12:48:10 -05002351static int resp_log_sense(struct scsi_cmnd *scp,
2352 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002353{
Bart Van Asscheab172412017-08-25 13:46:42 -07002354 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002355 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002356 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002357
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002358 memset(arr, 0, sizeof(arr));
2359 ppc = cmd[1] & 0x2;
2360 sp = cmd[1] & 0x1;
2361 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002362 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002363 return check_condition_result;
2364 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002365 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002366 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002367 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002368 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002369 if (0 == subpcode) {
2370 switch (pcode) {
2371 case 0x0: /* Supported log pages log page */
2372 n = 4;
2373 arr[n++] = 0x0; /* this page */
2374 arr[n++] = 0xd; /* Temperature */
2375 arr[n++] = 0x2f; /* Informational exceptions */
2376 arr[3] = n - 4;
2377 break;
2378 case 0xd: /* Temperature log page */
2379 arr[3] = resp_temp_l_pg(arr + 4);
2380 break;
2381 case 0x2f: /* Informational exceptions log page */
2382 arr[3] = resp_ie_l_pg(arr + 4);
2383 break;
2384 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002385 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002386 return check_condition_result;
2387 }
2388 } else if (0xff == subpcode) {
2389 arr[0] |= 0x40;
2390 arr[1] = subpcode;
2391 switch (pcode) {
2392 case 0x0: /* Supported log pages and subpages log page */
2393 n = 4;
2394 arr[n++] = 0x0;
2395 arr[n++] = 0x0; /* 0,0 page */
2396 arr[n++] = 0x0;
2397 arr[n++] = 0xff; /* this page */
2398 arr[n++] = 0xd;
2399 arr[n++] = 0x0; /* Temperature */
2400 arr[n++] = 0x2f;
2401 arr[n++] = 0x0; /* Informational exceptions */
2402 arr[3] = n - 4;
2403 break;
2404 case 0xd: /* Temperature subpages */
2405 n = 4;
2406 arr[n++] = 0xd;
2407 arr[n++] = 0x0; /* Temperature */
2408 arr[3] = n - 4;
2409 break;
2410 case 0x2f: /* Informational exceptions subpages */
2411 n = 4;
2412 arr[n++] = 0x2f;
2413 arr[n++] = 0x0; /* Informational exceptions */
2414 arr[3] = n - 4;
2415 break;
2416 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002417 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002418 return check_condition_result;
2419 }
2420 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002421 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002422 return check_condition_result;
2423 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002424 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002425 return fill_from_dev_buffer(scp, arr,
2426 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2427}
2428
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002429static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002430 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002432 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002433 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 return check_condition_result;
2435 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002436 /* transfer length excessive (tie in to block limits VPD page) */
2437 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002438 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002439 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002440 return check_condition_result;
2441 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002442 return 0;
2443}
2444
Akinobu Mitaa4517512013-07-08 16:01:57 -07002445/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002446static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2447 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002448{
2449 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002450 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002451 struct scsi_data_buffer *sdb;
2452 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002453
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002454 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002455 sdb = scsi_out(scmd);
2456 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002457 } else {
2458 sdb = scsi_in(scmd);
2459 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002460 }
2461
2462 if (!sdb->length)
2463 return 0;
2464 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2465 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002466
2467 block = do_div(lba, sdebug_store_sectors);
2468 if (block + num > sdebug_store_sectors)
2469 rest = block + num - sdebug_store_sectors;
2470
Dave Gordon386ecb12015-06-30 14:58:57 -07002471 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002472 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002473 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002474 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002475 return ret;
2476
2477 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002478 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002479 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002480 sg_skip + ((num - rest) * sdebug_sector_size),
2481 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002482 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002483
2484 return ret;
2485}
2486
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002487/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2488 * arr into fake_store(lba,num) and return true. If comparison fails then
2489 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002490static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002491{
2492 bool res;
2493 u64 block, rest = 0;
2494 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002495 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002496
2497 block = do_div(lba, store_blks);
2498 if (block + num > store_blks)
2499 rest = block + num - store_blks;
2500
2501 res = !memcmp(fake_storep + (block * lb_size), arr,
2502 (num - rest) * lb_size);
2503 if (!res)
2504 return res;
2505 if (rest)
2506 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2507 rest * lb_size);
2508 if (!res)
2509 return res;
2510 arr += num * lb_size;
2511 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2512 if (rest)
2513 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2514 rest * lb_size);
2515 return res;
2516}
2517
Akinobu Mita51d648a2013-09-18 21:27:28 +09002518static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002519{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002520 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002521
Douglas Gilbert773642d2016-04-25 12:16:28 -04002522 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002523 csum = (__force __be16)ip_compute_csum(buf, len);
2524 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002525 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002526
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002527 return csum;
2528}
2529
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002530static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002531 sector_t sector, u32 ei_lba)
2532{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002533 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002534
2535 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002536 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002537 (unsigned long)sector,
2538 be16_to_cpu(sdt->guard_tag),
2539 be16_to_cpu(csum));
2540 return 0x01;
2541 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002542 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002543 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002544 pr_err("REF check failed on sector %lu\n",
2545 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002546 return 0x03;
2547 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002548 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002549 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002550 pr_err("REF check failed on sector %lu\n",
2551 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002552 return 0x03;
2553 }
2554 return 0;
2555}
2556
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002557static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002558 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002559{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002560 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002561 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002562 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002563 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002564
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002565 /* Bytes of protection data to copy into sgl */
2566 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002567
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002568 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2569 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2570 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2571
2572 while (sg_miter_next(&miter) && resid > 0) {
2573 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002574 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002575 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002576
2577 if (dif_store_end < start + len)
2578 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002579
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002580 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002581
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002582 if (read)
2583 memcpy(paddr, start, len - rest);
2584 else
2585 memcpy(start, paddr, len - rest);
2586
2587 if (rest) {
2588 if (read)
2589 memcpy(paddr + len - rest, dif_storep, rest);
2590 else
2591 memcpy(dif_storep, paddr + len - rest, rest);
2592 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002593
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002594 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002595 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002596 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002597 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002598}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002599
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002600static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2601 unsigned int sectors, u32 ei_lba)
2602{
2603 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002604 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002605 sector_t sector;
2606
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002607 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002608 int ret;
2609
2610 sector = start_sec + i;
2611 sdt = dif_store(sector);
2612
Akinobu Mita51d648a2013-09-18 21:27:28 +09002613 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002614 continue;
2615
2616 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2617 if (ret) {
2618 dif_errors++;
2619 return ret;
2620 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002621 }
2622
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002623 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002624 dix_reads++;
2625
2626 return 0;
2627}
2628
Douglas Gilbertfd321192016-04-25 12:16:33 -04002629static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002630{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002631 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002632 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002633 u64 lba;
2634 u32 num;
2635 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002636 unsigned long iflags;
2637 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002638 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002639
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002640 switch (cmd[0]) {
2641 case READ_16:
2642 ei_lba = 0;
2643 lba = get_unaligned_be64(cmd + 2);
2644 num = get_unaligned_be32(cmd + 10);
2645 check_prot = true;
2646 break;
2647 case READ_10:
2648 ei_lba = 0;
2649 lba = get_unaligned_be32(cmd + 2);
2650 num = get_unaligned_be16(cmd + 7);
2651 check_prot = true;
2652 break;
2653 case READ_6:
2654 ei_lba = 0;
2655 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2656 (u32)(cmd[1] & 0x1f) << 16;
2657 num = (0 == cmd[4]) ? 256 : cmd[4];
2658 check_prot = true;
2659 break;
2660 case READ_12:
2661 ei_lba = 0;
2662 lba = get_unaligned_be32(cmd + 2);
2663 num = get_unaligned_be32(cmd + 6);
2664 check_prot = true;
2665 break;
2666 case XDWRITEREAD_10:
2667 ei_lba = 0;
2668 lba = get_unaligned_be32(cmd + 2);
2669 num = get_unaligned_be16(cmd + 7);
2670 check_prot = false;
2671 break;
2672 default: /* assume READ(32) */
2673 lba = get_unaligned_be64(cmd + 12);
2674 ei_lba = get_unaligned_be32(cmd + 20);
2675 num = get_unaligned_be32(cmd + 28);
2676 check_prot = false;
2677 break;
2678 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002679 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002680 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002681 (cmd[1] & 0xe0)) {
2682 mk_sense_invalid_opcode(scp);
2683 return check_condition_result;
2684 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002685 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2686 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002687 (cmd[1] & 0xe0) == 0)
2688 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2689 "to DIF device\n");
2690 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002691 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002692 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002693
Douglas Gilbertc4837392016-05-06 00:40:26 -04002694 if (sqcp) {
2695 if (sqcp->inj_short)
2696 num /= 2;
2697 }
2698 } else
2699 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002700
2701 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002702 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002703 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2704 return check_condition_result;
2705 }
2706 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002707 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002708 /* needs work to find which cdb byte 'num' comes from */
2709 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2710 return check_condition_result;
2711 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002712
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002713 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2714 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2715 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002716 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002717 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002718 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002719 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2720 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002721 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2722 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002723 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002724 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002725 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 return check_condition_result;
2727 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002728
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002729 read_lock_irqsave(&atomic_rw, iflags);
2730
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002731 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002732 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002733 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002734
2735 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002736 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002737 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002738 return illegal_condition_result;
2739 }
2740 }
2741
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002742 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002744 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002745 return DID_ERROR << 16;
2746
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002747 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002748
Douglas Gilbertc4837392016-05-06 00:40:26 -04002749 if (unlikely(sqcp)) {
2750 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002751 mk_sense_buffer(scp, RECOVERED_ERROR,
2752 THRESHOLD_EXCEEDED, 0);
2753 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002754 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002755 mk_sense_buffer(scp, ABORTED_COMMAND,
2756 TRANSPORT_PROBLEM, ACK_NAK_TO);
2757 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002758 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002759 /* Logical block guard check failed */
2760 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2761 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002762 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002763 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2764 return illegal_condition_result;
2765 }
2766 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002767 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768}
2769
Tomas Winkler58a86352015-07-28 16:54:23 +03002770static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002771{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002772 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002773
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002774 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002775 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002776 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002777
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002778 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002779 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002780
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002781 if (c >= 0x20 && c < 0x7e)
2782 n += scnprintf(b + n, sizeof(b) - n,
2783 " %c ", buf[i+j]);
2784 else
2785 n += scnprintf(b + n, sizeof(b) - n,
2786 "%02x ", buf[i+j]);
2787 }
2788 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002789 }
2790}
2791
2792static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002793 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002794{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002795 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002796 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002797 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002798 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002799 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002800 int dpage_offset;
2801 struct sg_mapping_iter diter;
2802 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002803
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002804 BUG_ON(scsi_sg_count(SCpnt) == 0);
2805 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2806
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002807 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2808 scsi_prot_sg_count(SCpnt),
2809 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2810 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2811 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002812
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002813 /* For each protection page */
2814 while (sg_miter_next(&piter)) {
2815 dpage_offset = 0;
2816 if (WARN_ON(!sg_miter_next(&diter))) {
2817 ret = 0x01;
2818 goto out;
2819 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002820
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002821 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002822 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002823 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002824 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002825 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002826 if (dpage_offset >= diter.length) {
2827 if (WARN_ON(!sg_miter_next(&diter))) {
2828 ret = 0x01;
2829 goto out;
2830 }
2831 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002832 }
2833
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002834 sdt = piter.addr + ppage_offset;
2835 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002836
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002837 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002838 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002839 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002840 goto out;
2841 }
2842
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002843 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002844 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002845 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002846 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002847 diter.consumed = dpage_offset;
2848 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002849 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002850 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002851
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002852 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002853 dix_writes++;
2854
2855 return 0;
2856
2857out:
2858 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002859 sg_miter_stop(&diter);
2860 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002861 return ret;
2862}
2863
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002864static unsigned long lba_to_map_index(sector_t lba)
2865{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002866 if (sdebug_unmap_alignment)
2867 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2868 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002869 return lba;
2870}
2871
2872static sector_t map_index_to_lba(unsigned long index)
2873{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002874 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002875
Douglas Gilbert773642d2016-04-25 12:16:28 -04002876 if (sdebug_unmap_alignment)
2877 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002878 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002879}
2880
Martin K. Petersen44d92692009-10-15 14:45:27 -04002881static unsigned int map_state(sector_t lba, unsigned int *num)
2882{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002883 sector_t end;
2884 unsigned int mapped;
2885 unsigned long index;
2886 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002887
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002888 index = lba_to_map_index(lba);
2889 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002890
2891 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002892 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002893 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002894 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002895
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002896 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002897 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002898 return mapped;
2899}
2900
2901static void map_region(sector_t lba, unsigned int len)
2902{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002903 sector_t end = lba + len;
2904
Martin K. Petersen44d92692009-10-15 14:45:27 -04002905 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002906 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002907
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002908 if (index < map_size)
2909 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002910
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002911 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002912 }
2913}
2914
2915static void unmap_region(sector_t lba, unsigned int len)
2916{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002917 sector_t end = lba + len;
2918
Martin K. Petersen44d92692009-10-15 14:45:27 -04002919 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002920 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002921
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002922 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002923 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002924 index < map_size) {
2925 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002926 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002927 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002928 lba * sdebug_sector_size,
2929 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002930 sdebug_sector_size *
2931 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002932 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002933 if (dif_storep) {
2934 memset(dif_storep + lba, 0xff,
2935 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002936 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002937 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002938 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002939 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002940 }
2941}
2942
Douglas Gilbertfd321192016-04-25 12:16:33 -04002943static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002945 u8 *cmd = scp->cmnd;
2946 u64 lba;
2947 u32 num;
2948 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002950 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002951 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002953 switch (cmd[0]) {
2954 case WRITE_16:
2955 ei_lba = 0;
2956 lba = get_unaligned_be64(cmd + 2);
2957 num = get_unaligned_be32(cmd + 10);
2958 check_prot = true;
2959 break;
2960 case WRITE_10:
2961 ei_lba = 0;
2962 lba = get_unaligned_be32(cmd + 2);
2963 num = get_unaligned_be16(cmd + 7);
2964 check_prot = true;
2965 break;
2966 case WRITE_6:
2967 ei_lba = 0;
2968 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2969 (u32)(cmd[1] & 0x1f) << 16;
2970 num = (0 == cmd[4]) ? 256 : cmd[4];
2971 check_prot = true;
2972 break;
2973 case WRITE_12:
2974 ei_lba = 0;
2975 lba = get_unaligned_be32(cmd + 2);
2976 num = get_unaligned_be32(cmd + 6);
2977 check_prot = true;
2978 break;
2979 case 0x53: /* XDWRITEREAD(10) */
2980 ei_lba = 0;
2981 lba = get_unaligned_be32(cmd + 2);
2982 num = get_unaligned_be16(cmd + 7);
2983 check_prot = false;
2984 break;
2985 default: /* assume WRITE(32) */
2986 lba = get_unaligned_be64(cmd + 12);
2987 ei_lba = get_unaligned_be32(cmd + 20);
2988 num = get_unaligned_be32(cmd + 28);
2989 check_prot = false;
2990 break;
2991 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002992 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002993 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002994 (cmd[1] & 0xe0)) {
2995 mk_sense_invalid_opcode(scp);
2996 return check_condition_result;
2997 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002998 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2999 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003000 (cmd[1] & 0xe0) == 0)
3001 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3002 "to DIF device\n");
3003 }
3004
3005 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003006 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003007 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3008 return check_condition_result;
3009 }
3010 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003011 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003012 /* needs work to find which cdb byte 'num' comes from */
3013 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3014 return check_condition_result;
3015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003017 write_lock_irqsave(&atomic_rw, iflags);
3018
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003019 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003020 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003021 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003022
3023 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003024 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003025 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003026 return illegal_condition_result;
3027 }
3028 }
3029
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003030 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003031 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003032 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003034 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003035 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003036 else if (unlikely(sdebug_verbose &&
3037 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003038 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003039 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003040 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003041
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003042 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003043 struct sdebug_queued_cmd *sqcp =
3044 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003045
Douglas Gilbertc4837392016-05-06 00:40:26 -04003046 if (sqcp) {
3047 if (sqcp->inj_recovered) {
3048 mk_sense_buffer(scp, RECOVERED_ERROR,
3049 THRESHOLD_EXCEEDED, 0);
3050 return check_condition_result;
3051 } else if (sqcp->inj_dif) {
3052 /* Logical block guard check failed */
3053 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3054 return illegal_condition_result;
3055 } else if (sqcp->inj_dix) {
3056 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3057 return illegal_condition_result;
3058 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003059 }
3060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 return 0;
3062}
3063
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003064/*
3065 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3066 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3067 */
3068static int resp_write_scat(struct scsi_cmnd *scp,
3069 struct sdebug_dev_info *devip)
3070{
3071 u8 *cmd = scp->cmnd;
3072 u8 *lrdp = NULL;
3073 u8 *up;
3074 u8 wrprotect;
3075 u16 lbdof, num_lrd, k;
3076 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3077 u32 lb_size = sdebug_sector_size;
3078 u32 ei_lba;
3079 u64 lba;
3080 unsigned long iflags;
3081 int ret, res;
3082 bool is_16;
3083 static const u32 lrd_size = 32; /* + parameter list header size */
3084
3085 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3086 is_16 = false;
3087 wrprotect = (cmd[10] >> 5) & 0x7;
3088 lbdof = get_unaligned_be16(cmd + 12);
3089 num_lrd = get_unaligned_be16(cmd + 16);
3090 bt_len = get_unaligned_be32(cmd + 28);
3091 } else { /* that leaves WRITE SCATTERED(16) */
3092 is_16 = true;
3093 wrprotect = (cmd[2] >> 5) & 0x7;
3094 lbdof = get_unaligned_be16(cmd + 4);
3095 num_lrd = get_unaligned_be16(cmd + 8);
3096 bt_len = get_unaligned_be32(cmd + 10);
3097 if (unlikely(have_dif_prot)) {
3098 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3099 wrprotect) {
3100 mk_sense_invalid_opcode(scp);
3101 return illegal_condition_result;
3102 }
3103 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3104 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3105 wrprotect == 0)
3106 sdev_printk(KERN_ERR, scp->device,
3107 "Unprotected WR to DIF device\n");
3108 }
3109 }
3110 if ((num_lrd == 0) || (bt_len == 0))
3111 return 0; /* T10 says these do-nothings are not errors */
3112 if (lbdof == 0) {
3113 if (sdebug_verbose)
3114 sdev_printk(KERN_INFO, scp->device,
3115 "%s: %s: LB Data Offset field bad\n",
3116 my_name, __func__);
3117 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3118 return illegal_condition_result;
3119 }
3120 lbdof_blen = lbdof * lb_size;
3121 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3122 if (sdebug_verbose)
3123 sdev_printk(KERN_INFO, scp->device,
3124 "%s: %s: LBA range descriptors don't fit\n",
3125 my_name, __func__);
3126 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3127 return illegal_condition_result;
3128 }
3129 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3130 if (lrdp == NULL)
3131 return SCSI_MLQUEUE_HOST_BUSY;
3132 if (sdebug_verbose)
3133 sdev_printk(KERN_INFO, scp->device,
3134 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3135 my_name, __func__, lbdof_blen);
3136 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3137 if (res == -1) {
3138 ret = DID_ERROR << 16;
3139 goto err_out;
3140 }
3141
3142 write_lock_irqsave(&atomic_rw, iflags);
3143 sg_off = lbdof_blen;
3144 /* Spec says Buffer xfer Length field in number of LBs in dout */
3145 cum_lb = 0;
3146 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3147 lba = get_unaligned_be64(up + 0);
3148 num = get_unaligned_be32(up + 8);
3149 if (sdebug_verbose)
3150 sdev_printk(KERN_INFO, scp->device,
3151 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3152 my_name, __func__, k, lba, num, sg_off);
3153 if (num == 0)
3154 continue;
3155 ret = check_device_access_params(scp, lba, num);
3156 if (ret)
3157 goto err_out_unlock;
3158 num_by = num * lb_size;
3159 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3160
3161 if ((cum_lb + num) > bt_len) {
3162 if (sdebug_verbose)
3163 sdev_printk(KERN_INFO, scp->device,
3164 "%s: %s: sum of blocks > data provided\n",
3165 my_name, __func__);
3166 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3167 0);
3168 ret = illegal_condition_result;
3169 goto err_out_unlock;
3170 }
3171
3172 /* DIX + T10 DIF */
3173 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3174 int prot_ret = prot_verify_write(scp, lba, num,
3175 ei_lba);
3176
3177 if (prot_ret) {
3178 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3179 prot_ret);
3180 ret = illegal_condition_result;
3181 goto err_out_unlock;
3182 }
3183 }
3184
3185 ret = do_device_access(scp, sg_off, lba, num, true);
3186 if (unlikely(scsi_debug_lbp()))
3187 map_region(lba, num);
3188 if (unlikely(-1 == ret)) {
3189 ret = DID_ERROR << 16;
3190 goto err_out_unlock;
3191 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3192 sdev_printk(KERN_INFO, scp->device,
3193 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3194 my_name, num_by, ret);
3195
3196 if (unlikely(sdebug_any_injecting_opt)) {
3197 struct sdebug_queued_cmd *sqcp =
3198 (struct sdebug_queued_cmd *)scp->host_scribble;
3199
3200 if (sqcp) {
3201 if (sqcp->inj_recovered) {
3202 mk_sense_buffer(scp, RECOVERED_ERROR,
3203 THRESHOLD_EXCEEDED, 0);
3204 ret = illegal_condition_result;
3205 goto err_out_unlock;
3206 } else if (sqcp->inj_dif) {
3207 /* Logical block guard check failed */
3208 mk_sense_buffer(scp, ABORTED_COMMAND,
3209 0x10, 1);
3210 ret = illegal_condition_result;
3211 goto err_out_unlock;
3212 } else if (sqcp->inj_dix) {
3213 mk_sense_buffer(scp, ILLEGAL_REQUEST,
3214 0x10, 1);
3215 ret = illegal_condition_result;
3216 goto err_out_unlock;
3217 }
3218 }
3219 }
3220 sg_off += num_by;
3221 cum_lb += num;
3222 }
3223 ret = 0;
3224err_out_unlock:
3225 write_unlock_irqrestore(&atomic_rw, iflags);
3226err_out:
3227 kfree(lrdp);
3228 return ret;
3229}
3230
Douglas Gilbertfd321192016-04-25 12:16:33 -04003231static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3232 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003233{
3234 unsigned long iflags;
3235 unsigned long long i;
3236 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003237 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003238
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003239 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003240 if (ret)
3241 return ret;
3242
3243 write_lock_irqsave(&atomic_rw, iflags);
3244
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003245 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003246 unmap_region(lba, num);
3247 goto out;
3248 }
3249
Douglas Gilbert773642d2016-04-25 12:16:28 -04003250 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003251 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3252 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003253 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003254 ret = 0;
3255 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003256 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3257 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003258
3259 if (-1 == ret) {
3260 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003261 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003262 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003263 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003264 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003265 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003266 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003267
3268 /* Copy first sector to remaining blocks */
3269 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003270 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3271 fake_storep + lba_off,
3272 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003273
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003274 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003275 map_region(lba, num);
3276out:
3277 write_unlock_irqrestore(&atomic_rw, iflags);
3278
3279 return 0;
3280}
3281
Douglas Gilbertfd321192016-04-25 12:16:33 -04003282static int resp_write_same_10(struct scsi_cmnd *scp,
3283 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003284{
3285 u8 *cmd = scp->cmnd;
3286 u32 lba;
3287 u16 num;
3288 u32 ei_lba = 0;
3289 bool unmap = false;
3290
3291 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003292 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003293 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3294 return check_condition_result;
3295 } else
3296 unmap = true;
3297 }
3298 lba = get_unaligned_be32(cmd + 2);
3299 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003300 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003301 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3302 return check_condition_result;
3303 }
3304 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3305}
3306
Douglas Gilbertfd321192016-04-25 12:16:33 -04003307static int resp_write_same_16(struct scsi_cmnd *scp,
3308 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003309{
3310 u8 *cmd = scp->cmnd;
3311 u64 lba;
3312 u32 num;
3313 u32 ei_lba = 0;
3314 bool unmap = false;
3315 bool ndob = false;
3316
3317 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003318 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003319 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3320 return check_condition_result;
3321 } else
3322 unmap = true;
3323 }
3324 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3325 ndob = true;
3326 lba = get_unaligned_be64(cmd + 2);
3327 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003328 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003329 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3330 return check_condition_result;
3331 }
3332 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3333}
3334
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003335/* Note the mode field is in the same position as the (lower) service action
3336 * field. For the Report supported operation codes command, SPC-4 suggests
3337 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003338static int resp_write_buffer(struct scsi_cmnd *scp,
3339 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003340{
3341 u8 *cmd = scp->cmnd;
3342 struct scsi_device *sdp = scp->device;
3343 struct sdebug_dev_info *dp;
3344 u8 mode;
3345
3346 mode = cmd[1] & 0x1f;
3347 switch (mode) {
3348 case 0x4: /* download microcode (MC) and activate (ACT) */
3349 /* set UAs on this device only */
3350 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3351 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3352 break;
3353 case 0x5: /* download MC, save and ACT */
3354 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3355 break;
3356 case 0x6: /* download MC with offsets and ACT */
3357 /* set UAs on most devices (LUs) in this target */
3358 list_for_each_entry(dp,
3359 &devip->sdbg_host->dev_info_list,
3360 dev_list)
3361 if (dp->target == sdp->id) {
3362 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3363 if (devip != dp)
3364 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3365 dp->uas_bm);
3366 }
3367 break;
3368 case 0x7: /* download MC with offsets, save, and ACT */
3369 /* set UA on all devices (LUs) in this target */
3370 list_for_each_entry(dp,
3371 &devip->sdbg_host->dev_info_list,
3372 dev_list)
3373 if (dp->target == sdp->id)
3374 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3375 dp->uas_bm);
3376 break;
3377 default:
3378 /* do nothing for this command for other mode values */
3379 break;
3380 }
3381 return 0;
3382}
3383
Douglas Gilbertfd321192016-04-25 12:16:33 -04003384static int resp_comp_write(struct scsi_cmnd *scp,
3385 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003386{
3387 u8 *cmd = scp->cmnd;
3388 u8 *arr;
3389 u8 *fake_storep_hold;
3390 u64 lba;
3391 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003392 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003393 u8 num;
3394 unsigned long iflags;
3395 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003396 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003397
Douglas Gilbertd467d312014-11-26 12:33:48 -05003398 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003399 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3400 if (0 == num)
3401 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003402 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003403 (cmd[1] & 0xe0)) {
3404 mk_sense_invalid_opcode(scp);
3405 return check_condition_result;
3406 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003407 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3408 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003409 (cmd[1] & 0xe0) == 0)
3410 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3411 "to DIF device\n");
3412
3413 /* inline check_device_access_params() */
3414 if (lba + num > sdebug_capacity) {
3415 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3416 return check_condition_result;
3417 }
3418 /* transfer length excessive (tie in to block limits VPD page) */
3419 if (num > sdebug_store_sectors) {
3420 /* needs work to find which cdb byte 'num' comes from */
3421 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3422 return check_condition_result;
3423 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003424 dnum = 2 * num;
3425 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3426 if (NULL == arr) {
3427 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3428 INSUFF_RES_ASCQ);
3429 return check_condition_result;
3430 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003431
3432 write_lock_irqsave(&atomic_rw, iflags);
3433
3434 /* trick do_device_access() to fetch both compare and write buffers
3435 * from data-in into arr. Safe (atomic) since write_lock held. */
3436 fake_storep_hold = fake_storep;
3437 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003438 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003439 fake_storep = fake_storep_hold;
3440 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003441 retval = DID_ERROR << 16;
3442 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003443 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003444 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3445 "indicated=%u, IO sent=%d bytes\n", my_name,
3446 dnum * lb_size, ret);
3447 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003448 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003449 retval = check_condition_result;
3450 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003451 }
3452 if (scsi_debug_lbp())
3453 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003454cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003455 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003456 kfree(arr);
3457 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003458}
3459
Martin K. Petersen44d92692009-10-15 14:45:27 -04003460struct unmap_block_desc {
3461 __be64 lba;
3462 __be32 blocks;
3463 __be32 __reserved;
3464};
3465
Douglas Gilbertfd321192016-04-25 12:16:33 -04003466static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003467{
3468 unsigned char *buf;
3469 struct unmap_block_desc *desc;
3470 unsigned int i, payload_len, descriptors;
3471 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003472 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003473
Martin K. Petersen44d92692009-10-15 14:45:27 -04003474
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003475 if (!scsi_debug_lbp())
3476 return 0; /* fib and say its done */
3477 payload_len = get_unaligned_be16(scp->cmnd + 7);
3478 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003479
3480 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003481 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003482 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003483 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003484 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003485
Douglas Gilbertb333a812016-04-25 12:16:30 -04003486 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003487 if (!buf) {
3488 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3489 INSUFF_RES_ASCQ);
3490 return check_condition_result;
3491 }
3492
3493 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003494
3495 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3496 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3497
3498 desc = (void *)&buf[8];
3499
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003500 write_lock_irqsave(&atomic_rw, iflags);
3501
Martin K. Petersen44d92692009-10-15 14:45:27 -04003502 for (i = 0 ; i < descriptors ; i++) {
3503 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3504 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3505
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003506 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003507 if (ret)
3508 goto out;
3509
3510 unmap_region(lba, num);
3511 }
3512
3513 ret = 0;
3514
3515out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003516 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003517 kfree(buf);
3518
3519 return ret;
3520}
3521
3522#define SDEBUG_GET_LBA_STATUS_LEN 32
3523
Douglas Gilbertfd321192016-04-25 12:16:33 -04003524static int resp_get_lba_status(struct scsi_cmnd *scp,
3525 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003526{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003527 u8 *cmd = scp->cmnd;
3528 u64 lba;
3529 u32 alloc_len, mapped, num;
3530 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003531 int ret;
3532
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003533 lba = get_unaligned_be64(cmd + 2);
3534 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003535
3536 if (alloc_len < 24)
3537 return 0;
3538
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003539 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003540 if (ret)
3541 return ret;
3542
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003543 if (scsi_debug_lbp())
3544 mapped = map_state(lba, &num);
3545 else {
3546 mapped = 1;
3547 /* following just in case virtual_gb changed */
3548 sdebug_capacity = get_sdebug_capacity();
3549 if (sdebug_capacity - lba <= 0xffffffff)
3550 num = sdebug_capacity - lba;
3551 else
3552 num = 0xffffffff;
3553 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003554
3555 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003556 put_unaligned_be32(20, arr); /* Parameter Data Length */
3557 put_unaligned_be64(lba, arr + 8); /* LBA */
3558 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3559 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003560
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003561 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003562}
3563
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003564#define RL_BUCKET_ELEMS 8
3565
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003566/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3567 * (W-LUN), the normal Linux scanning logic does not associate it with a
3568 * device (e.g. /dev/sg7). The following magic will make that association:
3569 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3570 * where <n> is a host number. If there are multiple targets in a host then
3571 * the above will associate a W-LUN to each target. To only get a W-LUN
3572 * for target 2, then use "echo '- 2 49409' > scan" .
3573 */
3574static int resp_report_luns(struct scsi_cmnd *scp,
3575 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003577 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003578 unsigned int alloc_len;
3579 unsigned char select_report;
3580 u64 lun;
3581 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003582 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003583 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3584 unsigned int wlun_cnt; /* report luns W-LUN count */
3585 unsigned int tlun_cnt; /* total LUN count */
3586 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003587 int k, j, n, res;
3588 unsigned int off_rsp = 0;
3589 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003591 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003592
3593 select_report = cmd[2];
3594 alloc_len = get_unaligned_be32(cmd + 6);
3595
3596 if (alloc_len < 4) {
3597 pr_err("alloc len too small %d\n", alloc_len);
3598 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 return check_condition_result;
3600 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003601
3602 switch (select_report) {
3603 case 0: /* all LUNs apart from W-LUNs */
3604 lun_cnt = sdebug_max_luns;
3605 wlun_cnt = 0;
3606 break;
3607 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003608 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003609 wlun_cnt = 1;
3610 break;
3611 case 2: /* all LUNs */
3612 lun_cnt = sdebug_max_luns;
3613 wlun_cnt = 1;
3614 break;
3615 case 0x10: /* only administrative LUs */
3616 case 0x11: /* see SPC-5 */
3617 case 0x12: /* only subsiduary LUs owned by referenced LU */
3618 default:
3619 pr_debug("select report invalid %d\n", select_report);
3620 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3621 return check_condition_result;
3622 }
3623
3624 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003625 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003626
3627 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003628 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3629 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003630 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3631 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3632
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003633 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003634 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003635 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3636 memset(arr, 0, sizeof(arr));
3637 lun_p = (struct scsi_lun *)&arr[0];
3638 if (k == 0) {
3639 put_unaligned_be32(rlen, &arr[0]);
3640 ++lun_p;
3641 j = 1;
3642 }
3643 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3644 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3645 break;
3646 int_to_scsilun(lun++, lun_p);
3647 }
3648 if (j < RL_BUCKET_ELEMS)
3649 break;
3650 n = j * sz_lun;
3651 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3652 if (res)
3653 return res;
3654 off_rsp += n;
3655 }
3656 if (wlun_cnt) {
3657 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3658 ++j;
3659 }
3660 if (j > 0)
3661 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003662 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663}
3664
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003665static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3666 unsigned int num, struct sdebug_dev_info *devip)
3667{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003668 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003669 unsigned char *kaddr, *buf;
3670 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003671 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003672 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003673
3674 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003675 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003676 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003677 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3678 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003679 return check_condition_result;
3680 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003681
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003682 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003683
3684 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003685 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3686 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003687
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003688 while (sg_miter_next(&miter)) {
3689 kaddr = miter.addr;
3690 for (j = 0; j < miter.length; j++)
3691 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003692
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003693 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003694 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003695 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003696 kfree(buf);
3697
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003698 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003699}
3700
Douglas Gilbertfd321192016-04-25 12:16:33 -04003701static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3702 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003703{
3704 u8 *cmd = scp->cmnd;
3705 u64 lba;
3706 u32 num;
3707 int errsts;
3708
3709 if (!scsi_bidi_cmnd(scp)) {
3710 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3711 INSUFF_RES_ASCQ);
3712 return check_condition_result;
3713 }
3714 errsts = resp_read_dt0(scp, devip);
3715 if (errsts)
3716 return errsts;
3717 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3718 errsts = resp_write_dt0(scp, devip);
3719 if (errsts)
3720 return errsts;
3721 }
3722 lba = get_unaligned_be32(cmd + 2);
3723 num = get_unaligned_be16(cmd + 7);
3724 return resp_xdwriteread(scp, lba, num, devip);
3725}
3726
Douglas Gilbertc4837392016-05-06 00:40:26 -04003727static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3728{
Bart Van Assche458df782018-01-26 08:52:19 -08003729 u32 tag = blk_mq_unique_tag(cmnd->request);
3730 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003731
Bart Van Assche458df782018-01-26 08:52:19 -08003732 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3733 if (WARN_ON_ONCE(hwq >= submit_queues))
3734 hwq = 0;
3735 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003736}
3737
3738/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003739static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003741 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003742 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003744 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003745 struct sdebug_queued_cmd *sqcp;
3746 struct scsi_cmnd *scp;
3747 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748
Douglas Gilbert10bde982018-01-10 16:57:31 -05003749 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003750 qc_idx = sd_dp->qc_idx;
3751 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3752 if (sdebug_statistics) {
3753 atomic_inc(&sdebug_completions);
3754 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3755 atomic_inc(&sdebug_miss_cpus);
3756 }
3757 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3758 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 return;
3760 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003761 spin_lock_irqsave(&sqp->qc_lock, iflags);
3762 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003763 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003764 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003765 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3766 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3767 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 return;
3769 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003770 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003771 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003772 atomic_dec(&devip->num_in_q);
3773 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003774 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003775 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003776 retiring = 1;
3777
3778 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003779 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3780 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003781 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003782 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003784
3785 if (unlikely(retiring)) { /* user has reduced max_queue */
3786 int k, retval;
3787
3788 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003789 if (qc_idx >= retval) {
3790 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003791 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003792 return;
3793 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003794 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003795 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003796 atomic_set(&retired_max_queue, 0);
3797 else
3798 atomic_set(&retired_max_queue, k + 1);
3799 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003800 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003801 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802}
3803
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003804/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003805static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003806{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003807 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3808 hrt);
3809 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003810 return HRTIMER_NORESTART;
3811}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
Douglas Gilberta10bc122016-04-25 12:16:32 -04003813/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003814static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003815{
3816 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3817 ew.work);
3818 sdebug_q_cmd_complete(sd_dp);
3819}
3820
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003821static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003822static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003823
Douglas Gilbertfd321192016-04-25 12:16:33 -04003824static struct sdebug_dev_info *sdebug_device_create(
3825 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003826{
3827 struct sdebug_dev_info *devip;
3828
3829 devip = kzalloc(sizeof(*devip), flags);
3830 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003831 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003832 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003833 else if (sdebug_uuid_ctl == 2) {
3834 if (got_shared_uuid)
3835 devip->lu_name = shared_uuid;
3836 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003837 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003838 got_shared_uuid = true;
3839 devip->lu_name = shared_uuid;
3840 }
3841 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003842 devip->sdbg_host = sdbg_host;
3843 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3844 }
3845 return devip;
3846}
3847
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003848static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003850 struct sdebug_host_info *sdbg_host;
3851 struct sdebug_dev_info *open_devip = NULL;
3852 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003854 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3855 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003856 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3860 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003861 (devip->target == sdev->id) &&
3862 (devip->lun == sdev->lun))
3863 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 else {
3865 if ((!devip->used) && (!open_devip))
3866 open_devip = devip;
3867 }
3868 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003869 if (!open_devip) { /* try and make a new one */
3870 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3871 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003872 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 return NULL;
3874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003876
3877 open_devip->channel = sdev->channel;
3878 open_devip->target = sdev->id;
3879 open_devip->lun = sdev->lun;
3880 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003881 atomic_set(&open_devip->num_in_q, 0);
3882 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003883 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003884 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885}
3886
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003887static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003889 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003890 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003891 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003892 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003893 return 0;
3894}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003896static int scsi_debug_slave_configure(struct scsi_device *sdp)
3897{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003898 struct sdebug_dev_info *devip =
3899 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003900
Douglas Gilbert773642d2016-04-25 12:16:28 -04003901 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003902 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003903 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003904 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3905 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3906 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003907 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003908 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003909 return 1; /* no resources, will be marked offline */
3910 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003911 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003912 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003913 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003914 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003915 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003916 return 0;
3917}
3918
3919static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3920{
3921 struct sdebug_dev_info *devip =
3922 (struct sdebug_dev_info *)sdp->hostdata;
3923
Douglas Gilbert773642d2016-04-25 12:16:28 -04003924 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003925 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003926 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3927 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003928 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003929 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003930 sdp->hostdata = NULL;
3931 }
3932}
3933
Douglas Gilbert10bde982018-01-10 16:57:31 -05003934static void stop_qc_helper(struct sdebug_defer *sd_dp,
3935 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003936{
3937 if (!sd_dp)
3938 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003939 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003940 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003941 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003942 cancel_work_sync(&sd_dp->ew.work);
3943}
3944
Douglas Gilberta10bc122016-04-25 12:16:32 -04003945/* If @cmnd found deletes its timer or work queue and returns true; else
3946 returns false */
3947static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003948{
3949 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003950 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003951 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003952 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003953 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003954 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003955 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003956
Douglas Gilbertc4837392016-05-06 00:40:26 -04003957 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3958 spin_lock_irqsave(&sqp->qc_lock, iflags);
3959 qmax = sdebug_max_queue;
3960 r_qmax = atomic_read(&retired_max_queue);
3961 if (r_qmax > qmax)
3962 qmax = r_qmax;
3963 for (k = 0; k < qmax; ++k) {
3964 if (test_bit(k, sqp->in_use_bm)) {
3965 sqcp = &sqp->qc_arr[k];
3966 if (cmnd != sqcp->a_cmnd)
3967 continue;
3968 /* found */
3969 devip = (struct sdebug_dev_info *)
3970 cmnd->device->hostdata;
3971 if (devip)
3972 atomic_dec(&devip->num_in_q);
3973 sqcp->a_cmnd = NULL;
3974 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003975 if (sd_dp) {
3976 l_defer_t = sd_dp->defer_t;
3977 sd_dp->defer_t = SDEB_DEFER_NONE;
3978 } else
3979 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003980 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003981 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003982 clear_bit(k, sqp->in_use_bm);
3983 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003984 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003985 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003986 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003987 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003988 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003989}
3990
Douglas Gilberta10bc122016-04-25 12:16:32 -04003991/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003992static void stop_all_queued(void)
3993{
3994 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003995 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003996 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003997 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003998 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003999 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004000 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004001
Douglas Gilbertc4837392016-05-06 00:40:26 -04004002 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4003 spin_lock_irqsave(&sqp->qc_lock, iflags);
4004 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4005 if (test_bit(k, sqp->in_use_bm)) {
4006 sqcp = &sqp->qc_arr[k];
4007 if (sqcp->a_cmnd == NULL)
4008 continue;
4009 devip = (struct sdebug_dev_info *)
4010 sqcp->a_cmnd->device->hostdata;
4011 if (devip)
4012 atomic_dec(&devip->num_in_q);
4013 sqcp->a_cmnd = NULL;
4014 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004015 if (sd_dp) {
4016 l_defer_t = sd_dp->defer_t;
4017 sd_dp->defer_t = SDEB_DEFER_NONE;
4018 } else
4019 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004020 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004021 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004022 clear_bit(k, sqp->in_use_bm);
4023 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004024 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004025 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004026 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028}
4029
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004030/* Free queued command memory on heap */
4031static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004033 int j, k;
4034 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004035 struct sdebug_queued_cmd *sqcp;
4036
Douglas Gilbertc4837392016-05-06 00:40:26 -04004037 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4038 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4039 sqcp = &sqp->qc_arr[k];
4040 kfree(sqcp->sd_dp);
4041 sqcp->sd_dp = NULL;
4042 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044}
4045
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004046static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004048 bool ok;
4049
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004050 ++num_aborts;
4051 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004052 ok = stop_queued_cmnd(SCpnt);
4053 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4054 sdev_printk(KERN_INFO, SCpnt->device,
4055 "%s: command%s found\n", __func__,
4056 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004058 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059}
4060
4061static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
4062{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004064 if (SCpnt && SCpnt->device) {
4065 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004066 struct sdebug_dev_info *devip =
4067 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004068
Douglas Gilbert773642d2016-04-25 12:16:28 -04004069 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004070 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004072 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 }
4074 return SUCCESS;
4075}
4076
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004077static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4078{
4079 struct sdebug_host_info *sdbg_host;
4080 struct sdebug_dev_info *devip;
4081 struct scsi_device *sdp;
4082 struct Scsi_Host *hp;
4083 int k = 0;
4084
4085 ++num_target_resets;
4086 if (!SCpnt)
4087 goto lie;
4088 sdp = SCpnt->device;
4089 if (!sdp)
4090 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004091 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004092 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4093 hp = sdp->host;
4094 if (!hp)
4095 goto lie;
4096 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4097 if (sdbg_host) {
4098 list_for_each_entry(devip,
4099 &sdbg_host->dev_info_list,
4100 dev_list)
4101 if (devip->target == sdp->id) {
4102 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4103 ++k;
4104 }
4105 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004106 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004107 sdev_printk(KERN_INFO, sdp,
4108 "%s: %d device(s) found in target\n", __func__, k);
4109lie:
4110 return SUCCESS;
4111}
4112
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
4114{
4115 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004116 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004117 struct scsi_device *sdp;
4118 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004119 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004122 if (!(SCpnt && SCpnt->device))
4123 goto lie;
4124 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004125 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004126 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4127 hp = sdp->host;
4128 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004129 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004131 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05004132 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004133 dev_list) {
4134 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4135 ++k;
4136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 }
4138 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004139 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004140 sdev_printk(KERN_INFO, sdp,
4141 "%s: %d device(s) found in host\n", __func__, k);
4142lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 return SUCCESS;
4144}
4145
4146static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
4147{
4148 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004149 struct sdebug_dev_info *devip;
4150 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004153 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004154 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05004155 spin_lock(&sdebug_host_list_lock);
4156 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004157 list_for_each_entry(devip, &sdbg_host->dev_info_list,
4158 dev_list) {
4159 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4160 ++k;
4161 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05004162 }
4163 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004165 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004166 sdev_printk(KERN_INFO, SCpnt->device,
4167 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 return SUCCESS;
4169}
4170
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09004171static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004172 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173{
4174 struct partition * pp;
4175 int starts[SDEBUG_MAX_PARTS + 2];
4176 int sectors_per_part, num_sectors, k;
4177 int heads_by_sects, start_sec, end_sec;
4178
4179 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004180 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004182 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4183 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03004184 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004186 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004188 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004190 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004191 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4193 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004194 starts[sdebug_num_parts] = num_sectors;
4195 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196
4197 ramp[510] = 0x55; /* magic partition markings */
4198 ramp[511] = 0xAA;
4199 pp = (struct partition *)(ramp + 0x1be);
4200 for (k = 0; starts[k + 1]; ++k, ++pp) {
4201 start_sec = starts[k];
4202 end_sec = starts[k + 1] - 1;
4203 pp->boot_ind = 0;
4204
4205 pp->cyl = start_sec / heads_by_sects;
4206 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4207 / sdebug_sectors_per;
4208 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4209
4210 pp->end_cyl = end_sec / heads_by_sects;
4211 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4212 / sdebug_sectors_per;
4213 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4214
Akinobu Mita150c3542013-08-26 22:08:40 +09004215 pp->start_sect = cpu_to_le32(start_sec);
4216 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 pp->sys_ind = 0x83; /* plain Linux partition */
4218 }
4219}
4220
Douglas Gilbertc4837392016-05-06 00:40:26 -04004221static void block_unblock_all_queues(bool block)
4222{
4223 int j;
4224 struct sdebug_queue *sqp;
4225
4226 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4227 atomic_set(&sqp->blocked, (int)block);
4228}
4229
4230/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4231 * commands will be processed normally before triggers occur.
4232 */
4233static void tweak_cmnd_count(void)
4234{
4235 int count, modulo;
4236
4237 modulo = abs(sdebug_every_nth);
4238 if (modulo < 2)
4239 return;
4240 block_unblock_all_queues(true);
4241 count = atomic_read(&sdebug_cmnd_count);
4242 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4243 block_unblock_all_queues(false);
4244}
4245
4246static void clear_queue_stats(void)
4247{
4248 atomic_set(&sdebug_cmnd_count, 0);
4249 atomic_set(&sdebug_completions, 0);
4250 atomic_set(&sdebug_miss_cpus, 0);
4251 atomic_set(&sdebug_a_tsf, 0);
4252}
4253
4254static void setup_inject(struct sdebug_queue *sqp,
4255 struct sdebug_queued_cmd *sqcp)
4256{
4257 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4258 return;
4259 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4260 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4261 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4262 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4263 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004264 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004265}
4266
4267/* Complete the processing of the thread that queued a SCSI command to this
4268 * driver. It either completes the command by calling cmnd_done() or
4269 * schedules a hr timer or work queue then returns 0. Returns
4270 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4271 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004272static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Douglas Gilbert10bde982018-01-10 16:57:31 -05004273 int scsi_result, int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004275 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004276 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004277 struct sdebug_queue *sqp;
4278 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004279 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004280 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004282 if (unlikely(devip == NULL)) {
4283 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004284 scsi_result = DID_NO_CONNECT << 16;
4285 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004287 sdp = cmnd->device;
4288
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004289 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004290 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4291 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004292 if (delta_jiff == 0)
4293 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004295 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004296 sqp = get_queue(cmnd);
4297 spin_lock_irqsave(&sqp->qc_lock, iflags);
4298 if (unlikely(atomic_read(&sqp->blocked))) {
4299 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4300 return SCSI_MLQUEUE_HOST_BUSY;
4301 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004302 num_in_q = atomic_read(&devip->num_in_q);
4303 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004304 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004305 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004306 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004307 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004308 goto respond_in_thread;
4309 } else
4310 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004311 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004312 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4313 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004314 if ((num_in_q == (qdepth - 1)) &&
4315 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004316 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004317 atomic_set(&sdebug_a_tsf, 0);
4318 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004319 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004321 }
4322
Douglas Gilbertc4837392016-05-06 00:40:26 -04004323 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004324 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004325 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004326 if (scsi_result)
4327 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004328 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004329 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004330 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004331 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004332 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004333 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004334 (scsi_result ? "status: TASK SET FULL" :
4335 "report: host busy"));
4336 if (scsi_result)
4337 goto respond_in_thread;
4338 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004339 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004341 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004342 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004343 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004344 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004345 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004346 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004347 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004348 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4349 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4350 setup_inject(sqp, sqcp);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004351 if (sd_dp == NULL) {
4352 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4353 if (sd_dp == NULL)
4354 return SCSI_MLQUEUE_HOST_BUSY;
4355 }
4356 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004357 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004358
Douglas Gilbertb333a812016-04-25 12:16:30 -04004359 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004360 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004361 } else
Douglas Gilbert10bde982018-01-10 16:57:31 -05004362 kt = ndelay;
4363 if (!sd_dp->init_hrt) {
4364 sd_dp->init_hrt = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004365 sqcp->sd_dp = sd_dp;
4366 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004367 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004368 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004369 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4370 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004371 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004372 if (sdebug_statistics)
4373 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004374 sd_dp->defer_t = SDEB_DEFER_HRT;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004375 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4376 } else { /* jdelay < 0, use work queue */
Douglas Gilbert10bde982018-01-10 16:57:31 -05004377 if (!sd_dp->init_wq) {
4378 sd_dp->init_wq = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004379 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004380 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4381 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004382 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004383 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004384 if (sdebug_statistics)
4385 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004386 sd_dp->defer_t = SDEB_DEFER_WQ;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004387 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004388 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004389 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4390 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004391 sdev_printk(KERN_INFO, sdp,
4392 "%s: num_in_q=%d +1, %s%s\n", __func__,
4393 num_in_q, (inject ? "<inject> " : ""),
4394 "status: TASK SET FULL");
4395 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004396
4397respond_in_thread: /* call back to mid-layer using invocation thread */
4398 cmnd->result = scsi_result;
4399 cmnd->scsi_done(cmnd);
4400 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004402
Douglas Gilbert23183912006-09-16 20:30:47 -04004403/* Note: The following macros create attribute files in the
4404 /sys/module/scsi_debug/parameters directory. Unfortunately this
4405 driver is unaware of a change and cannot trigger auxiliary actions
4406 as it can when the corresponding attribute in the
4407 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4408 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004409module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4410module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004411module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004412module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004413module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004414module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4415module_param_named(dif, sdebug_dif, int, S_IRUGO);
4416module_param_named(dix, sdebug_dix, int, S_IRUGO);
4417module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4418module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4419module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4420module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4421module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004422module_param_string(inq_vendor, sdebug_inq_vendor_id,
4423 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4424module_param_string(inq_product, sdebug_inq_product_id,
4425 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4426module_param_string(inq_rev, sdebug_inq_product_rev,
4427 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004428module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4429module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4430module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4431module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4432module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4433module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4434module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4435module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4436module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4437module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4438module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4439module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4440module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4441module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4442module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004443module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004444module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4445module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4446module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4447module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004448module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004449module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004450module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004451module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4452module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4453module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4454module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4455module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004456module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004457module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004458 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004459module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004460 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
4462MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4463MODULE_DESCRIPTION("SCSI debug adapter driver");
4464MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004465MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466
4467MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004468MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004469MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004470MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004471MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004472MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004473MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4474MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004475MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004476MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004477MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004478MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004479MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004480MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4481MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004482MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4483 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004484MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4485MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4486MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004487MODULE_PARM_DESC(lbprz,
4488 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004489MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004490MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004491MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4492MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004493MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004494MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004496MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004497MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004498MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004499MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004500MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004502MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004503MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004504MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004505MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004506MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004507MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004508MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4509MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004510MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4511MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004512MODULE_PARM_DESC(uuid_ctl,
4513 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004514MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004515MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4516MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004518#define SDEBUG_INFO_LEN 256
4519static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
4521static const char * scsi_debug_info(struct Scsi_Host * shp)
4522{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004523 int k;
4524
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004525 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4526 my_name, SDEBUG_VERSION, sdebug_version_date);
4527 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004528 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004529 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4530 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4531 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4532 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 return sdebug_info;
4534}
4535
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004536/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004537static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4538 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539{
Al Viroc8ed5552013-03-31 01:46:06 -04004540 char arr[16];
4541 int opts;
4542 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543
Al Viroc8ed5552013-03-31 01:46:06 -04004544 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4545 return -EACCES;
4546 memcpy(arr, buffer, minLen);
4547 arr[minLen] = '\0';
4548 if (1 != sscanf(arr, "%d", &opts))
4549 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004550 sdebug_opts = opts;
4551 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4552 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4553 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004554 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004555 return length;
4556}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004558/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4559 * same for each scsi_debug host (if more than one). Some of the counters
4560 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004561static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4562{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004563 int f, j, l;
4564 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004565
Douglas Gilbertc4837392016-05-06 00:40:26 -04004566 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4567 SDEBUG_VERSION, sdebug_version_date);
4568 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4569 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4570 sdebug_opts, sdebug_every_nth);
4571 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4572 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4573 sdebug_sector_size, "bytes");
4574 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4575 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4576 num_aborts);
4577 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4578 num_dev_resets, num_target_resets, num_bus_resets,
4579 num_host_resets);
4580 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4581 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08004582 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4583 sdebug_statistics);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004584 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4585 atomic_read(&sdebug_cmnd_count),
4586 atomic_read(&sdebug_completions),
4587 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4588 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004589
Douglas Gilbertc4837392016-05-06 00:40:26 -04004590 seq_printf(m, "submit_queues=%d\n", submit_queues);
4591 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4592 seq_printf(m, " queue %d:\n", j);
4593 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4594 if (f != sdebug_max_queue) {
4595 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4596 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4597 "first,last bits", f, l);
4598 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004599 }
Al Viroc8ed5552013-03-31 01:46:06 -04004600 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601}
4602
Akinobu Mita82069372013-10-14 22:48:04 +09004603static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004605 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004607/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4608 * of delay is jiffies.
4609 */
Akinobu Mita82069372013-10-14 22:48:04 +09004610static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4611 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004613 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004615 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004616 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004617 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004618 int j, k;
4619 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004620
Douglas Gilbertc4837392016-05-06 00:40:26 -04004621 block_unblock_all_queues(true);
4622 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4623 ++j, ++sqp) {
4624 k = find_first_bit(sqp->in_use_bm,
4625 sdebug_max_queue);
4626 if (k != sdebug_max_queue) {
4627 res = -EBUSY; /* queued commands */
4628 break;
4629 }
4630 }
4631 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04004632 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004633 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004634 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004635 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004637 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 }
4639 return -EINVAL;
4640}
Akinobu Mita82069372013-10-14 22:48:04 +09004641static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004643static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4644{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004645 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004646}
4647/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004648/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004649static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004650 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004651{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004652 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004653
4654 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004655 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004656 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004657 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004658 int j, k;
4659 struct sdebug_queue *sqp;
4660
4661 block_unblock_all_queues(true);
4662 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4663 ++j, ++sqp) {
4664 k = find_first_bit(sqp->in_use_bm,
4665 sdebug_max_queue);
4666 if (k != sdebug_max_queue) {
4667 res = -EBUSY; /* queued commands */
4668 break;
4669 }
4670 }
4671 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004672 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004673 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4674 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004675 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004676 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004677 }
4678 return res;
4679 }
4680 return -EINVAL;
4681}
4682static DRIVER_ATTR_RW(ndelay);
4683
Akinobu Mita82069372013-10-14 22:48:04 +09004684static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004686 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687}
4688
Akinobu Mita82069372013-10-14 22:48:04 +09004689static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4690 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004692 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 char work[20];
4694
Douglas Gilbert9a051012017-12-23 12:48:10 -05004695 if (sscanf(buf, "%10s", work) == 1) {
4696 if (strncasecmp(work, "0x", 2) == 0) {
4697 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 goto opts_done;
4699 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004700 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 goto opts_done;
4702 }
4703 }
4704 return -EINVAL;
4705opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004706 sdebug_opts = opts;
4707 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4708 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004709 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 return count;
4711}
Akinobu Mita82069372013-10-14 22:48:04 +09004712static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713
Akinobu Mita82069372013-10-14 22:48:04 +09004714static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004716 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717}
Akinobu Mita82069372013-10-14 22:48:04 +09004718static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4719 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004721 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
4723 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004724 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 return count;
4726 }
4727 return -EINVAL;
4728}
Akinobu Mita82069372013-10-14 22:48:04 +09004729static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730
Akinobu Mita82069372013-10-14 22:48:04 +09004731static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004733 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734}
Akinobu Mita82069372013-10-14 22:48:04 +09004735static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4736 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004738 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739
4740 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004741 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 return count;
4743 }
4744 return -EINVAL;
4745}
Akinobu Mita82069372013-10-14 22:48:04 +09004746static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747
Akinobu Mita82069372013-10-14 22:48:04 +09004748static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004749{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004750 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004751}
Akinobu Mita82069372013-10-14 22:48:04 +09004752static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4753 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004754{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004755 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004756
4757 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004758 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004759 sdebug_fake_rw = (sdebug_fake_rw > 0);
4760 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004761 if ((0 == n) && (NULL == fake_storep)) {
4762 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004763 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004764 1048576;
4765
4766 fake_storep = vmalloc(sz);
4767 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004768 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004769 return -ENOMEM;
4770 }
4771 memset(fake_storep, 0, sz);
4772 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004773 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004774 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004775 return count;
4776 }
4777 return -EINVAL;
4778}
Akinobu Mita82069372013-10-14 22:48:04 +09004779static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004780
Akinobu Mita82069372013-10-14 22:48:04 +09004781static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004782{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004783 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004784}
Akinobu Mita82069372013-10-14 22:48:04 +09004785static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4786 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004787{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004788 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004789
4790 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004791 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004792 return count;
4793 }
4794 return -EINVAL;
4795}
Akinobu Mita82069372013-10-14 22:48:04 +09004796static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004797
Akinobu Mita82069372013-10-14 22:48:04 +09004798static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004800 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801}
Akinobu Mita82069372013-10-14 22:48:04 +09004802static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4803 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004805 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806
4807 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004808 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 sdebug_max_tgts_luns();
4810 return count;
4811 }
4812 return -EINVAL;
4813}
Akinobu Mita82069372013-10-14 22:48:04 +09004814static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815
Akinobu Mita82069372013-10-14 22:48:04 +09004816static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004818 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819}
Akinobu Mita82069372013-10-14 22:48:04 +09004820static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821
Akinobu Mita82069372013-10-14 22:48:04 +09004822static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004824 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825}
Akinobu Mita82069372013-10-14 22:48:04 +09004826static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827
Akinobu Mita82069372013-10-14 22:48:04 +09004828static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004830 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831}
Akinobu Mita82069372013-10-14 22:48:04 +09004832static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4833 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004835 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
4837 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004838 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004839 if (nth && !sdebug_statistics) {
4840 pr_info("every_nth needs statistics=1, set it\n");
4841 sdebug_statistics = true;
4842 }
4843 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 return count;
4845 }
4846 return -EINVAL;
4847}
Akinobu Mita82069372013-10-14 22:48:04 +09004848static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849
Akinobu Mita82069372013-10-14 22:48:04 +09004850static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004852 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853}
Akinobu Mita82069372013-10-14 22:48:04 +09004854static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4855 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004857 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004858 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859
4860 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004861 if (n > 256) {
4862 pr_warn("max_luns can be no more than 256\n");
4863 return -EINVAL;
4864 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004865 changed = (sdebug_max_luns != n);
4866 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004868 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004869 struct sdebug_host_info *sdhp;
4870 struct sdebug_dev_info *dp;
4871
4872 spin_lock(&sdebug_host_list_lock);
4873 list_for_each_entry(sdhp, &sdebug_host_list,
4874 host_list) {
4875 list_for_each_entry(dp, &sdhp->dev_info_list,
4876 dev_list) {
4877 set_bit(SDEBUG_UA_LUNS_CHANGED,
4878 dp->uas_bm);
4879 }
4880 }
4881 spin_unlock(&sdebug_host_list_lock);
4882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 return count;
4884 }
4885 return -EINVAL;
4886}
Akinobu Mita82069372013-10-14 22:48:04 +09004887static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888
Akinobu Mita82069372013-10-14 22:48:04 +09004889static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004890{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004891 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004892}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004893/* N.B. max_queue can be changed while there are queued commands. In flight
4894 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004895static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4896 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004897{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004898 int j, n, k, a;
4899 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004900
4901 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004902 (n <= SDEBUG_CANQUEUE)) {
4903 block_unblock_all_queues(true);
4904 k = 0;
4905 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4906 ++j, ++sqp) {
4907 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4908 if (a > k)
4909 k = a;
4910 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004911 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004912 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004913 atomic_set(&retired_max_queue, 0);
4914 else if (k >= n)
4915 atomic_set(&retired_max_queue, k + 1);
4916 else
4917 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004918 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004919 return count;
4920 }
4921 return -EINVAL;
4922}
Akinobu Mita82069372013-10-14 22:48:04 +09004923static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004924
Akinobu Mita82069372013-10-14 22:48:04 +09004925static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004926{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004927 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004928}
Akinobu Mita82069372013-10-14 22:48:04 +09004929static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004930
Akinobu Mita82069372013-10-14 22:48:04 +09004931static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004933 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934}
Akinobu Mita82069372013-10-14 22:48:04 +09004935static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936
Akinobu Mita82069372013-10-14 22:48:04 +09004937static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004938{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004939 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004940}
Akinobu Mita82069372013-10-14 22:48:04 +09004941static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4942 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004943{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004944 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004945 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004946
4947 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004948 changed = (sdebug_virtual_gb != n);
4949 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004950 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004951 if (changed) {
4952 struct sdebug_host_info *sdhp;
4953 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004954
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004955 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004956 list_for_each_entry(sdhp, &sdebug_host_list,
4957 host_list) {
4958 list_for_each_entry(dp, &sdhp->dev_info_list,
4959 dev_list) {
4960 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4961 dp->uas_bm);
4962 }
4963 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004964 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004965 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004966 return count;
4967 }
4968 return -EINVAL;
4969}
Akinobu Mita82069372013-10-14 22:48:04 +09004970static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004971
Akinobu Mita82069372013-10-14 22:48:04 +09004972static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004974 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975}
4976
Douglas Gilbertfd321192016-04-25 12:16:33 -04004977static int sdebug_add_adapter(void);
4978static void sdebug_remove_adapter(void);
4979
Akinobu Mita82069372013-10-14 22:48:04 +09004980static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4981 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004983 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004985 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 if (delta_hosts > 0) {
4988 do {
4989 sdebug_add_adapter();
4990 } while (--delta_hosts);
4991 } else if (delta_hosts < 0) {
4992 do {
4993 sdebug_remove_adapter();
4994 } while (++delta_hosts);
4995 }
4996 return count;
4997}
Akinobu Mita82069372013-10-14 22:48:04 +09004998static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999
Akinobu Mita82069372013-10-14 22:48:04 +09005000static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04005001{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005002 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005003}
Akinobu Mita82069372013-10-14 22:48:04 +09005004static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
5005 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04005006{
5007 int n;
5008
5009 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005010 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04005011 return count;
5012 }
5013 return -EINVAL;
5014}
Akinobu Mita82069372013-10-14 22:48:04 +09005015static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005016
Douglas Gilbertc4837392016-05-06 00:40:26 -04005017static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5018{
5019 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5020}
5021static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5022 size_t count)
5023{
5024 int n;
5025
5026 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5027 if (n > 0)
5028 sdebug_statistics = true;
5029 else {
5030 clear_queue_stats();
5031 sdebug_statistics = false;
5032 }
5033 return count;
5034 }
5035 return -EINVAL;
5036}
5037static DRIVER_ATTR_RW(statistics);
5038
Akinobu Mita82069372013-10-14 22:48:04 +09005039static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04005040{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005041 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005042}
Akinobu Mita82069372013-10-14 22:48:04 +09005043static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005044
Douglas Gilbertc4837392016-05-06 00:40:26 -04005045static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5046{
5047 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5048}
5049static DRIVER_ATTR_RO(submit_queues);
5050
Akinobu Mita82069372013-10-14 22:48:04 +09005051static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005052{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005053 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005054}
Akinobu Mita82069372013-10-14 22:48:04 +09005055static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005056
Akinobu Mita82069372013-10-14 22:48:04 +09005057static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005058{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005059 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005060}
Akinobu Mita82069372013-10-14 22:48:04 +09005061static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005062
Akinobu Mita82069372013-10-14 22:48:04 +09005063static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005064{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005065 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005066}
Akinobu Mita82069372013-10-14 22:48:04 +09005067static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005068
Akinobu Mita82069372013-10-14 22:48:04 +09005069static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005070{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005071 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005072}
Akinobu Mita82069372013-10-14 22:48:04 +09005073static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005074
Akinobu Mita82069372013-10-14 22:48:04 +09005075static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005076{
5077 ssize_t count;
5078
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005079 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04005080 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
5081 sdebug_store_sectors);
5082
Tejun Heoc7badc92015-02-13 14:37:51 -08005083 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5084 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005085 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08005086 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04005087
5088 return count;
5089}
Akinobu Mita82069372013-10-14 22:48:04 +09005090static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005091
Akinobu Mita82069372013-10-14 22:48:04 +09005092static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02005093{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005094 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02005095}
Akinobu Mita82069372013-10-14 22:48:04 +09005096static ssize_t removable_store(struct device_driver *ddp, const char *buf,
5097 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02005098{
5099 int n;
5100
5101 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005102 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02005103 return count;
5104 }
5105 return -EINVAL;
5106}
Akinobu Mita82069372013-10-14 22:48:04 +09005107static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02005108
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005109static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5110{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005111 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005112}
Douglas Gilbert185dd232016-04-25 12:16:29 -04005113/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005114static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5115 size_t count)
5116{
Douglas Gilbert185dd232016-04-25 12:16:29 -04005117 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005118
5119 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04005120 sdebug_host_lock = (n > 0);
5121 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005122 }
5123 return -EINVAL;
5124}
5125static DRIVER_ATTR_RW(host_lock);
5126
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005127static ssize_t strict_show(struct device_driver *ddp, char *buf)
5128{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005129 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005130}
5131static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5132 size_t count)
5133{
5134 int n;
5135
5136 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005137 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005138 return count;
5139 }
5140 return -EINVAL;
5141}
5142static DRIVER_ATTR_RW(strict);
5143
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005144static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
5145{
5146 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
5147}
5148static DRIVER_ATTR_RO(uuid_ctl);
5149
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005150static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
5151{
5152 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
5153}
5154static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
5155 size_t count)
5156{
5157 int ret, n;
5158
5159 ret = kstrtoint(buf, 0, &n);
5160 if (ret)
5161 return ret;
5162 sdebug_cdb_len = n;
5163 all_config_cdb_len();
5164 return count;
5165}
5166static DRIVER_ATTR_RW(cdb_len);
5167
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005168
Akinobu Mita82069372013-10-14 22:48:04 +09005169/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04005170 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
5171 files (over those found in the /sys/module/scsi_debug/parameters
5172 directory) is that auxiliary actions can be triggered when an attribute
5173 is changed. For example see: sdebug_add_host_store() above.
5174 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005175
Akinobu Mita82069372013-10-14 22:48:04 +09005176static struct attribute *sdebug_drv_attrs[] = {
5177 &driver_attr_delay.attr,
5178 &driver_attr_opts.attr,
5179 &driver_attr_ptype.attr,
5180 &driver_attr_dsense.attr,
5181 &driver_attr_fake_rw.attr,
5182 &driver_attr_no_lun_0.attr,
5183 &driver_attr_num_tgts.attr,
5184 &driver_attr_dev_size_mb.attr,
5185 &driver_attr_num_parts.attr,
5186 &driver_attr_every_nth.attr,
5187 &driver_attr_max_luns.attr,
5188 &driver_attr_max_queue.attr,
5189 &driver_attr_no_uld.attr,
5190 &driver_attr_scsi_level.attr,
5191 &driver_attr_virtual_gb.attr,
5192 &driver_attr_add_host.attr,
5193 &driver_attr_vpd_use_hostno.attr,
5194 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005195 &driver_attr_statistics.attr,
5196 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005197 &driver_attr_dix.attr,
5198 &driver_attr_dif.attr,
5199 &driver_attr_guard.attr,
5200 &driver_attr_ato.attr,
5201 &driver_attr_map.attr,
5202 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005203 &driver_attr_host_lock.attr,
5204 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005205 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005206 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005207 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005208 NULL,
5209};
5210ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005212static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005213
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214static int __init scsi_debug_init(void)
5215{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005216 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 int host_to_add;
5218 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005219 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005221 atomic_set(&retired_max_queue, 0);
5222
Douglas Gilbert773642d2016-04-25 12:16:28 -04005223 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005224 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005225 sdebug_ndelay = 0;
5226 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005227 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005228
Douglas Gilbert773642d2016-04-25 12:16:28 -04005229 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04005230 case 512:
5231 case 1024:
5232 case 2048:
5233 case 4096:
5234 break;
5235 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005236 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005237 return -EINVAL;
5238 }
5239
Douglas Gilbert773642d2016-04-25 12:16:28 -04005240 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005241 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005242 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005243 case T10_PI_TYPE1_PROTECTION:
5244 case T10_PI_TYPE2_PROTECTION:
5245 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005246 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005247 break;
5248
5249 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005250 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005251 return -EINVAL;
5252 }
5253
Douglas Gilbert773642d2016-04-25 12:16:28 -04005254 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005255 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005256 return -EINVAL;
5257 }
5258
Douglas Gilbert773642d2016-04-25 12:16:28 -04005259 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005260 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005261 return -EINVAL;
5262 }
5263
Douglas Gilbert773642d2016-04-25 12:16:28 -04005264 if (sdebug_physblk_exp > 15) {
5265 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005266 return -EINVAL;
5267 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005268 if (sdebug_max_luns > 256) {
5269 pr_warn("max_luns can be no more than 256, use default\n");
5270 sdebug_max_luns = DEF_MAX_LUNS;
5271 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005272
Douglas Gilbert773642d2016-04-25 12:16:28 -04005273 if (sdebug_lowest_aligned > 0x3fff) {
5274 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005275 return -EINVAL;
5276 }
5277
Douglas Gilbertc4837392016-05-06 00:40:26 -04005278 if (submit_queues < 1) {
5279 pr_err("submit_queues must be 1 or more\n");
5280 return -EINVAL;
5281 }
5282 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5283 GFP_KERNEL);
5284 if (sdebug_q_arr == NULL)
5285 return -ENOMEM;
5286 for (k = 0; k < submit_queues; ++k)
5287 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5288
Douglas Gilbert773642d2016-04-25 12:16:28 -04005289 if (sdebug_dev_size_mb < 1)
5290 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5291 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5292 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005293 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294
5295 /* play around with geometry, don't waste too much on track 0 */
5296 sdebug_heads = 8;
5297 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005298 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005300 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005301 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5303 (sdebug_sectors_per * sdebug_heads);
5304 if (sdebug_cylinders_per >= 1024) {
5305 /* other LLDs do this; implies >= 1GB ram disk ... */
5306 sdebug_heads = 255;
5307 sdebug_sectors_per = 63;
5308 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5309 (sdebug_sectors_per * sdebug_heads);
5310 }
5311
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005312 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005313 fake_storep = vmalloc(sz);
5314 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005315 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005316 ret = -ENOMEM;
5317 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005318 }
5319 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005320 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005321 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323
Douglas Gilbert773642d2016-04-25 12:16:28 -04005324 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005325 int dif_size;
5326
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005327 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005328 dif_storep = vmalloc(dif_size);
5329
Tomas Winklerc12879702015-07-28 16:54:20 +03005330 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005331
5332 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005333 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005334 ret = -ENOMEM;
5335 goto free_vm;
5336 }
5337
5338 memset(dif_storep, 0xff, dif_size);
5339 }
5340
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005341 /* Logical Block Provisioning */
5342 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005343 sdebug_unmap_max_blocks =
5344 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005345
Douglas Gilbert773642d2016-04-25 12:16:28 -04005346 sdebug_unmap_max_desc =
5347 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005348
Douglas Gilbert773642d2016-04-25 12:16:28 -04005349 sdebug_unmap_granularity =
5350 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005351
Douglas Gilbert773642d2016-04-25 12:16:28 -04005352 if (sdebug_unmap_alignment &&
5353 sdebug_unmap_granularity <=
5354 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005355 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005356 ret = -EINVAL;
5357 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005358 }
5359
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005360 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5361 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005362
Tomas Winklerc12879702015-07-28 16:54:20 +03005363 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005364
5365 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005366 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005367 ret = -ENOMEM;
5368 goto free_vm;
5369 }
5370
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005371 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005372
5373 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005374 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005375 map_region(0, 2);
5376 }
5377
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005378 pseudo_primary = root_device_register("pseudo_0");
5379 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005380 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005381 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005382 goto free_vm;
5383 }
5384 ret = bus_register(&pseudo_lld_bus);
5385 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005386 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005387 goto dev_unreg;
5388 }
5389 ret = driver_register(&sdebug_driverfs_driver);
5390 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005391 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005392 goto bus_unreg;
5393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394
Douglas Gilbert773642d2016-04-25 12:16:28 -04005395 host_to_add = sdebug_add_host;
5396 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397
Douglas Gilbert9a051012017-12-23 12:48:10 -05005398 for (k = 0; k < host_to_add; k++) {
5399 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005400 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005401 break;
5402 }
5403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404
Douglas Gilbert773642d2016-04-25 12:16:28 -04005405 if (sdebug_verbose)
5406 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005407
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005409
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005410bus_unreg:
5411 bus_unregister(&pseudo_lld_bus);
5412dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005413 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005414free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005415 vfree(map_storep);
5416 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005417 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005418free_q_arr:
5419 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005420 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421}
5422
5423static void __exit scsi_debug_exit(void)
5424{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005425 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426
5427 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005428 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 for (; k; k--)
5430 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 driver_unregister(&sdebug_driverfs_driver);
5432 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005433 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005435 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005436 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005438 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439}
5440
5441device_initcall(scsi_debug_init);
5442module_exit(scsi_debug_exit);
5443
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444static void sdebug_release_adapter(struct device * dev)
5445{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005446 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447
5448 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005449 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450}
5451
5452static int sdebug_add_adapter(void)
5453{
5454 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005455 int error = 0;
5456 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005457 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458
Douglas Gilbert9a051012017-12-23 12:48:10 -05005459 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5460 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005461 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005462 return -ENOMEM;
5463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
Douglas Gilbert9a051012017-12-23 12:48:10 -05005465 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466
Douglas Gilbert773642d2016-04-25 12:16:28 -04005467 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005468 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005469 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5470 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005471 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005472 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005474 }
5475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476
Douglas Gilbert9a051012017-12-23 12:48:10 -05005477 spin_lock(&sdebug_host_list_lock);
5478 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5479 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
Douglas Gilbert9a051012017-12-23 12:48:10 -05005481 sdbg_host->dev.bus = &pseudo_lld_bus;
5482 sdbg_host->dev.parent = pseudo_primary;
5483 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005484 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485
Douglas Gilbert9a051012017-12-23 12:48:10 -05005486 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487
Douglas Gilbert9a051012017-12-23 12:48:10 -05005488 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 goto clean;
5490
Douglas Gilbert773642d2016-04-25 12:16:28 -04005491 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005492 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493
5494clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005495 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5496 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 list_del(&sdbg_devinfo->dev_list);
5498 kfree(sdbg_devinfo);
5499 }
5500
5501 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005502 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503}
5504
5505static void sdebug_remove_adapter(void)
5506{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005507 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508
Douglas Gilbert9a051012017-12-23 12:48:10 -05005509 spin_lock(&sdebug_host_list_lock);
5510 if (!list_empty(&sdebug_host_list)) {
5511 sdbg_host = list_entry(sdebug_host_list.prev,
5512 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 list_del(&sdbg_host->host_list);
5514 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005515 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516
5517 if (!sdbg_host)
5518 return;
5519
Douglas Gilbert773642d2016-04-25 12:16:28 -04005520 device_unregister(&sdbg_host->dev);
5521 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522}
5523
Douglas Gilbertfd321192016-04-25 12:16:33 -04005524static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005525{
5526 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005527 struct sdebug_dev_info *devip;
5528
Douglas Gilbertc4837392016-05-06 00:40:26 -04005529 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005530 devip = (struct sdebug_dev_info *)sdev->hostdata;
5531 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005532 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005533 return -ENODEV;
5534 }
5535 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005536
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005537 if (qdepth < 1)
5538 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005539 /* allow to exceed max host qc_arr elements for testing */
5540 if (qdepth > SDEBUG_CANQUEUE + 10)
5541 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005542 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005543
Douglas Gilbert773642d2016-04-25 12:16:28 -04005544 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005545 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005546 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005547 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005548 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005549 return sdev->queue_depth;
5550}
5551
Douglas Gilbertc4837392016-05-06 00:40:26 -04005552static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005553{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005554 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005555 if (sdebug_every_nth < -1)
5556 sdebug_every_nth = -1;
5557 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005558 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005559 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005560 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005561 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005562 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005563 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005564}
5565
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005566static bool fake_host_busy(struct scsi_cmnd *scp)
5567{
5568 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5569 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5570}
5571
Douglas Gilbertfd321192016-04-25 12:16:33 -04005572static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5573 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005574{
5575 u8 sdeb_i;
5576 struct scsi_device *sdp = scp->device;
5577 const struct opcode_info_t *oip;
5578 const struct opcode_info_t *r_oip;
5579 struct sdebug_dev_info *devip;
5580 u8 *cmd = scp->cmnd;
5581 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5582 int k, na;
5583 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005584 u32 flags;
5585 u16 sa;
5586 u8 opcode = cmd[0];
5587 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005588
5589 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005590 if (sdebug_statistics)
5591 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005592 if (unlikely(sdebug_verbose &&
5593 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005594 char b[120];
5595 int n, len, sb;
5596
5597 len = scp->cmd_len;
5598 sb = (int)sizeof(b);
5599 if (len > 32)
5600 strcpy(b, "too long, over 32 bytes");
5601 else {
5602 for (k = 0, n = 0; k < len && n < sb; ++k)
5603 n += scnprintf(b + n, sb - n, "%02x ",
5604 (u32)cmd[k]);
5605 }
Bart Van Assche458df782018-01-26 08:52:19 -08005606 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5607 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005608 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005609 if (fake_host_busy(scp))
5610 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005611 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005612 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5613 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005614
5615 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5616 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5617 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005618 if (unlikely(!devip)) {
5619 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005620 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005621 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005622 }
5623 na = oip->num_attached;
5624 r_pfp = oip->pfp;
5625 if (na) { /* multiple commands with this opcode */
5626 r_oip = oip;
5627 if (FF_SA & r_oip->flags) {
5628 if (F_SA_LOW & oip->flags)
5629 sa = 0x1f & cmd[1];
5630 else
5631 sa = get_unaligned_be16(cmd + 8);
5632 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5633 if (opcode == oip->opcode && sa == oip->sa)
5634 break;
5635 }
5636 } else { /* since no service action only check opcode */
5637 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5638 if (opcode == oip->opcode)
5639 break;
5640 }
5641 }
5642 if (k > na) {
5643 if (F_SA_LOW & r_oip->flags)
5644 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5645 else if (F_SA_HIGH & r_oip->flags)
5646 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5647 else
5648 mk_sense_invalid_opcode(scp);
5649 goto check_cond;
5650 }
5651 } /* else (when na==0) we assume the oip is a match */
5652 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005653 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005654 mk_sense_invalid_opcode(scp);
5655 goto check_cond;
5656 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005657 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005658 if (sdebug_verbose)
5659 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5660 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005661 mk_sense_invalid_opcode(scp);
5662 goto check_cond;
5663 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005664 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005665 u8 rem;
5666 int j;
5667
5668 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5669 rem = ~oip->len_mask[k] & cmd[k];
5670 if (rem) {
5671 for (j = 7; j >= 0; --j, rem <<= 1) {
5672 if (0x80 & rem)
5673 break;
5674 }
5675 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5676 goto check_cond;
5677 }
5678 }
5679 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005680 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005681 find_first_bit(devip->uas_bm,
5682 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005683 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005684 if (errsts)
5685 goto check_cond;
5686 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005687 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005688 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005689 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005690 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5691 "%s\n", my_name, "initializing command "
5692 "required");
5693 errsts = check_condition_result;
5694 goto fini;
5695 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005696 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005697 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005698 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005699 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005700 return 0; /* ignore command: make trouble */
5701 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005702 if (likely(oip->pfp))
5703 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005704 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5705 errsts = r_pfp(scp, devip);
5706
5707fini:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005708 if (F_DELAY_OVERR & flags)
5709 return schedule_resp(scp, devip, errsts, 0, 0);
5710 else
5711 return schedule_resp(scp, devip, errsts, sdebug_jdelay,
5712 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005713check_cond:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005714 return schedule_resp(scp, devip, check_condition_result, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005715err_out:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005716 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005717}
5718
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005719static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005720 .show_info = scsi_debug_show_info,
5721 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005722 .proc_name = sdebug_proc_name,
5723 .name = "SCSI DEBUG",
5724 .info = scsi_debug_info,
5725 .slave_alloc = scsi_debug_slave_alloc,
5726 .slave_configure = scsi_debug_slave_configure,
5727 .slave_destroy = scsi_debug_slave_destroy,
5728 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005729 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005730 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005731 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005732 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005733 .eh_target_reset_handler = scsi_debug_target_reset,
5734 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005735 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005736 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005737 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005738 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005739 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005740 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005741 .use_clustering = DISABLE_CLUSTERING,
5742 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005743 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005744};
5745
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746static int sdebug_driver_probe(struct device * dev)
5747{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005748 int error = 0;
5749 struct sdebug_host_info *sdbg_host;
5750 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005751 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752
5753 sdbg_host = to_sdebug_host(dev);
5754
Douglas Gilbert773642d2016-04-25 12:16:28 -04005755 sdebug_driver_template.can_queue = sdebug_max_queue;
5756 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005757 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005758 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5759 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005760 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005761 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005763 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005764 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005765 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005766 my_name, submit_queues, nr_cpu_ids);
5767 submit_queues = nr_cpu_ids;
5768 }
5769 /* Decide whether to tell scsi subsystem that we want mq */
5770 /* Following should give the same answer for each host */
Bart Van Assche458df782018-01-26 08:52:19 -08005771 if (shost_use_blk_mq(hpnt))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005772 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773
Douglas Gilbert9a051012017-12-23 12:48:10 -05005774 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005776 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5777 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005779 hpnt->max_id = sdebug_num_tgts;
5780 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005781 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005783 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005784
Douglas Gilbert773642d2016-04-25 12:16:28 -04005785 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005786
Christoph Hellwig8475c812016-09-11 19:35:41 +02005787 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005788 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005789 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005790 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005791 break;
5792
Christoph Hellwig8475c812016-09-11 19:35:41 +02005793 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005794 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005795 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005796 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005797 break;
5798
Christoph Hellwig8475c812016-09-11 19:35:41 +02005799 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005800 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005801 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005802 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005803 break;
5804
5805 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005806 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005807 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005808 break;
5809 }
5810
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005811 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005812
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005813 if (have_dif_prot || sdebug_dix)
5814 pr_info("host protection%s%s%s%s%s%s%s\n",
5815 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5816 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5817 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5818 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5819 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5820 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5821 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005822
Douglas Gilbert773642d2016-04-25 12:16:28 -04005823 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005824 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5825 else
5826 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5827
Douglas Gilbert773642d2016-04-25 12:16:28 -04005828 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5829 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005830 if (sdebug_every_nth) /* need stats counters for every_nth */
5831 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005832 error = scsi_add_host(hpnt, &sdbg_host->dev);
5833 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005834 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005835 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005837 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838 scsi_scan_host(hpnt);
5839
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005840 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841}
5842
5843static int sdebug_driver_remove(struct device * dev)
5844{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005845 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005846 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847
5848 sdbg_host = to_sdebug_host(dev);
5849
5850 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005851 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005852 return -ENODEV;
5853 }
5854
Douglas Gilbert9a051012017-12-23 12:48:10 -05005855 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005857 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5858 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005859 list_del(&sdbg_devinfo->dev_list);
5860 kfree(sdbg_devinfo);
5861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862
Douglas Gilbert9a051012017-12-23 12:48:10 -05005863 scsi_host_put(sdbg_host->shost);
5864 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865}
5866
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005867static int pseudo_lld_bus_match(struct device *dev,
5868 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005870 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005872
5873static struct bus_type pseudo_lld_bus = {
5874 .name = "pseudo",
5875 .match = pseudo_lld_bus_match,
5876 .probe = sdebug_driver_probe,
5877 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005878 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005879};