blob: 42b55d60e844ec882558c2e476daf040c48c64aa [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050097/* Additional Sense Code Qualifier (ASCQ) */
98#define ACK_NAK_TO 0x3
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100/* Default values for driver parameters */
101#define DEF_NUM_HOST 1
102#define DEF_NUM_TGTS 1
103#define DEF_MAX_LUNS 1
104/* With these defaults, this driver will make 1 host with 1 target
105 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
106 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500107#define DEF_ATO 1
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500108#define DEF_CDB_LEN 10
Douglas Gilbertc2206092016-04-25 12:16:31 -0400109#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500111#define DEF_DIF 0
112#define DEF_DIX 0
113#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500115#define DEF_FAKE_RW 0
116#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400117#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500118#define DEF_LBPU 0
119#define DEF_LBPWS 0
120#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600121#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500122#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400123#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500124#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125#define DEF_NUM_PARTS 0
126#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500127#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500128#define DEF_PHYSBLK_EXP 0
Lukas Herbolt86e68282017-01-26 10:00:37 +0100129#define DEF_OPT_XFERLEN_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400130#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200131#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400132#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500133#define DEF_SECTOR_SIZE 512
134#define DEF_UNMAP_ALIGNMENT 0
135#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400136#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
137#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500138#define DEF_VIRTUAL_GB 0
139#define DEF_VPD_USE_HOSTNO 1
140#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500141#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400142#define DEF_STATISTICS false
143#define DEF_SUBMIT_QUEUES 1
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400144#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400145#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400147#define SDEBUG_LUN_0_VAL 0
148
Douglas Gilbert773642d2016-04-25 12:16:28 -0400149/* bit mask values for sdebug_opts */
150#define SDEBUG_OPT_NOISE 1
151#define SDEBUG_OPT_MEDIUM_ERR 2
152#define SDEBUG_OPT_TIMEOUT 4
153#define SDEBUG_OPT_RECOVERED_ERR 8
154#define SDEBUG_OPT_TRANSPORT_ERR 16
155#define SDEBUG_OPT_DIF_ERR 32
156#define SDEBUG_OPT_DIX_ERR 64
157#define SDEBUG_OPT_MAC_TIMEOUT 128
158#define SDEBUG_OPT_SHORT_TRANSFER 0x100
159#define SDEBUG_OPT_Q_NOISE 0x200
160#define SDEBUG_OPT_ALL_TSF 0x400
161#define SDEBUG_OPT_RARE_TSF 0x800
162#define SDEBUG_OPT_N_WCE 0x1000
163#define SDEBUG_OPT_RESET_NOISE 0x2000
164#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800165#define SDEBUG_OPT_HOST_BUSY 0x8000
Douglas Gilbert773642d2016-04-25 12:16:28 -0400166#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
167 SDEBUG_OPT_RESET_NOISE)
168#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
169 SDEBUG_OPT_TRANSPORT_ERR | \
170 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800171 SDEBUG_OPT_SHORT_TRANSFER | \
172 SDEBUG_OPT_HOST_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400174 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400176 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500177 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400178 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 *
180 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400181 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400183 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500184 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400185 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
186 * This will continue on every subsequent command until some other action
187 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
188 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 */
190
Douglas Gilbertfd321192016-04-25 12:16:33 -0400191/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400192 * priority order. In the subset implemented here lower numbers have higher
193 * priority. The UA numbers should be a sequence starting from 0 with
194 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
195#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
196#define SDEBUG_UA_BUS_RESET 1
197#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500198#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500199#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500200#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
201#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
202#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400203
Douglas Gilbert773642d2016-04-25 12:16:28 -0400204/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 * sector on read commands: */
206#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500207#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
210 * or "peripheral device" addressing (value 0) */
211#define SAM2_LUN_ADDRESS_METHOD 0
212
Douglas Gilbertc4837392016-05-06 00:40:26 -0400213/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
214 * (for response) per submit queue at one time. Can be reduced by max_queue
215 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
216 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
217 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
218 * but cannot exceed SDEBUG_CANQUEUE .
219 */
220#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
221#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400222#define DEF_CMD_PER_LUN 255
223
Douglas Gilbertfd321192016-04-25 12:16:33 -0400224#define F_D_IN 1
225#define F_D_OUT 2
226#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
227#define F_D_UNKN 8
228#define F_RL_WLUN_OK 0x10
229#define F_SKIP_UA 0x20
230#define F_DELAY_OVERR 0x40
231#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
232#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
233#define F_INV_OP 0x200
234#define F_FAKE_RW 0x400
235#define F_M_ACCESS 0x800 /* media access */
236
237#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500238#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400239#define FF_SA (F_SA_HIGH | F_SA_LOW)
240
241#define SDEBUG_MAX_PARTS 4
242
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400243#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400244
245
246struct sdebug_dev_info {
247 struct list_head dev_list;
248 unsigned int channel;
249 unsigned int target;
250 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200251 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400252 struct sdebug_host_info *sdbg_host;
253 unsigned long uas_bm[1];
254 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400255 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400256 bool used;
257};
258
259struct sdebug_host_info {
260 struct list_head host_list;
261 struct Scsi_Host *shost;
262 struct device dev;
263 struct list_head dev_info_list;
264};
265
266#define to_sdebug_host(d) \
267 container_of(d, struct sdebug_host_info, dev)
268
269struct sdebug_defer {
270 struct hrtimer hrt;
271 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400272 int sqa_idx; /* index of sdebug_queue array */
273 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
274 int issuing_cpu;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400275};
276
277struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400278 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
279 * instance indicates this slot is in use.
280 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400281 struct sdebug_defer *sd_dp;
282 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400283 unsigned int inj_recovered:1;
284 unsigned int inj_transport:1;
285 unsigned int inj_dif:1;
286 unsigned int inj_dix:1;
287 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800288 unsigned int inj_host_busy:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400289};
290
Douglas Gilbertc4837392016-05-06 00:40:26 -0400291struct sdebug_queue {
292 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
293 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
294 spinlock_t qc_lock;
295 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400296};
297
Douglas Gilbertc4837392016-05-06 00:40:26 -0400298static atomic_t sdebug_cmnd_count; /* number of incoming commands */
299static atomic_t sdebug_completions; /* count of deferred completions */
300static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
301static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
302
Douglas Gilbertfd321192016-04-25 12:16:33 -0400303struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400304 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
305 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400306 u8 opcode; /* if num_attached > 0, preferred */
307 u16 sa; /* service action */
308 u32 flags; /* OR-ed set of SDEB_F_* */
309 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
310 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500311 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
312 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400313};
314
315/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500316enum sdeb_opcode_index {
317 SDEB_I_INVALID_OPCODE = 0,
318 SDEB_I_INQUIRY = 1,
319 SDEB_I_REPORT_LUNS = 2,
320 SDEB_I_REQUEST_SENSE = 3,
321 SDEB_I_TEST_UNIT_READY = 4,
322 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
323 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
324 SDEB_I_LOG_SENSE = 7,
325 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
326 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
327 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
328 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500329 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
330 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500331 SDEB_I_MAINT_IN = 14,
332 SDEB_I_MAINT_OUT = 15,
333 SDEB_I_VERIFY = 16, /* 10 only */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500334 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500335 SDEB_I_RESERVE = 18, /* 6, 10 */
336 SDEB_I_RELEASE = 19, /* 6, 10 */
337 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
338 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
339 SDEB_I_ATA_PT = 22, /* 12, 16 */
340 SDEB_I_SEND_DIAG = 23,
341 SDEB_I_UNMAP = 24,
342 SDEB_I_XDWRITEREAD = 25, /* 10 only */
343 SDEB_I_WRITE_BUFFER = 26,
344 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
345 SDEB_I_SYNC_CACHE = 28, /* 10 only */
346 SDEB_I_COMP_WRITE = 29,
Douglas Gilbert9a051012017-12-23 12:48:10 -0500347 SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500348};
349
Douglas Gilbertc4837392016-05-06 00:40:26 -0400350
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500351static const unsigned char opcode_ind_arr[256] = {
352/* 0x0; 0x0->0x1f: 6 byte cdbs */
353 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
354 0, 0, 0, 0,
355 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
356 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
357 SDEB_I_RELEASE,
358 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
359 SDEB_I_ALLOW_REMOVAL, 0,
360/* 0x20; 0x20->0x3f: 10 byte cdbs */
361 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
362 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
363 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
364 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
365/* 0x40; 0x40->0x5f: 10 byte cdbs */
366 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
368 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
369 SDEB_I_RELEASE,
370 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400371/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
374 0, SDEB_I_VARIABLE_LEN,
375/* 0x80; 0x80->0x9f: 16 byte cdbs */
376 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
377 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
378 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500379 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 -0500380/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
381 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
382 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500383 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
384 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500385 0, 0, 0, 0, 0, 0, 0, 0,
386 0, 0, 0, 0, 0, 0, 0, 0,
387/* 0xc0; 0xc0->0xff: vendor specific */
388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
392};
393
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500394static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
395static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
396static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
397static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
398static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
399static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
400static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
401static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
402static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
403static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
404static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
405static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
406static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
407static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500408static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
409static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500410static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
411static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
412static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500413static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500414static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500415
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500416/*
417 * The following are overflow arrays for cdbs that "hit" the same index in
418 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
419 * should be placed in opcode_info_arr[], the others should be placed here.
420 */
421static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500422 {0, 0x1a, 0, F_D_IN, NULL, NULL,
423 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
424};
425
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500426static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500427 {0, 0x15, 0, F_D_OUT, NULL, NULL,
428 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
429};
430
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500431static const struct opcode_info_t read_iarr[] = {
432 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500433 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500434 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500435 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500436 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500437 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500438 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500439 0xc7, 0, 0, 0, 0} },
440};
441
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500442static const struct opcode_info_t write_iarr[] = {
443 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
444 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
445 0, 0, 0, 0, 0, 0} },
446 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
447 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
448 0, 0, 0} },
449 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
450 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
451 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500452};
453
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500454static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500455 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
456 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500457 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500458};
459
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500460static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
461 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500462 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500463 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
464};
465
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500466static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500467 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500468 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500469 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500470 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500471 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500472 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500473};
474
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500475static const struct opcode_info_t write_same_iarr[] = {
476 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500477 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500478 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500479};
480
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500481static const struct opcode_info_t reserve_iarr[] = {
482 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500483 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
484};
485
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500486static const struct opcode_info_t release_iarr[] = {
487 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500488 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
489};
490
491
492/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
493 * plus the terminating elements for logic that scans this table such as
494 * REPORT SUPPORTED OPERATION CODES. */
495static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
496/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500497 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500498 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500499 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500500 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
501 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
502 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500503 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500504 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
505 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
506 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
507 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500508/* 5 */
509 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
510 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
511 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
512 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
513 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
514 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
515 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500516 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
517 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500518 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500519 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
520 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500521 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
522 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
523 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500524/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500525 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
526 resp_write_dt0, write_iarr, /* WRITE(16) */
527 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
528 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* WRITE(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500529 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
530 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500531 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
532 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
533 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
534 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
535 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA_OUT(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500536 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500537 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
538 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
539 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
540 0xff, 0, 0xc7, 0, 0, 0, 0} },
541/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500542 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
543 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500544 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500545 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
546 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500547 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
548 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
549 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
550 0xff, 0xff} },
551 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
552 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500553 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
554 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500555 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
556 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500557 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
558 0} },
559/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500560 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
561 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500562 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
563 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
564 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
565 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
566 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
567 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500568 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500569 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500570/* 25 */
571 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500572 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500573 0, 0, 0, 0, 0, 0} }, /* XDWRITEREAD(10) */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500574 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
575 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
576 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500577 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
578 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
579 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
580 0, 0, 0, 0, 0} },
581 {0, 0x35, 0, F_DELAY_OVERR | FF_MEDIA_IO, NULL, NULL, /* SYNC_CACHE */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500582 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500583 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500584 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500585 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500586 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500587
588/* 30 */
589 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
590 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
591};
592
Douglas Gilbert773642d2016-04-25 12:16:28 -0400593static int sdebug_add_host = DEF_NUM_HOST;
594static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500595static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400596static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400597static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
598static int sdebug_dif = DEF_DIF;
599static int sdebug_dix = DEF_DIX;
600static int sdebug_dsense = DEF_D_SENSE;
601static int sdebug_every_nth = DEF_EVERY_NTH;
602static int sdebug_fake_rw = DEF_FAKE_RW;
603static unsigned int sdebug_guard = DEF_GUARD;
604static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
605static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400606static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400607static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400608static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400609static int sdebug_no_lun_0 = DEF_NO_LUN_0;
610static int sdebug_no_uld;
611static int sdebug_num_parts = DEF_NUM_PARTS;
612static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
613static int sdebug_opt_blks = DEF_OPT_BLKS;
614static int sdebug_opts = DEF_OPTS;
615static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100616static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400617static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400618static int sdebug_scsi_level = DEF_SCSI_LEVEL;
619static int sdebug_sector_size = DEF_SECTOR_SIZE;
620static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
621static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
622static unsigned int sdebug_lbpu = DEF_LBPU;
623static unsigned int sdebug_lbpws = DEF_LBPWS;
624static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
625static unsigned int sdebug_lbprz = DEF_LBPRZ;
626static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
627static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
628static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
629static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
630static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400631static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400632static bool sdebug_removable = DEF_REMOVABLE;
633static bool sdebug_clustering;
634static bool sdebug_host_lock = DEF_HOST_LOCK;
635static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500636static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400637static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400638static bool have_dif_prot;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400639static bool sdebug_statistics = DEF_STATISTICS;
640static bool sdebug_mq_active;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400642static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643static sector_t sdebug_capacity; /* in sectors */
644
645/* old BIOS stuff, kernel may get rid of them but some mode sense pages
646 may still need them */
647static int sdebug_heads; /* heads per disk */
648static int sdebug_cylinders_per; /* cylinders per surface */
649static int sdebug_sectors_per; /* sectors per cylinder */
650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651static LIST_HEAD(sdebug_host_list);
652static DEFINE_SPINLOCK(sdebug_host_list_lock);
653
Douglas Gilbertfd321192016-04-25 12:16:33 -0400654static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200655static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400656static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Martin K. Petersen44d92692009-10-15 14:45:27 -0400658static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400659static int num_aborts;
660static int num_dev_resets;
661static int num_target_resets;
662static int num_bus_resets;
663static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500664static int dix_writes;
665static int dix_reads;
666static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Douglas Gilbertc4837392016-05-06 00:40:26 -0400668static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
669static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400670
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671static DEFINE_RWLOCK(atomic_rw);
672
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400673static char sdebug_proc_name[] = MY_NAME;
674static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676static struct bus_type pseudo_lld_bus;
677
678static struct device_driver sdebug_driverfs_driver = {
679 .name = sdebug_proc_name,
680 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681};
682
683static const int check_condition_result =
684 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
685
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500686static const int illegal_condition_result =
687 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
688
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400689static const int device_qfull_result =
690 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
691
Douglas Gilbertfd321192016-04-25 12:16:33 -0400692
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400693/* Only do the extra work involved in logical block provisioning if one or
694 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
695 * real reads and writes (i.e. not skipping them for speed).
696 */
697static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400698{
699 return 0 == sdebug_fake_rw &&
700 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
701}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400702
Akinobu Mita14faa942013-09-18 21:27:24 +0900703static void *fake_store(unsigned long long lba)
704{
705 lba = do_div(lba, sdebug_store_sectors);
706
Douglas Gilbert773642d2016-04-25 12:16:28 -0400707 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900708}
709
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200710static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900711{
Arnd Bergmann49413112015-11-20 17:38:28 +0100712 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900713
714 return dif_storep + sector;
715}
716
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900717static void sdebug_max_tgts_luns(void)
718{
719 struct sdebug_host_info *sdbg_host;
720 struct Scsi_Host *hpnt;
721
722 spin_lock(&sdebug_host_list_lock);
723 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
724 hpnt = sdbg_host->shost;
725 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400726 (sdebug_num_tgts > hpnt->this_id))
727 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900728 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400729 hpnt->max_id = sdebug_num_tgts;
730 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300731 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900732 }
733 spin_unlock(&sdebug_host_list_lock);
734}
735
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500736enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
737
738/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400739static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
740 enum sdeb_cmd_data c_d,
741 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500742{
743 unsigned char *sbuff;
744 u8 sks[4];
745 int sl, asc;
746
747 sbuff = scp->sense_buffer;
748 if (!sbuff) {
749 sdev_printk(KERN_ERR, scp->device,
750 "%s: sense_buffer is NULL\n", __func__);
751 return;
752 }
753 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
754 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400755 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500756 memset(sks, 0, sizeof(sks));
757 sks[0] = 0x80;
758 if (c_d)
759 sks[0] |= 0x40;
760 if (in_bit >= 0) {
761 sks[0] |= 0x8;
762 sks[0] |= 0x7 & in_bit;
763 }
764 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400765 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500766 sl = sbuff[7] + 8;
767 sbuff[7] = sl;
768 sbuff[sl] = 0x2;
769 sbuff[sl + 1] = 0x6;
770 memcpy(sbuff + sl + 4, sks, 3);
771 } else
772 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400773 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500774 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
775 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
776 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
777}
778
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400779static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900780{
781 unsigned char *sbuff;
782
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400783 sbuff = scp->sense_buffer;
784 if (!sbuff) {
785 sdev_printk(KERN_ERR, scp->device,
786 "%s: sense_buffer is NULL\n", __func__);
787 return;
788 }
789 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900790
Douglas Gilbert773642d2016-04-25 12:16:28 -0400791 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900792
Douglas Gilbert773642d2016-04-25 12:16:28 -0400793 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400794 sdev_printk(KERN_INFO, scp->device,
795 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
796 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900797}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798
Douglas Gilbertfd321192016-04-25 12:16:33 -0400799static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500800{
801 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
802}
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
805{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400806 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400807 if (0x1261 == cmd)
808 sdev_printk(KERN_INFO, dev,
809 "%s: BLKFLSBUF [0x1261]\n", __func__);
810 else if (0x5331 == cmd)
811 sdev_printk(KERN_INFO, dev,
812 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
813 __func__);
814 else
815 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
816 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 }
818 return -EINVAL;
819 /* return -ENOTTY; // correct return but upsets fdisk */
820}
821
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500822static void config_cdb_len(struct scsi_device *sdev)
823{
824 switch (sdebug_cdb_len) {
825 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
826 sdev->use_10_for_rw = false;
827 sdev->use_16_for_rw = false;
828 sdev->use_10_for_ms = false;
829 break;
830 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
831 sdev->use_10_for_rw = true;
832 sdev->use_16_for_rw = false;
833 sdev->use_10_for_ms = false;
834 break;
835 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
836 sdev->use_10_for_rw = true;
837 sdev->use_16_for_rw = false;
838 sdev->use_10_for_ms = true;
839 break;
840 case 16:
841 sdev->use_10_for_rw = false;
842 sdev->use_16_for_rw = true;
843 sdev->use_10_for_ms = true;
844 break;
845 case 32: /* No knobs to suggest this so same as 16 for now */
846 sdev->use_10_for_rw = false;
847 sdev->use_16_for_rw = true;
848 sdev->use_10_for_ms = true;
849 break;
850 default:
851 pr_warn("unexpected cdb_len=%d, force to 10\n",
852 sdebug_cdb_len);
853 sdev->use_10_for_rw = true;
854 sdev->use_16_for_rw = false;
855 sdev->use_10_for_ms = false;
856 sdebug_cdb_len = 10;
857 break;
858 }
859}
860
861static void all_config_cdb_len(void)
862{
863 struct sdebug_host_info *sdbg_host;
864 struct Scsi_Host *shost;
865 struct scsi_device *sdev;
866
867 spin_lock(&sdebug_host_list_lock);
868 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
869 shost = sdbg_host->shost;
870 shost_for_each_device(sdev, shost) {
871 config_cdb_len(sdev);
872 }
873 }
874 spin_unlock(&sdebug_host_list_lock);
875}
876
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500877static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
878{
879 struct sdebug_host_info *sdhp;
880 struct sdebug_dev_info *dp;
881
882 spin_lock(&sdebug_host_list_lock);
883 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
884 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
885 if ((devip->sdbg_host == dp->sdbg_host) &&
886 (devip->target == dp->target))
887 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
888 }
889 }
890 spin_unlock(&sdebug_host_list_lock);
891}
892
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400893static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400895 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400896
897 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
898 if (k != SDEBUG_NUM_UAS) {
899 const char *cp = NULL;
900
901 switch (k) {
902 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400903 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
904 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400905 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400906 cp = "power on reset";
907 break;
908 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400909 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
910 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400911 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400912 cp = "bus reset";
913 break;
914 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400915 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
916 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400917 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400918 cp = "mode parameters changed";
919 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500920 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400921 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
922 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400923 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500924 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500925 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500926 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400927 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400928 TARGET_CHANGED_ASC,
929 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400930 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500931 cp = "microcode has been changed";
932 break;
933 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400934 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500935 TARGET_CHANGED_ASC,
936 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400937 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500938 cp = "microcode has been changed without reset";
939 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500940 case SDEBUG_UA_LUNS_CHANGED:
941 /*
942 * SPC-3 behavior is to report a UNIT ATTENTION with
943 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
944 * on the target, until a REPORT LUNS command is
945 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400946 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500947 * values as struct scsi_device->scsi_level.
948 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400949 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500950 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400951 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500952 TARGET_CHANGED_ASC,
953 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400954 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500955 cp = "reported luns data has changed";
956 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400957 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400958 pr_warn("unexpected unit attention code=%d\n", k);
959 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400960 cp = "unknown";
961 break;
962 }
963 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400964 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400965 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400966 "%s reports: Unit attention: %s\n",
967 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 return check_condition_result;
969 }
970 return 0;
971}
972
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400973/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900974static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 int arr_len)
976{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900977 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900978 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900980 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900982 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400983 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900984
985 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
986 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700987 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 return 0;
990}
991
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400992/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
993 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
994 * calls, not required to write in ascending offset order. Assumes resid
995 * set to scsi_bufflen() prior to any calls.
996 */
997static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
998 int arr_len, unsigned int off_dst)
999{
1000 int act_len, n;
1001 struct scsi_data_buffer *sdb = scsi_in(scp);
1002 off_t skip = off_dst;
1003
1004 if (sdb->length <= off_dst)
1005 return 0;
1006 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1007 return DID_ERROR << 16;
1008
1009 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1010 arr, arr_len, skip);
1011 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1012 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1013 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1014 sdb->resid = min(sdb->resid, n);
1015 return 0;
1016}
1017
1018/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1019 * 'arr' or -1 if error.
1020 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001021static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1022 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001024 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001026 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001028
1029 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030}
1031
1032
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001033static char sdebug_inq_vendor_id[9] = "Linux ";
1034static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001035static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001036/* Use some locally assigned NAAs for SAS addresses. */
1037static const u64 naa3_comp_a = 0x3222222000000000ULL;
1038static const u64 naa3_comp_b = 0x3333333000000000ULL;
1039static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001041/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001042static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1043 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001044 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001045 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001047 int num, port_a;
1048 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001050 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 /* T10 vendor identifier field format (faked) */
1052 arr[0] = 0x2; /* ASCII */
1053 arr[1] = 0x1;
1054 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001055 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1056 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1058 num = 8 + 16 + dev_id_str_len;
1059 arr[3] = num;
1060 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001061 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001062 if (sdebug_uuid_ctl) {
1063 /* Locally assigned UUID */
1064 arr[num++] = 0x1; /* binary (not necessarily sas) */
1065 arr[num++] = 0xa; /* PIV=0, lu, naa */
1066 arr[num++] = 0x0;
1067 arr[num++] = 0x12;
1068 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1069 arr[num++] = 0x0;
1070 memcpy(arr + num, lu_name, 16);
1071 num += 16;
1072 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001073 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001074 arr[num++] = 0x1; /* binary (not necessarily sas) */
1075 arr[num++] = 0x3; /* PIV=0, lu, naa */
1076 arr[num++] = 0x0;
1077 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001078 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001079 num += 8;
1080 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001081 /* Target relative port number */
1082 arr[num++] = 0x61; /* proto=sas, binary */
1083 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1084 arr[num++] = 0x0; /* reserved */
1085 arr[num++] = 0x4; /* length */
1086 arr[num++] = 0x0; /* reserved */
1087 arr[num++] = 0x0; /* reserved */
1088 arr[num++] = 0x0;
1089 arr[num++] = 0x1; /* relative port A */
1090 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001091 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001092 arr[num++] = 0x61; /* proto=sas, binary */
1093 arr[num++] = 0x93; /* piv=1, target port, naa */
1094 arr[num++] = 0x0;
1095 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001096 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001097 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001098 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001099 arr[num++] = 0x61; /* proto=sas, binary */
1100 arr[num++] = 0x95; /* piv=1, target port group id */
1101 arr[num++] = 0x0;
1102 arr[num++] = 0x4;
1103 arr[num++] = 0;
1104 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001105 put_unaligned_be16(port_group_id, arr + num);
1106 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001107 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001108 arr[num++] = 0x61; /* proto=sas, binary */
1109 arr[num++] = 0xa3; /* piv=1, target device, naa */
1110 arr[num++] = 0x0;
1111 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001112 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001113 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001114 /* SCSI name string: Target device identifier */
1115 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1116 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1117 arr[num++] = 0x0;
1118 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001119 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001120 num += 12;
1121 snprintf(b, sizeof(b), "%08X", target_dev_id);
1122 memcpy(arr + num, b, 8);
1123 num += 8;
1124 memset(arr + num, 0, 4);
1125 num += 4;
1126 return num;
1127}
1128
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001129static unsigned char vpd84_data[] = {
1130/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1131 0x22,0x22,0x22,0x0,0xbb,0x1,
1132 0x22,0x22,0x22,0x0,0xbb,0x2,
1133};
1134
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001135/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001136static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001137{
1138 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1139 return sizeof(vpd84_data);
1140}
1141
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001142/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001143static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001144{
1145 int num = 0;
1146 const char * na1 = "https://www.kernel.org/config";
1147 const char * na2 = "http://www.kernel.org/log";
1148 int plen, olen;
1149
1150 arr[num++] = 0x1; /* lu, storage config */
1151 arr[num++] = 0x0; /* reserved */
1152 arr[num++] = 0x0;
1153 olen = strlen(na1);
1154 plen = olen + 1;
1155 if (plen % 4)
1156 plen = ((plen / 4) + 1) * 4;
1157 arr[num++] = plen; /* length, null termianted, padded */
1158 memcpy(arr + num, na1, olen);
1159 memset(arr + num + olen, 0, plen - olen);
1160 num += plen;
1161
1162 arr[num++] = 0x4; /* lu, logging */
1163 arr[num++] = 0x0; /* reserved */
1164 arr[num++] = 0x0;
1165 olen = strlen(na2);
1166 plen = olen + 1;
1167 if (plen % 4)
1168 plen = ((plen / 4) + 1) * 4;
1169 arr[num++] = plen; /* length, null terminated, padded */
1170 memcpy(arr + num, na2, olen);
1171 memset(arr + num + olen, 0, plen - olen);
1172 num += plen;
1173
1174 return num;
1175}
1176
1177/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001178static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001179{
1180 int num = 0;
1181 int port_a, port_b;
1182
1183 port_a = target_dev_id + 1;
1184 port_b = port_a + 1;
1185 arr[num++] = 0x0; /* reserved */
1186 arr[num++] = 0x0; /* reserved */
1187 arr[num++] = 0x0;
1188 arr[num++] = 0x1; /* relative port 1 (primary) */
1189 memset(arr + num, 0, 6);
1190 num += 6;
1191 arr[num++] = 0x0;
1192 arr[num++] = 12; /* length tp descriptor */
1193 /* naa-5 target port identifier (A) */
1194 arr[num++] = 0x61; /* proto=sas, binary */
1195 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1196 arr[num++] = 0x0; /* reserved */
1197 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001198 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001199 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001200 arr[num++] = 0x0; /* reserved */
1201 arr[num++] = 0x0; /* reserved */
1202 arr[num++] = 0x0;
1203 arr[num++] = 0x2; /* relative port 2 (secondary) */
1204 memset(arr + num, 0, 6);
1205 num += 6;
1206 arr[num++] = 0x0;
1207 arr[num++] = 12; /* length tp descriptor */
1208 /* naa-5 target port identifier (B) */
1209 arr[num++] = 0x61; /* proto=sas, binary */
1210 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1211 arr[num++] = 0x0; /* reserved */
1212 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001213 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001214 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001215
1216 return num;
1217}
1218
1219
1220static unsigned char vpd89_data[] = {
1221/* from 4th byte */ 0,0,0,0,
1222'l','i','n','u','x',' ',' ',' ',
1223'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1224'1','2','3','4',
12250x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12260xec,0,0,0,
12270x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12280,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12290x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12300x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12310x53,0x41,
12320x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12330x20,0x20,
12340x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12350x10,0x80,
12360,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12370x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12380x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12390,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12400x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12410x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12420,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12450,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12460x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12470,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12480xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12490,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
12500,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12510,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12520,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12530,0,0,0,0,0,0,0,0,0,0,0,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,
12570,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12590,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12610,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1262};
1263
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001264/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001265static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001266{
1267 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1268 return sizeof(vpd89_data);
1269}
1270
1271
1272static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001273 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1274 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1275 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1276 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001277};
1278
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001279/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001280static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001281{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001282 unsigned int gran;
1283
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001284 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001285
1286 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001287 if (sdebug_opt_xferlen_exp != 0 &&
1288 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1289 gran = 1 << sdebug_opt_xferlen_exp;
1290 else
1291 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001292 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001293
1294 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001295 if (sdebug_store_sectors > 0x400)
1296 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001297
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001298 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001299 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001300
Douglas Gilbert773642d2016-04-25 12:16:28 -04001301 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001302 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001303 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001304
1305 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001306 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001307 }
1308
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001309 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001310 if (sdebug_unmap_alignment) {
1311 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001312 arr[28] |= 0x80; /* UGAVALID */
1313 }
1314
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001315 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001316 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001317
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001318 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001319 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001320
1321 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001322
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001323 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324}
1325
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001326/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001327static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001328{
1329 memset(arr, 0, 0x3c);
1330 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001331 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1332 arr[2] = 0;
1333 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001334
1335 return 0x3c;
1336}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001338/* Logical block provisioning VPD page (SBC-4) */
1339static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001340{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001341 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001342 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001343 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001344 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001345 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001346 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001347 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001348 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001349 if (sdebug_lbprz && scsi_debug_lbp())
1350 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1351 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1352 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1353 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001354 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001355}
1356
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001358#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001360static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361{
1362 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001363 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001364 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001365 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001366 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Douglas Gilbert773642d2016-04-25 12:16:28 -04001368 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001369 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1370 if (! arr)
1371 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001372 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001373 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001374 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001375 pq_pdt = TYPE_WLUN; /* present, wlun */
1376 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1377 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001378 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001379 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 arr[0] = pq_pdt;
1381 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001382 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001383 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 return check_condition_result;
1385 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001386 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001387 char lu_id_str[6];
1388 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001390 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1391 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001392 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001393 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001394 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001395 (devip->target * 1000) + devip->lun);
1396 target_dev_id = ((host_no + 1) * 2000) +
1397 (devip->target * 1000) - 3;
1398 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001400 arr[1] = cmd[2]; /*sanity */
1401 n = 4;
1402 arr[n++] = 0x0; /* this page */
1403 arr[n++] = 0x80; /* unit serial number */
1404 arr[n++] = 0x83; /* device identification */
1405 arr[n++] = 0x84; /* software interface ident. */
1406 arr[n++] = 0x85; /* management network addresses */
1407 arr[n++] = 0x86; /* extended inquiry */
1408 arr[n++] = 0x87; /* mode page policy */
1409 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001410 if (is_disk) { /* SBC only */
1411 arr[n++] = 0x89; /* ATA information */
1412 arr[n++] = 0xb0; /* Block limits */
1413 arr[n++] = 0xb1; /* Block characteristics */
1414 arr[n++] = 0xb2; /* Logical Block Prov */
1415 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001416 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001418 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001420 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001422 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001423 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1424 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001425 lu_id_str, len,
1426 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001427 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1428 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001429 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001430 } else if (0x85 == cmd[2]) { /* Management network addresses */
1431 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001432 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001433 } else if (0x86 == cmd[2]) { /* extended inquiry */
1434 arr[1] = cmd[2]; /*sanity */
1435 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001436 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001437 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001438 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001439 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1440 else
1441 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001442 arr[5] = 0x7; /* head of q, ordered + simple q's */
1443 } else if (0x87 == cmd[2]) { /* mode page policy */
1444 arr[1] = cmd[2]; /*sanity */
1445 arr[3] = 0x8; /* number of following entries */
1446 arr[4] = 0x2; /* disconnect-reconnect mp */
1447 arr[6] = 0x80; /* mlus, shared */
1448 arr[8] = 0x18; /* protocol specific lu */
1449 arr[10] = 0x82; /* mlus, per initiator port */
1450 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1451 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001452 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1453 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001454 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001455 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001456 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001457 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001458 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001459 arr[3] = inquiry_vpd_b0(&arr[4]);
1460 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001461 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001462 arr[3] = inquiry_vpd_b1(&arr[4]);
1463 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001464 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001465 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001467 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001468 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 return check_condition_result;
1470 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001471 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001472 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001473 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001474 kfree(arr);
1475 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 }
1477 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001478 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1479 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 arr[3] = 2; /* response_data_format==2 */
1481 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001482 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001483 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001484 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001485 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001487 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001488 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1489 memcpy(&arr[16], sdebug_inq_product_id, 16);
1490 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001491 /* Use Vendor Specific area to place driver date in ASCII hex */
1492 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001494 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1495 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001497 if (is_disk) { /* SBC-4 no version claimed */
1498 put_unaligned_be16(0x600, arr + n);
1499 n += 2;
1500 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1501 put_unaligned_be16(0x525, arr + n);
1502 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001504 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001505 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001507 kfree(arr);
1508 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509}
1510
Douglas Gilbertfd321192016-04-25 12:16:33 -04001511static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1512 0, 0, 0x0, 0x0};
1513
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514static int resp_requests(struct scsi_cmnd * scp,
1515 struct sdebug_dev_info * devip)
1516{
1517 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001518 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001519 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001520 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 int len = 18;
1522
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001523 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001524 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001525 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001526 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001527 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001528 arr[0] = 0x72;
1529 arr[1] = 0x0; /* NO_SENSE in sense_key */
1530 arr[2] = THRESHOLD_EXCEEDED;
1531 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001532 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001533 } else {
1534 arr[0] = 0x70;
1535 arr[2] = 0x0; /* NO_SENSE in sense_key */
1536 arr[7] = 0xa; /* 18 byte sense buffer */
1537 arr[12] = THRESHOLD_EXCEEDED;
1538 arr[13] = 0xff; /* TEST set and MRIE==6 */
1539 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001540 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001541 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001542 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001543 ; /* have sense and formats match */
1544 else if (arr[0] <= 0x70) {
1545 if (dsense) {
1546 memset(arr, 0, 8);
1547 arr[0] = 0x72;
1548 len = 8;
1549 } else {
1550 memset(arr, 0, 18);
1551 arr[0] = 0x70;
1552 arr[7] = 0xa;
1553 }
1554 } else if (dsense) {
1555 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001556 arr[0] = 0x72;
1557 arr[1] = sbuff[2]; /* sense key */
1558 arr[2] = sbuff[12]; /* asc */
1559 arr[3] = sbuff[13]; /* ascq */
1560 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001561 } else {
1562 memset(arr, 0, 18);
1563 arr[0] = 0x70;
1564 arr[2] = sbuff[1];
1565 arr[7] = 0xa;
1566 arr[12] = sbuff[1];
1567 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001568 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001569
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001570 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001571 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 return fill_from_dev_buffer(scp, arr, len);
1573}
1574
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001575static int resp_start_stop(struct scsi_cmnd * scp,
1576 struct sdebug_dev_info * devip)
1577{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001578 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001579 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001580
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001581 power_cond = (cmd[4] & 0xf0) >> 4;
1582 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001583 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001584 return check_condition_result;
1585 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001586 stop = !(cmd[4] & 1);
1587 atomic_xchg(&devip->stopped, stop);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001588 return 0;
1589}
1590
FUJITA Tomonori28898872008-03-30 00:59:55 +09001591static sector_t get_sdebug_capacity(void)
1592{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001593 static const unsigned int gibibyte = 1073741824;
1594
1595 if (sdebug_virtual_gb > 0)
1596 return (sector_t)sdebug_virtual_gb *
1597 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001598 else
1599 return sdebug_store_sectors;
1600}
1601
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602#define SDEBUG_READCAP_ARR_SZ 8
1603static int resp_readcap(struct scsi_cmnd * scp,
1604 struct sdebug_dev_info * devip)
1605{
1606 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001607 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001609 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001610 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001612 if (sdebug_capacity < 0xffffffff) {
1613 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001614 put_unaligned_be32(capac, arr + 0);
1615 } else
1616 put_unaligned_be32(0xffffffff, arr + 0);
1617 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1619}
1620
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001621#define SDEBUG_READCAP16_ARR_SZ 32
1622static int resp_readcap16(struct scsi_cmnd * scp,
1623 struct sdebug_dev_info * devip)
1624{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001625 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001626 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001627 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001628
Douglas Gilbert773642d2016-04-25 12:16:28 -04001629 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001630 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001631 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001632 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001633 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1634 put_unaligned_be32(sdebug_sector_size, arr + 8);
1635 arr[13] = sdebug_physblk_exp & 0xf;
1636 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001637
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001638 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001639 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001640 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1641 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1642 * in the wider field maps to 0 in this field.
1643 */
1644 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1645 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001646 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001647
Douglas Gilbert773642d2016-04-25 12:16:28 -04001648 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001649
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001650 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001651 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001652 arr[12] |= 1; /* PROT_EN */
1653 }
1654
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001655 return fill_from_dev_buffer(scp, arr,
1656 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1657}
1658
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001659#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1660
1661static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1662 struct sdebug_dev_info * devip)
1663{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001664 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001665 unsigned char * arr;
1666 int host_no = devip->sdbg_host->shost->host_no;
1667 int n, ret, alen, rlen;
1668 int port_group_a, port_group_b, port_a, port_b;
1669
Douglas Gilbert773642d2016-04-25 12:16:28 -04001670 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001671 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1672 if (! arr)
1673 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001674 /*
1675 * EVPD page 0x88 states we have two ports, one
1676 * real and a fake port with no device connected.
1677 * So we create two port groups with one port each
1678 * and set the group with port B to unavailable.
1679 */
1680 port_a = 0x1; /* relative port A */
1681 port_b = 0x2; /* relative port B */
1682 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001683 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001684 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001685 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001686
1687 /*
1688 * The asymmetric access state is cycled according to the host_id.
1689 */
1690 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001691 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001692 arr[n++] = host_no % 3; /* Asymm access state */
1693 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001694 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001695 arr[n++] = 0x0; /* Active/Optimized path */
1696 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001697 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001698 put_unaligned_be16(port_group_a, arr + n);
1699 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001700 arr[n++] = 0; /* Reserved */
1701 arr[n++] = 0; /* Status code */
1702 arr[n++] = 0; /* Vendor unique */
1703 arr[n++] = 0x1; /* One port per group */
1704 arr[n++] = 0; /* Reserved */
1705 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001706 put_unaligned_be16(port_a, arr + n);
1707 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001708 arr[n++] = 3; /* Port unavailable */
1709 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001710 put_unaligned_be16(port_group_b, arr + n);
1711 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001712 arr[n++] = 0; /* Reserved */
1713 arr[n++] = 0; /* Status code */
1714 arr[n++] = 0; /* Vendor unique */
1715 arr[n++] = 0x1; /* One port per group */
1716 arr[n++] = 0; /* Reserved */
1717 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001718 put_unaligned_be16(port_b, arr + n);
1719 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001720
1721 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001722 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001723
1724 /*
1725 * Return the smallest value of either
1726 * - The allocated length
1727 * - The constructed command length
1728 * - The maximum array size
1729 */
1730 rlen = min(alen,n);
1731 ret = fill_from_dev_buffer(scp, arr,
1732 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1733 kfree(arr);
1734 return ret;
1735}
1736
Douglas Gilbertfd321192016-04-25 12:16:33 -04001737static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1738 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001739{
1740 bool rctd;
1741 u8 reporting_opts, req_opcode, sdeb_i, supp;
1742 u16 req_sa, u;
1743 u32 alloc_len, a_len;
1744 int k, offset, len, errsts, count, bump, na;
1745 const struct opcode_info_t *oip;
1746 const struct opcode_info_t *r_oip;
1747 u8 *arr;
1748 u8 *cmd = scp->cmnd;
1749
1750 rctd = !!(cmd[2] & 0x80);
1751 reporting_opts = cmd[2] & 0x7;
1752 req_opcode = cmd[3];
1753 req_sa = get_unaligned_be16(cmd + 4);
1754 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001755 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001756 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1757 return check_condition_result;
1758 }
1759 if (alloc_len > 8192)
1760 a_len = 8192;
1761 else
1762 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001763 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001764 if (NULL == arr) {
1765 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1766 INSUFF_RES_ASCQ);
1767 return check_condition_result;
1768 }
1769 switch (reporting_opts) {
1770 case 0: /* all commands */
1771 /* count number of commands */
1772 for (count = 0, oip = opcode_info_arr;
1773 oip->num_attached != 0xff; ++oip) {
1774 if (F_INV_OP & oip->flags)
1775 continue;
1776 count += (oip->num_attached + 1);
1777 }
1778 bump = rctd ? 20 : 8;
1779 put_unaligned_be32(count * bump, arr);
1780 for (offset = 4, oip = opcode_info_arr;
1781 oip->num_attached != 0xff && offset < a_len; ++oip) {
1782 if (F_INV_OP & oip->flags)
1783 continue;
1784 na = oip->num_attached;
1785 arr[offset] = oip->opcode;
1786 put_unaligned_be16(oip->sa, arr + offset + 2);
1787 if (rctd)
1788 arr[offset + 5] |= 0x2;
1789 if (FF_SA & oip->flags)
1790 arr[offset + 5] |= 0x1;
1791 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1792 if (rctd)
1793 put_unaligned_be16(0xa, arr + offset + 8);
1794 r_oip = oip;
1795 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1796 if (F_INV_OP & oip->flags)
1797 continue;
1798 offset += bump;
1799 arr[offset] = oip->opcode;
1800 put_unaligned_be16(oip->sa, arr + offset + 2);
1801 if (rctd)
1802 arr[offset + 5] |= 0x2;
1803 if (FF_SA & oip->flags)
1804 arr[offset + 5] |= 0x1;
1805 put_unaligned_be16(oip->len_mask[0],
1806 arr + offset + 6);
1807 if (rctd)
1808 put_unaligned_be16(0xa,
1809 arr + offset + 8);
1810 }
1811 oip = r_oip;
1812 offset += bump;
1813 }
1814 break;
1815 case 1: /* one command: opcode only */
1816 case 2: /* one command: opcode plus service action */
1817 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1818 sdeb_i = opcode_ind_arr[req_opcode];
1819 oip = &opcode_info_arr[sdeb_i];
1820 if (F_INV_OP & oip->flags) {
1821 supp = 1;
1822 offset = 4;
1823 } else {
1824 if (1 == reporting_opts) {
1825 if (FF_SA & oip->flags) {
1826 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1827 2, 2);
1828 kfree(arr);
1829 return check_condition_result;
1830 }
1831 req_sa = 0;
1832 } else if (2 == reporting_opts &&
1833 0 == (FF_SA & oip->flags)) {
1834 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1835 kfree(arr); /* point at requested sa */
1836 return check_condition_result;
1837 }
1838 if (0 == (FF_SA & oip->flags) &&
1839 req_opcode == oip->opcode)
1840 supp = 3;
1841 else if (0 == (FF_SA & oip->flags)) {
1842 na = oip->num_attached;
1843 for (k = 0, oip = oip->arrp; k < na;
1844 ++k, ++oip) {
1845 if (req_opcode == oip->opcode)
1846 break;
1847 }
1848 supp = (k >= na) ? 1 : 3;
1849 } else if (req_sa != oip->sa) {
1850 na = oip->num_attached;
1851 for (k = 0, oip = oip->arrp; k < na;
1852 ++k, ++oip) {
1853 if (req_sa == oip->sa)
1854 break;
1855 }
1856 supp = (k >= na) ? 1 : 3;
1857 } else
1858 supp = 3;
1859 if (3 == supp) {
1860 u = oip->len_mask[0];
1861 put_unaligned_be16(u, arr + 2);
1862 arr[4] = oip->opcode;
1863 for (k = 1; k < u; ++k)
1864 arr[4 + k] = (k < 16) ?
1865 oip->len_mask[k] : 0xff;
1866 offset = 4 + u;
1867 } else
1868 offset = 4;
1869 }
1870 arr[1] = (rctd ? 0x80 : 0) | supp;
1871 if (rctd) {
1872 put_unaligned_be16(0xa, arr + offset);
1873 offset += 12;
1874 }
1875 break;
1876 default:
1877 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1878 kfree(arr);
1879 return check_condition_result;
1880 }
1881 offset = (offset < a_len) ? offset : a_len;
1882 len = (offset < alloc_len) ? offset : alloc_len;
1883 errsts = fill_from_dev_buffer(scp, arr, len);
1884 kfree(arr);
1885 return errsts;
1886}
1887
Douglas Gilbertfd321192016-04-25 12:16:33 -04001888static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1889 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001890{
1891 bool repd;
1892 u32 alloc_len, len;
1893 u8 arr[16];
1894 u8 *cmd = scp->cmnd;
1895
1896 memset(arr, 0, sizeof(arr));
1897 repd = !!(cmd[2] & 0x80);
1898 alloc_len = get_unaligned_be32(cmd + 6);
1899 if (alloc_len < 4) {
1900 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1901 return check_condition_result;
1902 }
1903 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1904 arr[1] = 0x1; /* ITNRS */
1905 if (repd) {
1906 arr[3] = 0xc;
1907 len = 16;
1908 } else
1909 len = 4;
1910
1911 len = (len < alloc_len) ? len : alloc_len;
1912 return fill_from_dev_buffer(scp, arr, len);
1913}
1914
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915/* <<Following mode page info copied from ST318451LW>> */
1916
1917static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1918{ /* Read-Write Error Recovery page for mode_sense */
1919 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1920 5, 0, 0xff, 0xff};
1921
1922 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1923 if (1 == pcontrol)
1924 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1925 return sizeof(err_recov_pg);
1926}
1927
1928static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1929{ /* Disconnect-Reconnect page for mode_sense */
1930 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1931 0, 0, 0, 0, 0, 0, 0, 0};
1932
1933 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1934 if (1 == pcontrol)
1935 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1936 return sizeof(disconnect_pg);
1937}
1938
1939static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1940{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001941 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1942 0, 0, 0, 0, 0, 0, 0, 0,
1943 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
Martin K. Petersen597136a2008-06-05 00:12:59 -04001945 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001946 put_unaligned_be16(sdebug_sectors_per, p + 10);
1947 put_unaligned_be16(sdebug_sector_size, p + 12);
1948 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001949 p[20] |= 0x20; /* should agree with INQUIRY */
1950 if (1 == pcontrol)
1951 memset(p + 2, 0, sizeof(format_pg) - 2);
1952 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953}
1954
Douglas Gilbertfd321192016-04-25 12:16:33 -04001955static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1956 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1957 0, 0, 0, 0};
1958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1960{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001961 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1962 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1963 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1965
Douglas Gilbert773642d2016-04-25 12:16:28 -04001966 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001967 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 memcpy(p, caching_pg, sizeof(caching_pg));
1969 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001970 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1971 else if (2 == pcontrol)
1972 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 return sizeof(caching_pg);
1974}
1975
Douglas Gilbertfd321192016-04-25 12:16:33 -04001976static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1977 0, 0, 0x2, 0x4b};
1978
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1980{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001981 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05001982 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001983 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 0, 0, 0x2, 0x4b};
1985
Douglas Gilbert773642d2016-04-25 12:16:28 -04001986 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001988 else
1989 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001990
Douglas Gilbert773642d2016-04-25 12:16:28 -04001991 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001992 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1993
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1995 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001996 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1997 else if (2 == pcontrol)
1998 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 return sizeof(ctrl_m_pg);
2000}
2001
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002002
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
2004{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002005 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2006 0, 0, 0x0, 0x0};
2007 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2008 0, 0, 0x0, 0x0};
2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2011 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002012 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2013 else if (2 == pcontrol)
2014 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 return sizeof(iec_m_pg);
2016}
2017
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002018static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
2019{ /* SAS SSP mode page - short format for mode_sense */
2020 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2021 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2022
2023 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2024 if (1 == pcontrol)
2025 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2026 return sizeof(sas_sf_m_pg);
2027}
2028
2029
2030static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
2031 int target_dev_id)
2032{ /* SAS phy control and discover mode page for mode_sense */
2033 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2034 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002035 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2036 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002037 0x2, 0, 0, 0, 0, 0, 0, 0,
2038 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2039 0, 0, 0, 0, 0, 0, 0, 0,
2040 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002041 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2042 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002043 0x3, 0, 0, 0, 0, 0, 0, 0,
2044 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2045 0, 0, 0, 0, 0, 0, 0, 0,
2046 };
2047 int port_a, port_b;
2048
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002049 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2050 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2051 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2052 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002053 port_a = target_dev_id + 1;
2054 port_b = port_a + 1;
2055 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002056 put_unaligned_be32(port_a, p + 20);
2057 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002058 if (1 == pcontrol)
2059 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2060 return sizeof(sas_pcd_m_pg);
2061}
2062
2063static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
2064{ /* SAS SSP shared protocol specific port mode subpage */
2065 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2066 0, 0, 0, 0, 0, 0, 0, 0,
2067 };
2068
2069 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2070 if (1 == pcontrol)
2071 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2072 return sizeof(sas_sha_m_pg);
2073}
2074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075#define SDEBUG_MAX_MSENSE_SZ 256
2076
Douglas Gilbertfd321192016-04-25 12:16:33 -04002077static int resp_mode_sense(struct scsi_cmnd *scp,
2078 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079{
Douglas Gilbert23183912006-09-16 20:30:47 -04002080 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002082 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002083 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 unsigned char * ap;
2085 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002086 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002087 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002089 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 pcontrol = (cmd[2] & 0xc0) >> 6;
2091 pcode = cmd[2] & 0x3f;
2092 subpcode = cmd[3];
2093 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002094 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2095 is_disk = (sdebug_ptype == TYPE_DISK);
2096 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002097 bd_len = llbaa ? 16 : 8;
2098 else
2099 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002100 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2102 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002103 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 return check_condition_result;
2105 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002106 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2107 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002108 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002109 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002110 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002111 else
2112 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 if (msense_6) {
2114 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002115 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 offset = 4;
2117 } else {
2118 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002119 if (16 == bd_len)
2120 arr[4] = 0x1; /* set LONGLBA bit */
2121 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 offset = 8;
2123 }
2124 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002125 if ((bd_len > 0) && (!sdebug_capacity))
2126 sdebug_capacity = get_sdebug_capacity();
2127
Douglas Gilbert23183912006-09-16 20:30:47 -04002128 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002129 if (sdebug_capacity > 0xfffffffe)
2130 put_unaligned_be32(0xffffffff, ap + 0);
2131 else
2132 put_unaligned_be32(sdebug_capacity, ap + 0);
2133 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002134 offset += bd_len;
2135 ap = arr + offset;
2136 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002137 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2138 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002139 offset += bd_len;
2140 ap = arr + offset;
2141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002143 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2144 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002145 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 return check_condition_result;
2147 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002148 bad_pcode = false;
2149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 switch (pcode) {
2151 case 0x1: /* Read-Write error recovery page, direct access */
2152 len = resp_err_recov_pg(ap, pcontrol, target);
2153 offset += len;
2154 break;
2155 case 0x2: /* Disconnect-Reconnect page, all devices */
2156 len = resp_disconnect_pg(ap, pcontrol, target);
2157 offset += len;
2158 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002159 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002160 if (is_disk) {
2161 len = resp_format_pg(ap, pcontrol, target);
2162 offset += len;
2163 } else
2164 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002165 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002167 if (is_disk) {
2168 len = resp_caching_pg(ap, pcontrol, target);
2169 offset += len;
2170 } else
2171 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 break;
2173 case 0xa: /* Control Mode page, all devices */
2174 len = resp_ctrl_m_pg(ap, pcontrol, target);
2175 offset += len;
2176 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002177 case 0x19: /* if spc==1 then sas phy, control+discover */
2178 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002179 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002180 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002181 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002182 len = 0;
2183 if ((0x0 == subpcode) || (0xff == subpcode))
2184 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2185 if ((0x1 == subpcode) || (0xff == subpcode))
2186 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2187 target_dev_id);
2188 if ((0x2 == subpcode) || (0xff == subpcode))
2189 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2190 offset += len;
2191 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 case 0x1c: /* Informational Exceptions Mode page, all devices */
2193 len = resp_iec_m_pg(ap, pcontrol, target);
2194 offset += len;
2195 break;
2196 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002197 if ((0 == subpcode) || (0xff == subpcode)) {
2198 len = resp_err_recov_pg(ap, pcontrol, target);
2199 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002200 if (is_disk) {
2201 len += resp_format_pg(ap + len, pcontrol,
2202 target);
2203 len += resp_caching_pg(ap + len, pcontrol,
2204 target);
2205 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002206 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2207 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2208 if (0xff == subpcode) {
2209 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2210 target, target_dev_id);
2211 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2212 }
2213 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002214 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002215 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002216 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002217 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 break;
2220 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002221 bad_pcode = true;
2222 break;
2223 }
2224 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002225 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 return check_condition_result;
2227 }
2228 if (msense_6)
2229 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002230 else
2231 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2233}
2234
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002235#define SDEBUG_MAX_MSELECT_SZ 512
2236
Douglas Gilbertfd321192016-04-25 12:16:33 -04002237static int resp_mode_select(struct scsi_cmnd *scp,
2238 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002239{
2240 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002241 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002242 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002243 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002244 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002245
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002246 memset(arr, 0, sizeof(arr));
2247 pf = cmd[1] & 0x10;
2248 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002249 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002250 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002251 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002252 return check_condition_result;
2253 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002254 res = fetch_to_dev_buffer(scp, arr, param_len);
2255 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002256 return DID_ERROR << 16;
2257 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002258 sdev_printk(KERN_INFO, scp->device,
2259 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2260 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002261 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2262 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002263 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002264 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002265 return check_condition_result;
2266 }
2267 off = bd_len + (mselect6 ? 4 : 8);
2268 mpage = arr[off] & 0x3f;
2269 ps = !!(arr[off] & 0x80);
2270 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002271 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002272 return check_condition_result;
2273 }
2274 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002275 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002276 (arr[off + 1] + 2);
2277 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002278 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002279 PARAMETER_LIST_LENGTH_ERR, 0);
2280 return check_condition_result;
2281 }
2282 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002283 case 0x8: /* Caching Mode page */
2284 if (caching_pg[1] == arr[off + 1]) {
2285 memcpy(caching_pg + 2, arr + off + 2,
2286 sizeof(caching_pg) - 2);
2287 goto set_mode_changed_ua;
2288 }
2289 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002290 case 0xa: /* Control Mode page */
2291 if (ctrl_m_pg[1] == arr[off + 1]) {
2292 memcpy(ctrl_m_pg + 2, arr + off + 2,
2293 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002294 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002295 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002296 }
2297 break;
2298 case 0x1c: /* Informational Exceptions Mode page */
2299 if (iec_m_pg[1] == arr[off + 1]) {
2300 memcpy(iec_m_pg + 2, arr + off + 2,
2301 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002302 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002303 }
2304 break;
2305 default:
2306 break;
2307 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002308 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002309 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002310set_mode_changed_ua:
2311 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2312 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002313}
2314
2315static int resp_temp_l_pg(unsigned char * arr)
2316{
2317 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2318 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2319 };
2320
Douglas Gilbert9a051012017-12-23 12:48:10 -05002321 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2322 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002323}
2324
2325static int resp_ie_l_pg(unsigned char * arr)
2326{
2327 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2328 };
2329
Douglas Gilbert9a051012017-12-23 12:48:10 -05002330 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002331 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2332 arr[4] = THRESHOLD_EXCEEDED;
2333 arr[5] = 0xff;
2334 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002335 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002336}
2337
2338#define SDEBUG_MAX_LSENSE_SZ 512
2339
Douglas Gilbert9a051012017-12-23 12:48:10 -05002340static int resp_log_sense(struct scsi_cmnd *scp,
2341 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002342{
Bart Van Asscheab172412017-08-25 13:46:42 -07002343 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002344 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002345 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002346
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002347 memset(arr, 0, sizeof(arr));
2348 ppc = cmd[1] & 0x2;
2349 sp = cmd[1] & 0x1;
2350 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002351 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002352 return check_condition_result;
2353 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002354 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002355 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002356 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002357 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002358 if (0 == subpcode) {
2359 switch (pcode) {
2360 case 0x0: /* Supported log pages log page */
2361 n = 4;
2362 arr[n++] = 0x0; /* this page */
2363 arr[n++] = 0xd; /* Temperature */
2364 arr[n++] = 0x2f; /* Informational exceptions */
2365 arr[3] = n - 4;
2366 break;
2367 case 0xd: /* Temperature log page */
2368 arr[3] = resp_temp_l_pg(arr + 4);
2369 break;
2370 case 0x2f: /* Informational exceptions log page */
2371 arr[3] = resp_ie_l_pg(arr + 4);
2372 break;
2373 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002374 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002375 return check_condition_result;
2376 }
2377 } else if (0xff == subpcode) {
2378 arr[0] |= 0x40;
2379 arr[1] = subpcode;
2380 switch (pcode) {
2381 case 0x0: /* Supported log pages and subpages log page */
2382 n = 4;
2383 arr[n++] = 0x0;
2384 arr[n++] = 0x0; /* 0,0 page */
2385 arr[n++] = 0x0;
2386 arr[n++] = 0xff; /* this page */
2387 arr[n++] = 0xd;
2388 arr[n++] = 0x0; /* Temperature */
2389 arr[n++] = 0x2f;
2390 arr[n++] = 0x0; /* Informational exceptions */
2391 arr[3] = n - 4;
2392 break;
2393 case 0xd: /* Temperature subpages */
2394 n = 4;
2395 arr[n++] = 0xd;
2396 arr[n++] = 0x0; /* Temperature */
2397 arr[3] = n - 4;
2398 break;
2399 case 0x2f: /* Informational exceptions subpages */
2400 n = 4;
2401 arr[n++] = 0x2f;
2402 arr[n++] = 0x0; /* Informational exceptions */
2403 arr[3] = n - 4;
2404 break;
2405 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002406 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002407 return check_condition_result;
2408 }
2409 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002410 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002411 return check_condition_result;
2412 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002413 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002414 return fill_from_dev_buffer(scp, arr,
2415 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2416}
2417
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002418static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002419 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002421 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002422 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 return check_condition_result;
2424 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002425 /* transfer length excessive (tie in to block limits VPD page) */
2426 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002427 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002428 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002429 return check_condition_result;
2430 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002431 return 0;
2432}
2433
Akinobu Mitaa4517512013-07-08 16:01:57 -07002434/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002435static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2436 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002437{
2438 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002439 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002440 struct scsi_data_buffer *sdb;
2441 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002442
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002443 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002444 sdb = scsi_out(scmd);
2445 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002446 } else {
2447 sdb = scsi_in(scmd);
2448 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002449 }
2450
2451 if (!sdb->length)
2452 return 0;
2453 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2454 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002455
2456 block = do_div(lba, sdebug_store_sectors);
2457 if (block + num > sdebug_store_sectors)
2458 rest = block + num - sdebug_store_sectors;
2459
Dave Gordon386ecb12015-06-30 14:58:57 -07002460 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002461 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002462 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002463 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002464 return ret;
2465
2466 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002467 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002468 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002469 sg_skip + ((num - rest) * sdebug_sector_size),
2470 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002471 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002472
2473 return ret;
2474}
2475
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002476/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2477 * arr into fake_store(lba,num) and return true. If comparison fails then
2478 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002479static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002480{
2481 bool res;
2482 u64 block, rest = 0;
2483 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002484 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002485
2486 block = do_div(lba, store_blks);
2487 if (block + num > store_blks)
2488 rest = block + num - store_blks;
2489
2490 res = !memcmp(fake_storep + (block * lb_size), arr,
2491 (num - rest) * lb_size);
2492 if (!res)
2493 return res;
2494 if (rest)
2495 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2496 rest * lb_size);
2497 if (!res)
2498 return res;
2499 arr += num * lb_size;
2500 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2501 if (rest)
2502 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2503 rest * lb_size);
2504 return res;
2505}
2506
Akinobu Mita51d648a2013-09-18 21:27:28 +09002507static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002508{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002509 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002510
Douglas Gilbert773642d2016-04-25 12:16:28 -04002511 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002512 csum = (__force __be16)ip_compute_csum(buf, len);
2513 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002514 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002515
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002516 return csum;
2517}
2518
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002519static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002520 sector_t sector, u32 ei_lba)
2521{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002522 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002523
2524 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002525 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002526 (unsigned long)sector,
2527 be16_to_cpu(sdt->guard_tag),
2528 be16_to_cpu(csum));
2529 return 0x01;
2530 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002531 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002532 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002533 pr_err("REF check failed on sector %lu\n",
2534 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002535 return 0x03;
2536 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002537 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002538 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002539 pr_err("REF check failed on sector %lu\n",
2540 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002541 return 0x03;
2542 }
2543 return 0;
2544}
2545
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002546static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002547 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002548{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002549 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002550 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002551 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002552 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002553
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002554 /* Bytes of protection data to copy into sgl */
2555 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002556
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002557 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2558 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2559 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2560
2561 while (sg_miter_next(&miter) && resid > 0) {
2562 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002563 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002564 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002565
2566 if (dif_store_end < start + len)
2567 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002568
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002569 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002570
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002571 if (read)
2572 memcpy(paddr, start, len - rest);
2573 else
2574 memcpy(start, paddr, len - rest);
2575
2576 if (rest) {
2577 if (read)
2578 memcpy(paddr + len - rest, dif_storep, rest);
2579 else
2580 memcpy(dif_storep, paddr + len - rest, rest);
2581 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002582
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002583 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002584 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002585 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002586 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002587}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002588
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002589static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2590 unsigned int sectors, u32 ei_lba)
2591{
2592 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002593 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002594 sector_t sector;
2595
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002596 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002597 int ret;
2598
2599 sector = start_sec + i;
2600 sdt = dif_store(sector);
2601
Akinobu Mita51d648a2013-09-18 21:27:28 +09002602 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002603 continue;
2604
2605 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2606 if (ret) {
2607 dif_errors++;
2608 return ret;
2609 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002610 }
2611
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002612 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002613 dix_reads++;
2614
2615 return 0;
2616}
2617
Douglas Gilbertfd321192016-04-25 12:16:33 -04002618static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002619{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002620 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002621 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002622 u64 lba;
2623 u32 num;
2624 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002625 unsigned long iflags;
2626 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002627 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002628
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002629 switch (cmd[0]) {
2630 case READ_16:
2631 ei_lba = 0;
2632 lba = get_unaligned_be64(cmd + 2);
2633 num = get_unaligned_be32(cmd + 10);
2634 check_prot = true;
2635 break;
2636 case READ_10:
2637 ei_lba = 0;
2638 lba = get_unaligned_be32(cmd + 2);
2639 num = get_unaligned_be16(cmd + 7);
2640 check_prot = true;
2641 break;
2642 case READ_6:
2643 ei_lba = 0;
2644 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2645 (u32)(cmd[1] & 0x1f) << 16;
2646 num = (0 == cmd[4]) ? 256 : cmd[4];
2647 check_prot = true;
2648 break;
2649 case READ_12:
2650 ei_lba = 0;
2651 lba = get_unaligned_be32(cmd + 2);
2652 num = get_unaligned_be32(cmd + 6);
2653 check_prot = true;
2654 break;
2655 case XDWRITEREAD_10:
2656 ei_lba = 0;
2657 lba = get_unaligned_be32(cmd + 2);
2658 num = get_unaligned_be16(cmd + 7);
2659 check_prot = false;
2660 break;
2661 default: /* assume READ(32) */
2662 lba = get_unaligned_be64(cmd + 12);
2663 ei_lba = get_unaligned_be32(cmd + 20);
2664 num = get_unaligned_be32(cmd + 28);
2665 check_prot = false;
2666 break;
2667 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002668 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002669 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002670 (cmd[1] & 0xe0)) {
2671 mk_sense_invalid_opcode(scp);
2672 return check_condition_result;
2673 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002674 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2675 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002676 (cmd[1] & 0xe0) == 0)
2677 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2678 "to DIF device\n");
2679 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002680 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002681 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002682
Douglas Gilbertc4837392016-05-06 00:40:26 -04002683 if (sqcp) {
2684 if (sqcp->inj_short)
2685 num /= 2;
2686 }
2687 } else
2688 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002689
2690 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002691 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002692 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2693 return check_condition_result;
2694 }
2695 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002696 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002697 /* needs work to find which cdb byte 'num' comes from */
2698 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2699 return check_condition_result;
2700 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002701
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002702 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2703 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2704 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002705 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002706 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002707 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002708 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2709 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002710 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2711 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002712 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002713 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002714 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 return check_condition_result;
2716 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002717
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002718 read_lock_irqsave(&atomic_rw, iflags);
2719
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002720 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002721 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002722 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002723
2724 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002725 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002726 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002727 return illegal_condition_result;
2728 }
2729 }
2730
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002731 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002733 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002734 return DID_ERROR << 16;
2735
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002736 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002737
Douglas Gilbertc4837392016-05-06 00:40:26 -04002738 if (unlikely(sqcp)) {
2739 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002740 mk_sense_buffer(scp, RECOVERED_ERROR,
2741 THRESHOLD_EXCEEDED, 0);
2742 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002743 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002744 mk_sense_buffer(scp, ABORTED_COMMAND,
2745 TRANSPORT_PROBLEM, ACK_NAK_TO);
2746 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002747 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002748 /* Logical block guard check failed */
2749 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2750 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002751 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002752 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2753 return illegal_condition_result;
2754 }
2755 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002756 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757}
2758
Tomas Winkler58a86352015-07-28 16:54:23 +03002759static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002760{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002761 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002762
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002763 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002764 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002765 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002766
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002767 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002768 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002769
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002770 if (c >= 0x20 && c < 0x7e)
2771 n += scnprintf(b + n, sizeof(b) - n,
2772 " %c ", buf[i+j]);
2773 else
2774 n += scnprintf(b + n, sizeof(b) - n,
2775 "%02x ", buf[i+j]);
2776 }
2777 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002778 }
2779}
2780
2781static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002782 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002783{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002784 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002785 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002786 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002787 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002788 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002789 int dpage_offset;
2790 struct sg_mapping_iter diter;
2791 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002792
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002793 BUG_ON(scsi_sg_count(SCpnt) == 0);
2794 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2795
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002796 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2797 scsi_prot_sg_count(SCpnt),
2798 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2799 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2800 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002801
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002802 /* For each protection page */
2803 while (sg_miter_next(&piter)) {
2804 dpage_offset = 0;
2805 if (WARN_ON(!sg_miter_next(&diter))) {
2806 ret = 0x01;
2807 goto out;
2808 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002809
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002810 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002811 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002812 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002813 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002814 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002815 if (dpage_offset >= diter.length) {
2816 if (WARN_ON(!sg_miter_next(&diter))) {
2817 ret = 0x01;
2818 goto out;
2819 }
2820 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002821 }
2822
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002823 sdt = piter.addr + ppage_offset;
2824 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002825
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002826 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002827 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002828 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002829 goto out;
2830 }
2831
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002832 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002833 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002834 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002835 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002836 diter.consumed = dpage_offset;
2837 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002838 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002839 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002840
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002841 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002842 dix_writes++;
2843
2844 return 0;
2845
2846out:
2847 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002848 sg_miter_stop(&diter);
2849 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002850 return ret;
2851}
2852
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002853static unsigned long lba_to_map_index(sector_t lba)
2854{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002855 if (sdebug_unmap_alignment)
2856 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2857 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002858 return lba;
2859}
2860
2861static sector_t map_index_to_lba(unsigned long index)
2862{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002863 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002864
Douglas Gilbert773642d2016-04-25 12:16:28 -04002865 if (sdebug_unmap_alignment)
2866 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002867 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002868}
2869
Martin K. Petersen44d92692009-10-15 14:45:27 -04002870static unsigned int map_state(sector_t lba, unsigned int *num)
2871{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002872 sector_t end;
2873 unsigned int mapped;
2874 unsigned long index;
2875 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002876
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002877 index = lba_to_map_index(lba);
2878 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002879
2880 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002881 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002882 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002883 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002884
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002885 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002886 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002887 return mapped;
2888}
2889
2890static void map_region(sector_t lba, unsigned int len)
2891{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002892 sector_t end = lba + len;
2893
Martin K. Petersen44d92692009-10-15 14:45:27 -04002894 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002895 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002896
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002897 if (index < map_size)
2898 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002899
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002900 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002901 }
2902}
2903
2904static void unmap_region(sector_t lba, unsigned int len)
2905{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002906 sector_t end = lba + len;
2907
Martin K. Petersen44d92692009-10-15 14:45:27 -04002908 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002909 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002910
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002911 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002912 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002913 index < map_size) {
2914 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002915 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002916 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002917 lba * sdebug_sector_size,
2918 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002919 sdebug_sector_size *
2920 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002921 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002922 if (dif_storep) {
2923 memset(dif_storep + lba, 0xff,
2924 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002925 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002926 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002927 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002928 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002929 }
2930}
2931
Douglas Gilbertfd321192016-04-25 12:16:33 -04002932static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002934 u8 *cmd = scp->cmnd;
2935 u64 lba;
2936 u32 num;
2937 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002939 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002940 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002942 switch (cmd[0]) {
2943 case WRITE_16:
2944 ei_lba = 0;
2945 lba = get_unaligned_be64(cmd + 2);
2946 num = get_unaligned_be32(cmd + 10);
2947 check_prot = true;
2948 break;
2949 case WRITE_10:
2950 ei_lba = 0;
2951 lba = get_unaligned_be32(cmd + 2);
2952 num = get_unaligned_be16(cmd + 7);
2953 check_prot = true;
2954 break;
2955 case WRITE_6:
2956 ei_lba = 0;
2957 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2958 (u32)(cmd[1] & 0x1f) << 16;
2959 num = (0 == cmd[4]) ? 256 : cmd[4];
2960 check_prot = true;
2961 break;
2962 case WRITE_12:
2963 ei_lba = 0;
2964 lba = get_unaligned_be32(cmd + 2);
2965 num = get_unaligned_be32(cmd + 6);
2966 check_prot = true;
2967 break;
2968 case 0x53: /* XDWRITEREAD(10) */
2969 ei_lba = 0;
2970 lba = get_unaligned_be32(cmd + 2);
2971 num = get_unaligned_be16(cmd + 7);
2972 check_prot = false;
2973 break;
2974 default: /* assume WRITE(32) */
2975 lba = get_unaligned_be64(cmd + 12);
2976 ei_lba = get_unaligned_be32(cmd + 20);
2977 num = get_unaligned_be32(cmd + 28);
2978 check_prot = false;
2979 break;
2980 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002981 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002982 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002983 (cmd[1] & 0xe0)) {
2984 mk_sense_invalid_opcode(scp);
2985 return check_condition_result;
2986 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002987 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2988 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002989 (cmd[1] & 0xe0) == 0)
2990 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2991 "to DIF device\n");
2992 }
2993
2994 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002995 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002996 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2997 return check_condition_result;
2998 }
2999 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003000 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003001 /* needs work to find which cdb byte 'num' comes from */
3002 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3003 return check_condition_result;
3004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003006 write_lock_irqsave(&atomic_rw, iflags);
3007
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003008 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003009 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003010 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003011
3012 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003013 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003014 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003015 return illegal_condition_result;
3016 }
3017 }
3018
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003019 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003020 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003021 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003023 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003024 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003025 else if (unlikely(sdebug_verbose &&
3026 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003027 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003028 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003029 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003030
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003031 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003032 struct sdebug_queued_cmd *sqcp =
3033 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003034
Douglas Gilbertc4837392016-05-06 00:40:26 -04003035 if (sqcp) {
3036 if (sqcp->inj_recovered) {
3037 mk_sense_buffer(scp, RECOVERED_ERROR,
3038 THRESHOLD_EXCEEDED, 0);
3039 return check_condition_result;
3040 } else if (sqcp->inj_dif) {
3041 /* Logical block guard check failed */
3042 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3043 return illegal_condition_result;
3044 } else if (sqcp->inj_dix) {
3045 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3046 return illegal_condition_result;
3047 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003048 }
3049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 return 0;
3051}
3052
Douglas Gilbertfd321192016-04-25 12:16:33 -04003053static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3054 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003055{
3056 unsigned long iflags;
3057 unsigned long long i;
3058 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003059 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003060
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003061 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003062 if (ret)
3063 return ret;
3064
3065 write_lock_irqsave(&atomic_rw, iflags);
3066
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003067 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003068 unmap_region(lba, num);
3069 goto out;
3070 }
3071
Douglas Gilbert773642d2016-04-25 12:16:28 -04003072 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003073 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3074 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003075 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003076 ret = 0;
3077 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003078 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3079 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003080
3081 if (-1 == ret) {
3082 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003083 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003084 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003085 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003086 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003087 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003088 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003089
3090 /* Copy first sector to remaining blocks */
3091 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003092 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3093 fake_storep + lba_off,
3094 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003095
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003096 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003097 map_region(lba, num);
3098out:
3099 write_unlock_irqrestore(&atomic_rw, iflags);
3100
3101 return 0;
3102}
3103
Douglas Gilbertfd321192016-04-25 12:16:33 -04003104static int resp_write_same_10(struct scsi_cmnd *scp,
3105 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003106{
3107 u8 *cmd = scp->cmnd;
3108 u32 lba;
3109 u16 num;
3110 u32 ei_lba = 0;
3111 bool unmap = false;
3112
3113 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003114 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003115 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3116 return check_condition_result;
3117 } else
3118 unmap = true;
3119 }
3120 lba = get_unaligned_be32(cmd + 2);
3121 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003122 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003123 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3124 return check_condition_result;
3125 }
3126 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3127}
3128
Douglas Gilbertfd321192016-04-25 12:16:33 -04003129static int resp_write_same_16(struct scsi_cmnd *scp,
3130 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003131{
3132 u8 *cmd = scp->cmnd;
3133 u64 lba;
3134 u32 num;
3135 u32 ei_lba = 0;
3136 bool unmap = false;
3137 bool ndob = false;
3138
3139 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003140 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003141 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3142 return check_condition_result;
3143 } else
3144 unmap = true;
3145 }
3146 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3147 ndob = true;
3148 lba = get_unaligned_be64(cmd + 2);
3149 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003150 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003151 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3152 return check_condition_result;
3153 }
3154 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3155}
3156
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003157/* Note the mode field is in the same position as the (lower) service action
3158 * field. For the Report supported operation codes command, SPC-4 suggests
3159 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003160static int resp_write_buffer(struct scsi_cmnd *scp,
3161 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003162{
3163 u8 *cmd = scp->cmnd;
3164 struct scsi_device *sdp = scp->device;
3165 struct sdebug_dev_info *dp;
3166 u8 mode;
3167
3168 mode = cmd[1] & 0x1f;
3169 switch (mode) {
3170 case 0x4: /* download microcode (MC) and activate (ACT) */
3171 /* set UAs on this device only */
3172 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3173 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3174 break;
3175 case 0x5: /* download MC, save and ACT */
3176 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3177 break;
3178 case 0x6: /* download MC with offsets and ACT */
3179 /* set UAs on most devices (LUs) in this target */
3180 list_for_each_entry(dp,
3181 &devip->sdbg_host->dev_info_list,
3182 dev_list)
3183 if (dp->target == sdp->id) {
3184 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3185 if (devip != dp)
3186 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3187 dp->uas_bm);
3188 }
3189 break;
3190 case 0x7: /* download MC with offsets, save, and ACT */
3191 /* set UA on all devices (LUs) in this target */
3192 list_for_each_entry(dp,
3193 &devip->sdbg_host->dev_info_list,
3194 dev_list)
3195 if (dp->target == sdp->id)
3196 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3197 dp->uas_bm);
3198 break;
3199 default:
3200 /* do nothing for this command for other mode values */
3201 break;
3202 }
3203 return 0;
3204}
3205
Douglas Gilbertfd321192016-04-25 12:16:33 -04003206static int resp_comp_write(struct scsi_cmnd *scp,
3207 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003208{
3209 u8 *cmd = scp->cmnd;
3210 u8 *arr;
3211 u8 *fake_storep_hold;
3212 u64 lba;
3213 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003214 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003215 u8 num;
3216 unsigned long iflags;
3217 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003218 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003219
Douglas Gilbertd467d312014-11-26 12:33:48 -05003220 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003221 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3222 if (0 == num)
3223 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003224 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003225 (cmd[1] & 0xe0)) {
3226 mk_sense_invalid_opcode(scp);
3227 return check_condition_result;
3228 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003229 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3230 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003231 (cmd[1] & 0xe0) == 0)
3232 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3233 "to DIF device\n");
3234
3235 /* inline check_device_access_params() */
3236 if (lba + num > sdebug_capacity) {
3237 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3238 return check_condition_result;
3239 }
3240 /* transfer length excessive (tie in to block limits VPD page) */
3241 if (num > sdebug_store_sectors) {
3242 /* needs work to find which cdb byte 'num' comes from */
3243 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3244 return check_condition_result;
3245 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003246 dnum = 2 * num;
3247 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3248 if (NULL == arr) {
3249 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3250 INSUFF_RES_ASCQ);
3251 return check_condition_result;
3252 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003253
3254 write_lock_irqsave(&atomic_rw, iflags);
3255
3256 /* trick do_device_access() to fetch both compare and write buffers
3257 * from data-in into arr. Safe (atomic) since write_lock held. */
3258 fake_storep_hold = fake_storep;
3259 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003260 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003261 fake_storep = fake_storep_hold;
3262 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003263 retval = DID_ERROR << 16;
3264 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003265 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003266 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3267 "indicated=%u, IO sent=%d bytes\n", my_name,
3268 dnum * lb_size, ret);
3269 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003270 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003271 retval = check_condition_result;
3272 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003273 }
3274 if (scsi_debug_lbp())
3275 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003276cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003277 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003278 kfree(arr);
3279 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003280}
3281
Martin K. Petersen44d92692009-10-15 14:45:27 -04003282struct unmap_block_desc {
3283 __be64 lba;
3284 __be32 blocks;
3285 __be32 __reserved;
3286};
3287
Douglas Gilbertfd321192016-04-25 12:16:33 -04003288static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003289{
3290 unsigned char *buf;
3291 struct unmap_block_desc *desc;
3292 unsigned int i, payload_len, descriptors;
3293 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003294 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003295
Martin K. Petersen44d92692009-10-15 14:45:27 -04003296
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003297 if (!scsi_debug_lbp())
3298 return 0; /* fib and say its done */
3299 payload_len = get_unaligned_be16(scp->cmnd + 7);
3300 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003301
3302 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003303 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003304 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003305 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003306 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003307
Douglas Gilbertb333a812016-04-25 12:16:30 -04003308 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003309 if (!buf) {
3310 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3311 INSUFF_RES_ASCQ);
3312 return check_condition_result;
3313 }
3314
3315 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003316
3317 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3318 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3319
3320 desc = (void *)&buf[8];
3321
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003322 write_lock_irqsave(&atomic_rw, iflags);
3323
Martin K. Petersen44d92692009-10-15 14:45:27 -04003324 for (i = 0 ; i < descriptors ; i++) {
3325 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3326 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3327
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003328 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003329 if (ret)
3330 goto out;
3331
3332 unmap_region(lba, num);
3333 }
3334
3335 ret = 0;
3336
3337out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003338 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003339 kfree(buf);
3340
3341 return ret;
3342}
3343
3344#define SDEBUG_GET_LBA_STATUS_LEN 32
3345
Douglas Gilbertfd321192016-04-25 12:16:33 -04003346static int resp_get_lba_status(struct scsi_cmnd *scp,
3347 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003348{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003349 u8 *cmd = scp->cmnd;
3350 u64 lba;
3351 u32 alloc_len, mapped, num;
3352 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003353 int ret;
3354
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003355 lba = get_unaligned_be64(cmd + 2);
3356 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003357
3358 if (alloc_len < 24)
3359 return 0;
3360
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003361 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003362 if (ret)
3363 return ret;
3364
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003365 if (scsi_debug_lbp())
3366 mapped = map_state(lba, &num);
3367 else {
3368 mapped = 1;
3369 /* following just in case virtual_gb changed */
3370 sdebug_capacity = get_sdebug_capacity();
3371 if (sdebug_capacity - lba <= 0xffffffff)
3372 num = sdebug_capacity - lba;
3373 else
3374 num = 0xffffffff;
3375 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003376
3377 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003378 put_unaligned_be32(20, arr); /* Parameter Data Length */
3379 put_unaligned_be64(lba, arr + 8); /* LBA */
3380 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3381 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003382
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003383 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003384}
3385
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003386#define RL_BUCKET_ELEMS 8
3387
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003388/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3389 * (W-LUN), the normal Linux scanning logic does not associate it with a
3390 * device (e.g. /dev/sg7). The following magic will make that association:
3391 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3392 * where <n> is a host number. If there are multiple targets in a host then
3393 * the above will associate a W-LUN to each target. To only get a W-LUN
3394 * for target 2, then use "echo '- 2 49409' > scan" .
3395 */
3396static int resp_report_luns(struct scsi_cmnd *scp,
3397 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003399 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003400 unsigned int alloc_len;
3401 unsigned char select_report;
3402 u64 lun;
3403 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003404 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003405 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3406 unsigned int wlun_cnt; /* report luns W-LUN count */
3407 unsigned int tlun_cnt; /* total LUN count */
3408 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003409 int k, j, n, res;
3410 unsigned int off_rsp = 0;
3411 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003413 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003414
3415 select_report = cmd[2];
3416 alloc_len = get_unaligned_be32(cmd + 6);
3417
3418 if (alloc_len < 4) {
3419 pr_err("alloc len too small %d\n", alloc_len);
3420 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 return check_condition_result;
3422 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003423
3424 switch (select_report) {
3425 case 0: /* all LUNs apart from W-LUNs */
3426 lun_cnt = sdebug_max_luns;
3427 wlun_cnt = 0;
3428 break;
3429 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003430 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003431 wlun_cnt = 1;
3432 break;
3433 case 2: /* all LUNs */
3434 lun_cnt = sdebug_max_luns;
3435 wlun_cnt = 1;
3436 break;
3437 case 0x10: /* only administrative LUs */
3438 case 0x11: /* see SPC-5 */
3439 case 0x12: /* only subsiduary LUs owned by referenced LU */
3440 default:
3441 pr_debug("select report invalid %d\n", select_report);
3442 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3443 return check_condition_result;
3444 }
3445
3446 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003447 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003448
3449 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003450 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3451 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003452 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3453 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3454
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003455 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003456 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003457 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3458 memset(arr, 0, sizeof(arr));
3459 lun_p = (struct scsi_lun *)&arr[0];
3460 if (k == 0) {
3461 put_unaligned_be32(rlen, &arr[0]);
3462 ++lun_p;
3463 j = 1;
3464 }
3465 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3466 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3467 break;
3468 int_to_scsilun(lun++, lun_p);
3469 }
3470 if (j < RL_BUCKET_ELEMS)
3471 break;
3472 n = j * sz_lun;
3473 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3474 if (res)
3475 return res;
3476 off_rsp += n;
3477 }
3478 if (wlun_cnt) {
3479 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3480 ++j;
3481 }
3482 if (j > 0)
3483 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003484 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485}
3486
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003487static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3488 unsigned int num, struct sdebug_dev_info *devip)
3489{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003490 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003491 unsigned char *kaddr, *buf;
3492 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003493 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003494 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003495
3496 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003497 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003498 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003499 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3500 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003501 return check_condition_result;
3502 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003503
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003504 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003505
3506 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003507 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3508 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003509
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003510 while (sg_miter_next(&miter)) {
3511 kaddr = miter.addr;
3512 for (j = 0; j < miter.length; j++)
3513 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003514
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003515 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003516 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003517 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003518 kfree(buf);
3519
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003520 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003521}
3522
Douglas Gilbertfd321192016-04-25 12:16:33 -04003523static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3524 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003525{
3526 u8 *cmd = scp->cmnd;
3527 u64 lba;
3528 u32 num;
3529 int errsts;
3530
3531 if (!scsi_bidi_cmnd(scp)) {
3532 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3533 INSUFF_RES_ASCQ);
3534 return check_condition_result;
3535 }
3536 errsts = resp_read_dt0(scp, devip);
3537 if (errsts)
3538 return errsts;
3539 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3540 errsts = resp_write_dt0(scp, devip);
3541 if (errsts)
3542 return errsts;
3543 }
3544 lba = get_unaligned_be32(cmd + 2);
3545 num = get_unaligned_be16(cmd + 7);
3546 return resp_xdwriteread(scp, lba, num, devip);
3547}
3548
Douglas Gilbertc4837392016-05-06 00:40:26 -04003549static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3550{
3551 struct sdebug_queue *sqp = sdebug_q_arr;
3552
3553 if (sdebug_mq_active) {
3554 u32 tag = blk_mq_unique_tag(cmnd->request);
3555 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3556
3557 if (unlikely(hwq >= submit_queues)) {
3558 pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3559 hwq %= submit_queues;
3560 }
3561 pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3562 return sqp + hwq;
3563 } else
3564 return sqp;
3565}
3566
3567/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003568static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003570 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003571 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003573 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003574 struct sdebug_queued_cmd *sqcp;
3575 struct scsi_cmnd *scp;
3576 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
Douglas Gilbertc4837392016-05-06 00:40:26 -04003578 qc_idx = sd_dp->qc_idx;
3579 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3580 if (sdebug_statistics) {
3581 atomic_inc(&sdebug_completions);
3582 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3583 atomic_inc(&sdebug_miss_cpus);
3584 }
3585 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3586 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 return;
3588 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003589 spin_lock_irqsave(&sqp->qc_lock, iflags);
3590 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003591 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003592 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003593 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3594 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3595 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 return;
3597 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003598 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003599 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003600 atomic_dec(&devip->num_in_q);
3601 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003602 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003603 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003604 retiring = 1;
3605
3606 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003607 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3608 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003609 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003610 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003612
3613 if (unlikely(retiring)) { /* user has reduced max_queue */
3614 int k, retval;
3615
3616 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003617 if (qc_idx >= retval) {
3618 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003619 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003620 return;
3621 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003622 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003623 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003624 atomic_set(&retired_max_queue, 0);
3625 else
3626 atomic_set(&retired_max_queue, k + 1);
3627 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003628 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003629 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630}
3631
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003632/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003633static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003634{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003635 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3636 hrt);
3637 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003638 return HRTIMER_NORESTART;
3639}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640
Douglas Gilberta10bc122016-04-25 12:16:32 -04003641/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003642static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003643{
3644 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3645 ew.work);
3646 sdebug_q_cmd_complete(sd_dp);
3647}
3648
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003649static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003650static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003651
Douglas Gilbertfd321192016-04-25 12:16:33 -04003652static struct sdebug_dev_info *sdebug_device_create(
3653 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003654{
3655 struct sdebug_dev_info *devip;
3656
3657 devip = kzalloc(sizeof(*devip), flags);
3658 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003659 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003660 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003661 else if (sdebug_uuid_ctl == 2) {
3662 if (got_shared_uuid)
3663 devip->lu_name = shared_uuid;
3664 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003665 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003666 got_shared_uuid = true;
3667 devip->lu_name = shared_uuid;
3668 }
3669 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003670 devip->sdbg_host = sdbg_host;
3671 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3672 }
3673 return devip;
3674}
3675
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003676static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003678 struct sdebug_host_info *sdbg_host;
3679 struct sdebug_dev_info *open_devip = NULL;
3680 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003682 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3683 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003684 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3688 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003689 (devip->target == sdev->id) &&
3690 (devip->lun == sdev->lun))
3691 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 else {
3693 if ((!devip->used) && (!open_devip))
3694 open_devip = devip;
3695 }
3696 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003697 if (!open_devip) { /* try and make a new one */
3698 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3699 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003700 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 return NULL;
3702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003704
3705 open_devip->channel = sdev->channel;
3706 open_devip->target = sdev->id;
3707 open_devip->lun = sdev->lun;
3708 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003709 atomic_set(&open_devip->num_in_q, 0);
3710 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003711 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003712 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713}
3714
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003715static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003717 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003718 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003719 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003720 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003721 return 0;
3722}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003724static int scsi_debug_slave_configure(struct scsi_device *sdp)
3725{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003726 struct sdebug_dev_info *devip =
3727 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003728
Douglas Gilbert773642d2016-04-25 12:16:28 -04003729 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003730 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003731 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003732 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3733 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3734 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003735 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003736 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003737 return 1; /* no resources, will be marked offline */
3738 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003739 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003740 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003741 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003742 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003743 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003744 return 0;
3745}
3746
3747static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3748{
3749 struct sdebug_dev_info *devip =
3750 (struct sdebug_dev_info *)sdp->hostdata;
3751
Douglas Gilbert773642d2016-04-25 12:16:28 -04003752 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003753 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003754 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3755 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003756 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003757 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003758 sdp->hostdata = NULL;
3759 }
3760}
3761
Douglas Gilbertc4837392016-05-06 00:40:26 -04003762static void stop_qc_helper(struct sdebug_defer *sd_dp)
3763{
3764 if (!sd_dp)
3765 return;
3766 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3767 hrtimer_cancel(&sd_dp->hrt);
3768 else if (sdebug_jdelay < 0)
3769 cancel_work_sync(&sd_dp->ew.work);
3770}
3771
Douglas Gilberta10bc122016-04-25 12:16:32 -04003772/* If @cmnd found deletes its timer or work queue and returns true; else
3773 returns false */
3774static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003775{
3776 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003777 int j, k, qmax, r_qmax;
3778 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003779 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003780 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003781 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003782
Douglas Gilbertc4837392016-05-06 00:40:26 -04003783 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3784 spin_lock_irqsave(&sqp->qc_lock, iflags);
3785 qmax = sdebug_max_queue;
3786 r_qmax = atomic_read(&retired_max_queue);
3787 if (r_qmax > qmax)
3788 qmax = r_qmax;
3789 for (k = 0; k < qmax; ++k) {
3790 if (test_bit(k, sqp->in_use_bm)) {
3791 sqcp = &sqp->qc_arr[k];
3792 if (cmnd != sqcp->a_cmnd)
3793 continue;
3794 /* found */
3795 devip = (struct sdebug_dev_info *)
3796 cmnd->device->hostdata;
3797 if (devip)
3798 atomic_dec(&devip->num_in_q);
3799 sqcp->a_cmnd = NULL;
3800 sd_dp = sqcp->sd_dp;
3801 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3802 stop_qc_helper(sd_dp);
3803 clear_bit(k, sqp->in_use_bm);
3804 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003805 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003806 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003807 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003808 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003809 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003810}
3811
Douglas Gilberta10bc122016-04-25 12:16:32 -04003812/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003813static void stop_all_queued(void)
3814{
3815 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003816 int j, k;
3817 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003818 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003819 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003820 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003821
Douglas Gilbertc4837392016-05-06 00:40:26 -04003822 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3823 spin_lock_irqsave(&sqp->qc_lock, iflags);
3824 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3825 if (test_bit(k, sqp->in_use_bm)) {
3826 sqcp = &sqp->qc_arr[k];
3827 if (sqcp->a_cmnd == NULL)
3828 continue;
3829 devip = (struct sdebug_dev_info *)
3830 sqcp->a_cmnd->device->hostdata;
3831 if (devip)
3832 atomic_dec(&devip->num_in_q);
3833 sqcp->a_cmnd = NULL;
3834 sd_dp = sqcp->sd_dp;
3835 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3836 stop_qc_helper(sd_dp);
3837 clear_bit(k, sqp->in_use_bm);
3838 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003839 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003840 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003841 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843}
3844
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003845/* Free queued command memory on heap */
3846static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003848 int j, k;
3849 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003850 struct sdebug_queued_cmd *sqcp;
3851
Douglas Gilbertc4837392016-05-06 00:40:26 -04003852 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3853 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3854 sqcp = &sqp->qc_arr[k];
3855 kfree(sqcp->sd_dp);
3856 sqcp->sd_dp = NULL;
3857 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859}
3860
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003861static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003863 bool ok;
3864
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003865 ++num_aborts;
3866 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003867 ok = stop_queued_cmnd(SCpnt);
3868 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3869 sdev_printk(KERN_INFO, SCpnt->device,
3870 "%s: command%s found\n", __func__,
3871 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003873 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874}
3875
3876static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3877{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003879 if (SCpnt && SCpnt->device) {
3880 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003881 struct sdebug_dev_info *devip =
3882 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003883
Douglas Gilbert773642d2016-04-25 12:16:28 -04003884 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003885 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003887 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 }
3889 return SUCCESS;
3890}
3891
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003892static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3893{
3894 struct sdebug_host_info *sdbg_host;
3895 struct sdebug_dev_info *devip;
3896 struct scsi_device *sdp;
3897 struct Scsi_Host *hp;
3898 int k = 0;
3899
3900 ++num_target_resets;
3901 if (!SCpnt)
3902 goto lie;
3903 sdp = SCpnt->device;
3904 if (!sdp)
3905 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003906 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003907 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3908 hp = sdp->host;
3909 if (!hp)
3910 goto lie;
3911 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3912 if (sdbg_host) {
3913 list_for_each_entry(devip,
3914 &sdbg_host->dev_info_list,
3915 dev_list)
3916 if (devip->target == sdp->id) {
3917 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3918 ++k;
3919 }
3920 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003921 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003922 sdev_printk(KERN_INFO, sdp,
3923 "%s: %d device(s) found in target\n", __func__, k);
3924lie:
3925 return SUCCESS;
3926}
3927
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3929{
3930 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003931 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003932 struct scsi_device *sdp;
3933 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003934 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003937 if (!(SCpnt && SCpnt->device))
3938 goto lie;
3939 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003940 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003941 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3942 hp = sdp->host;
3943 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003944 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003946 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05003947 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003948 dev_list) {
3949 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3950 ++k;
3951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 }
3953 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003954 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003955 sdev_printk(KERN_INFO, sdp,
3956 "%s: %d device(s) found in host\n", __func__, k);
3957lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 return SUCCESS;
3959}
3960
3961static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3962{
3963 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003964 struct sdebug_dev_info *devip;
3965 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003968 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003969 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05003970 spin_lock(&sdebug_host_list_lock);
3971 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003972 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3973 dev_list) {
3974 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3975 ++k;
3976 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05003977 }
3978 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003980 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003981 sdev_printk(KERN_INFO, SCpnt->device,
3982 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 return SUCCESS;
3984}
3985
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003986static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003987 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988{
3989 struct partition * pp;
3990 int starts[SDEBUG_MAX_PARTS + 2];
3991 int sectors_per_part, num_sectors, k;
3992 int heads_by_sects, start_sec, end_sec;
3993
3994 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003995 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003997 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3998 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003999 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004001 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004003 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004005 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004006 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4008 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004009 starts[sdebug_num_parts] = num_sectors;
4010 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011
4012 ramp[510] = 0x55; /* magic partition markings */
4013 ramp[511] = 0xAA;
4014 pp = (struct partition *)(ramp + 0x1be);
4015 for (k = 0; starts[k + 1]; ++k, ++pp) {
4016 start_sec = starts[k];
4017 end_sec = starts[k + 1] - 1;
4018 pp->boot_ind = 0;
4019
4020 pp->cyl = start_sec / heads_by_sects;
4021 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4022 / sdebug_sectors_per;
4023 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4024
4025 pp->end_cyl = end_sec / heads_by_sects;
4026 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4027 / sdebug_sectors_per;
4028 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4029
Akinobu Mita150c3542013-08-26 22:08:40 +09004030 pp->start_sect = cpu_to_le32(start_sec);
4031 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 pp->sys_ind = 0x83; /* plain Linux partition */
4033 }
4034}
4035
Douglas Gilbertc4837392016-05-06 00:40:26 -04004036static void block_unblock_all_queues(bool block)
4037{
4038 int j;
4039 struct sdebug_queue *sqp;
4040
4041 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4042 atomic_set(&sqp->blocked, (int)block);
4043}
4044
4045/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4046 * commands will be processed normally before triggers occur.
4047 */
4048static void tweak_cmnd_count(void)
4049{
4050 int count, modulo;
4051
4052 modulo = abs(sdebug_every_nth);
4053 if (modulo < 2)
4054 return;
4055 block_unblock_all_queues(true);
4056 count = atomic_read(&sdebug_cmnd_count);
4057 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4058 block_unblock_all_queues(false);
4059}
4060
4061static void clear_queue_stats(void)
4062{
4063 atomic_set(&sdebug_cmnd_count, 0);
4064 atomic_set(&sdebug_completions, 0);
4065 atomic_set(&sdebug_miss_cpus, 0);
4066 atomic_set(&sdebug_a_tsf, 0);
4067}
4068
4069static void setup_inject(struct sdebug_queue *sqp,
4070 struct sdebug_queued_cmd *sqcp)
4071{
4072 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4073 return;
4074 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4075 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4076 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4077 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4078 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004079 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004080}
4081
4082/* Complete the processing of the thread that queued a SCSI command to this
4083 * driver. It either completes the command by calling cmnd_done() or
4084 * schedules a hr timer or work queue then returns 0. Returns
4085 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4086 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004087static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4088 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004090 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004091 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004092 struct sdebug_queue *sqp;
4093 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004094 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004095 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004097 if (unlikely(devip == NULL)) {
4098 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004099 scsi_result = DID_NO_CONNECT << 16;
4100 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004102 sdp = cmnd->device;
4103
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004104 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004105 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4106 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004107 if (delta_jiff == 0)
4108 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004110 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004111 sqp = get_queue(cmnd);
4112 spin_lock_irqsave(&sqp->qc_lock, iflags);
4113 if (unlikely(atomic_read(&sqp->blocked))) {
4114 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4115 return SCSI_MLQUEUE_HOST_BUSY;
4116 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004117 num_in_q = atomic_read(&devip->num_in_q);
4118 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004119 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004120 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004121 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004122 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004123 goto respond_in_thread;
4124 } else
4125 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004126 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004127 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4128 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004129 if ((num_in_q == (qdepth - 1)) &&
4130 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004131 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004132 atomic_set(&sdebug_a_tsf, 0);
4133 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004134 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004136 }
4137
Douglas Gilbertc4837392016-05-06 00:40:26 -04004138 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004139 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004140 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004141 if (scsi_result)
4142 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004143 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004144 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004145 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004146 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004147 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004148 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004149 (scsi_result ? "status: TASK SET FULL" :
4150 "report: host busy"));
4151 if (scsi_result)
4152 goto respond_in_thread;
4153 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004154 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004156 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004157 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004158 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004159 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004160 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004161 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004162 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004163 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4164 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4165 setup_inject(sqp, sqcp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004166 if (delta_jiff > 0 || sdebug_ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004167 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004168
Douglas Gilbertb333a812016-04-25 12:16:30 -04004169 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004170 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004171 } else
Thomas Gleixner8b0e1952016-12-25 12:30:41 +01004172 kt = sdebug_ndelay;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004173 if (NULL == sd_dp) {
4174 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4175 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004176 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004177 sqcp->sd_dp = sd_dp;
4178 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004179 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004180 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004181 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4182 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004183 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004184 if (sdebug_statistics)
4185 sd_dp->issuing_cpu = raw_smp_processor_id();
4186 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4187 } else { /* jdelay < 0, use work queue */
Douglas Gilberta10bc122016-04-25 12:16:32 -04004188 if (NULL == sd_dp) {
4189 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4190 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004191 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004192 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004193 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4194 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004195 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004196 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004197 if (sdebug_statistics)
4198 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilberta10bc122016-04-25 12:16:32 -04004199 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004200 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004201 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4202 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004203 sdev_printk(KERN_INFO, sdp,
4204 "%s: num_in_q=%d +1, %s%s\n", __func__,
4205 num_in_q, (inject ? "<inject> " : ""),
4206 "status: TASK SET FULL");
4207 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004208
4209respond_in_thread: /* call back to mid-layer using invocation thread */
4210 cmnd->result = scsi_result;
4211 cmnd->scsi_done(cmnd);
4212 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004214
Douglas Gilbert23183912006-09-16 20:30:47 -04004215/* Note: The following macros create attribute files in the
4216 /sys/module/scsi_debug/parameters directory. Unfortunately this
4217 driver is unaware of a change and cannot trigger auxiliary actions
4218 as it can when the corresponding attribute in the
4219 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4220 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004221module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4222module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004223module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004224module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004225module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004226module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4227module_param_named(dif, sdebug_dif, int, S_IRUGO);
4228module_param_named(dix, sdebug_dix, int, S_IRUGO);
4229module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4230module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4231module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4232module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4233module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004234module_param_string(inq_vendor, sdebug_inq_vendor_id,
4235 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4236module_param_string(inq_product, sdebug_inq_product_id,
4237 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4238module_param_string(inq_rev, sdebug_inq_product_rev,
4239 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004240module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4241module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4242module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4243module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4244module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4245module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4246module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4247module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4248module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4249module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4250module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4251module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4252module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4253module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4254module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004255module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004256module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4257module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4258module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4259module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004260module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004261module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004262module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004263module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4264module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4265module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4266module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4267module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004268module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004269module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004270 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004271module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004272 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273
4274MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4275MODULE_DESCRIPTION("SCSI debug adapter driver");
4276MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004277MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278
4279MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004280MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004281MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004282MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004283MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004284MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004285MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4286MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004287MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004288MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004289MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004290MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004291MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004292MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4293MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004294MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4295 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004296MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4297MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4298MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004299MODULE_PARM_DESC(lbprz,
4300 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004301MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004302MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004303MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4304MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004305MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004306MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004308MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004309MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004310MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004311MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004312MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004314MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004315MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004316MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004317MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004318MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004319MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004320MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4321MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004322MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4323MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004324MODULE_PARM_DESC(uuid_ctl,
4325 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004326MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004327MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4328MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004330#define SDEBUG_INFO_LEN 256
4331static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332
4333static const char * scsi_debug_info(struct Scsi_Host * shp)
4334{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004335 int k;
4336
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004337 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4338 my_name, SDEBUG_VERSION, sdebug_version_date);
4339 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004340 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004341 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4342 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4343 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4344 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 return sdebug_info;
4346}
4347
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004348/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004349static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4350 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351{
Al Viroc8ed5552013-03-31 01:46:06 -04004352 char arr[16];
4353 int opts;
4354 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
Al Viroc8ed5552013-03-31 01:46:06 -04004356 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4357 return -EACCES;
4358 memcpy(arr, buffer, minLen);
4359 arr[minLen] = '\0';
4360 if (1 != sscanf(arr, "%d", &opts))
4361 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004362 sdebug_opts = opts;
4363 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4364 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4365 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004366 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004367 return length;
4368}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004370/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4371 * same for each scsi_debug host (if more than one). Some of the counters
4372 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004373static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4374{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004375 int f, j, l;
4376 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004377
Douglas Gilbertc4837392016-05-06 00:40:26 -04004378 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4379 SDEBUG_VERSION, sdebug_version_date);
4380 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4381 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4382 sdebug_opts, sdebug_every_nth);
4383 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4384 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4385 sdebug_sector_size, "bytes");
4386 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4387 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4388 num_aborts);
4389 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4390 num_dev_resets, num_target_resets, num_bus_resets,
4391 num_host_resets);
4392 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4393 dix_reads, dix_writes, dif_errors);
4394 seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4395 TICK_NSEC / 1000, "statistics", sdebug_statistics,
4396 sdebug_mq_active);
4397 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4398 atomic_read(&sdebug_cmnd_count),
4399 atomic_read(&sdebug_completions),
4400 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4401 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004402
Douglas Gilbertc4837392016-05-06 00:40:26 -04004403 seq_printf(m, "submit_queues=%d\n", submit_queues);
4404 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4405 seq_printf(m, " queue %d:\n", j);
4406 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4407 if (f != sdebug_max_queue) {
4408 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4409 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4410 "first,last bits", f, l);
4411 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004412 }
Al Viroc8ed5552013-03-31 01:46:06 -04004413 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414}
4415
Akinobu Mita82069372013-10-14 22:48:04 +09004416static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004418 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004420/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4421 * of delay is jiffies.
4422 */
Akinobu Mita82069372013-10-14 22:48:04 +09004423static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4424 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004426 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004428 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004429 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004430 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004431 int j, k;
4432 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004433
Douglas Gilbertc4837392016-05-06 00:40:26 -04004434 block_unblock_all_queues(true);
4435 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4436 ++j, ++sqp) {
4437 k = find_first_bit(sqp->in_use_bm,
4438 sdebug_max_queue);
4439 if (k != sdebug_max_queue) {
4440 res = -EBUSY; /* queued commands */
4441 break;
4442 }
4443 }
4444 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004445 /* make sure sdebug_defer instances get
4446 * re-allocated for new delay variant */
4447 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004448 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004449 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004450 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004451 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004453 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 }
4455 return -EINVAL;
4456}
Akinobu Mita82069372013-10-14 22:48:04 +09004457static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004459static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4460{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004461 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004462}
4463/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004464/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004465static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004466 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004467{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004468 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004469
4470 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004471 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004472 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004473 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004474 int j, k;
4475 struct sdebug_queue *sqp;
4476
4477 block_unblock_all_queues(true);
4478 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4479 ++j, ++sqp) {
4480 k = find_first_bit(sqp->in_use_bm,
4481 sdebug_max_queue);
4482 if (k != sdebug_max_queue) {
4483 res = -EBUSY; /* queued commands */
4484 break;
4485 }
4486 }
4487 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004488 /* make sure sdebug_defer instances get
4489 * re-allocated for new delay variant */
4490 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004491 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004492 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4493 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004494 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004495 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004496 }
4497 return res;
4498 }
4499 return -EINVAL;
4500}
4501static DRIVER_ATTR_RW(ndelay);
4502
Akinobu Mita82069372013-10-14 22:48:04 +09004503static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004505 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506}
4507
Akinobu Mita82069372013-10-14 22:48:04 +09004508static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4509 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004511 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 char work[20];
4513
Douglas Gilbert9a051012017-12-23 12:48:10 -05004514 if (sscanf(buf, "%10s", work) == 1) {
4515 if (strncasecmp(work, "0x", 2) == 0) {
4516 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 goto opts_done;
4518 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004519 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 goto opts_done;
4521 }
4522 }
4523 return -EINVAL;
4524opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004525 sdebug_opts = opts;
4526 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4527 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004528 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 return count;
4530}
Akinobu Mita82069372013-10-14 22:48:04 +09004531static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
Akinobu Mita82069372013-10-14 22:48:04 +09004533static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004535 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536}
Akinobu Mita82069372013-10-14 22:48:04 +09004537static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4538 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004540 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541
4542 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004543 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 return count;
4545 }
4546 return -EINVAL;
4547}
Akinobu Mita82069372013-10-14 22:48:04 +09004548static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549
Akinobu Mita82069372013-10-14 22:48:04 +09004550static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004552 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553}
Akinobu Mita82069372013-10-14 22:48:04 +09004554static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4555 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004557 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
4559 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004560 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 return count;
4562 }
4563 return -EINVAL;
4564}
Akinobu Mita82069372013-10-14 22:48:04 +09004565static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566
Akinobu Mita82069372013-10-14 22:48:04 +09004567static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004568{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004569 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004570}
Akinobu Mita82069372013-10-14 22:48:04 +09004571static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4572 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004573{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004574 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004575
4576 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004577 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004578 sdebug_fake_rw = (sdebug_fake_rw > 0);
4579 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004580 if ((0 == n) && (NULL == fake_storep)) {
4581 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004582 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004583 1048576;
4584
4585 fake_storep = vmalloc(sz);
4586 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004587 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004588 return -ENOMEM;
4589 }
4590 memset(fake_storep, 0, sz);
4591 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004592 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004593 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004594 return count;
4595 }
4596 return -EINVAL;
4597}
Akinobu Mita82069372013-10-14 22:48:04 +09004598static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004599
Akinobu Mita82069372013-10-14 22:48:04 +09004600static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004601{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004602 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004603}
Akinobu Mita82069372013-10-14 22:48:04 +09004604static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4605 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004606{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004607 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004608
4609 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004610 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004611 return count;
4612 }
4613 return -EINVAL;
4614}
Akinobu Mita82069372013-10-14 22:48:04 +09004615static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004616
Akinobu Mita82069372013-10-14 22:48:04 +09004617static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004619 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620}
Akinobu Mita82069372013-10-14 22:48:04 +09004621static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4622 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004624 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625
4626 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004627 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 sdebug_max_tgts_luns();
4629 return count;
4630 }
4631 return -EINVAL;
4632}
Akinobu Mita82069372013-10-14 22:48:04 +09004633static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634
Akinobu Mita82069372013-10-14 22:48:04 +09004635static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004637 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638}
Akinobu Mita82069372013-10-14 22:48:04 +09004639static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640
Akinobu Mita82069372013-10-14 22:48:04 +09004641static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004643 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644}
Akinobu Mita82069372013-10-14 22:48:04 +09004645static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646
Akinobu Mita82069372013-10-14 22:48:04 +09004647static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004649 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650}
Akinobu Mita82069372013-10-14 22:48:04 +09004651static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4652 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004654 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655
4656 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004657 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004658 if (nth && !sdebug_statistics) {
4659 pr_info("every_nth needs statistics=1, set it\n");
4660 sdebug_statistics = true;
4661 }
4662 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 return count;
4664 }
4665 return -EINVAL;
4666}
Akinobu Mita82069372013-10-14 22:48:04 +09004667static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668
Akinobu Mita82069372013-10-14 22:48:04 +09004669static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004671 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672}
Akinobu Mita82069372013-10-14 22:48:04 +09004673static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4674 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004676 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004677 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
4679 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004680 if (n > 256) {
4681 pr_warn("max_luns can be no more than 256\n");
4682 return -EINVAL;
4683 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004684 changed = (sdebug_max_luns != n);
4685 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004687 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004688 struct sdebug_host_info *sdhp;
4689 struct sdebug_dev_info *dp;
4690
4691 spin_lock(&sdebug_host_list_lock);
4692 list_for_each_entry(sdhp, &sdebug_host_list,
4693 host_list) {
4694 list_for_each_entry(dp, &sdhp->dev_info_list,
4695 dev_list) {
4696 set_bit(SDEBUG_UA_LUNS_CHANGED,
4697 dp->uas_bm);
4698 }
4699 }
4700 spin_unlock(&sdebug_host_list_lock);
4701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 return count;
4703 }
4704 return -EINVAL;
4705}
Akinobu Mita82069372013-10-14 22:48:04 +09004706static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707
Akinobu Mita82069372013-10-14 22:48:04 +09004708static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004709{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004710 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004711}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004712/* N.B. max_queue can be changed while there are queued commands. In flight
4713 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004714static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4715 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004716{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004717 int j, n, k, a;
4718 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004719
4720 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004721 (n <= SDEBUG_CANQUEUE)) {
4722 block_unblock_all_queues(true);
4723 k = 0;
4724 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4725 ++j, ++sqp) {
4726 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4727 if (a > k)
4728 k = a;
4729 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004730 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004731 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004732 atomic_set(&retired_max_queue, 0);
4733 else if (k >= n)
4734 atomic_set(&retired_max_queue, k + 1);
4735 else
4736 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004737 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004738 return count;
4739 }
4740 return -EINVAL;
4741}
Akinobu Mita82069372013-10-14 22:48:04 +09004742static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004743
Akinobu Mita82069372013-10-14 22:48:04 +09004744static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004745{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004746 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004747}
Akinobu Mita82069372013-10-14 22:48:04 +09004748static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004749
Akinobu Mita82069372013-10-14 22:48:04 +09004750static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004752 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753}
Akinobu Mita82069372013-10-14 22:48:04 +09004754static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755
Akinobu Mita82069372013-10-14 22:48:04 +09004756static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004757{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004758 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004759}
Akinobu Mita82069372013-10-14 22:48:04 +09004760static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4761 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004762{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004763 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004764 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004765
4766 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004767 changed = (sdebug_virtual_gb != n);
4768 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004769 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004770 if (changed) {
4771 struct sdebug_host_info *sdhp;
4772 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004773
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004774 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004775 list_for_each_entry(sdhp, &sdebug_host_list,
4776 host_list) {
4777 list_for_each_entry(dp, &sdhp->dev_info_list,
4778 dev_list) {
4779 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4780 dp->uas_bm);
4781 }
4782 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004783 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004784 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004785 return count;
4786 }
4787 return -EINVAL;
4788}
Akinobu Mita82069372013-10-14 22:48:04 +09004789static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004790
Akinobu Mita82069372013-10-14 22:48:04 +09004791static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004793 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794}
4795
Douglas Gilbertfd321192016-04-25 12:16:33 -04004796static int sdebug_add_adapter(void);
4797static void sdebug_remove_adapter(void);
4798
Akinobu Mita82069372013-10-14 22:48:04 +09004799static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4800 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004802 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004804 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 if (delta_hosts > 0) {
4807 do {
4808 sdebug_add_adapter();
4809 } while (--delta_hosts);
4810 } else if (delta_hosts < 0) {
4811 do {
4812 sdebug_remove_adapter();
4813 } while (++delta_hosts);
4814 }
4815 return count;
4816}
Akinobu Mita82069372013-10-14 22:48:04 +09004817static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818
Akinobu Mita82069372013-10-14 22:48:04 +09004819static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004820{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004821 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004822}
Akinobu Mita82069372013-10-14 22:48:04 +09004823static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4824 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004825{
4826 int n;
4827
4828 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004829 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004830 return count;
4831 }
4832 return -EINVAL;
4833}
Akinobu Mita82069372013-10-14 22:48:04 +09004834static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004835
Douglas Gilbertc4837392016-05-06 00:40:26 -04004836static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4837{
4838 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4839}
4840static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4841 size_t count)
4842{
4843 int n;
4844
4845 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4846 if (n > 0)
4847 sdebug_statistics = true;
4848 else {
4849 clear_queue_stats();
4850 sdebug_statistics = false;
4851 }
4852 return count;
4853 }
4854 return -EINVAL;
4855}
4856static DRIVER_ATTR_RW(statistics);
4857
Akinobu Mita82069372013-10-14 22:48:04 +09004858static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004859{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004860 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004861}
Akinobu Mita82069372013-10-14 22:48:04 +09004862static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004863
Douglas Gilbertc4837392016-05-06 00:40:26 -04004864static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4865{
4866 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4867}
4868static DRIVER_ATTR_RO(submit_queues);
4869
Akinobu Mita82069372013-10-14 22:48:04 +09004870static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004871{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004872 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004873}
Akinobu Mita82069372013-10-14 22:48:04 +09004874static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004875
Akinobu Mita82069372013-10-14 22:48:04 +09004876static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004877{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004878 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004879}
Akinobu Mita82069372013-10-14 22:48:04 +09004880static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004881
Akinobu Mita82069372013-10-14 22:48:04 +09004882static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004883{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004884 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004885}
Akinobu Mita82069372013-10-14 22:48:04 +09004886static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004887
Akinobu Mita82069372013-10-14 22:48:04 +09004888static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004889{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004890 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004891}
Akinobu Mita82069372013-10-14 22:48:04 +09004892static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004893
Akinobu Mita82069372013-10-14 22:48:04 +09004894static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004895{
4896 ssize_t count;
4897
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004898 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004899 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4900 sdebug_store_sectors);
4901
Tejun Heoc7badc92015-02-13 14:37:51 -08004902 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4903 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004904 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004905 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004906
4907 return count;
4908}
Akinobu Mita82069372013-10-14 22:48:04 +09004909static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004910
Akinobu Mita82069372013-10-14 22:48:04 +09004911static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004912{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004913 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004914}
Akinobu Mita82069372013-10-14 22:48:04 +09004915static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4916 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004917{
4918 int n;
4919
4920 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004921 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004922 return count;
4923 }
4924 return -EINVAL;
4925}
Akinobu Mita82069372013-10-14 22:48:04 +09004926static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004927
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004928static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4929{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004930 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004931}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004932/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004933static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4934 size_t count)
4935{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004936 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004937
4938 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004939 sdebug_host_lock = (n > 0);
4940 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004941 }
4942 return -EINVAL;
4943}
4944static DRIVER_ATTR_RW(host_lock);
4945
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004946static ssize_t strict_show(struct device_driver *ddp, char *buf)
4947{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004948 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004949}
4950static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4951 size_t count)
4952{
4953 int n;
4954
4955 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004956 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004957 return count;
4958 }
4959 return -EINVAL;
4960}
4961static DRIVER_ATTR_RW(strict);
4962
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004963static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
4964{
4965 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
4966}
4967static DRIVER_ATTR_RO(uuid_ctl);
4968
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004969static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
4970{
4971 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
4972}
4973static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
4974 size_t count)
4975{
4976 int ret, n;
4977
4978 ret = kstrtoint(buf, 0, &n);
4979 if (ret)
4980 return ret;
4981 sdebug_cdb_len = n;
4982 all_config_cdb_len();
4983 return count;
4984}
4985static DRIVER_ATTR_RW(cdb_len);
4986
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004987
Akinobu Mita82069372013-10-14 22:48:04 +09004988/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004989 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4990 files (over those found in the /sys/module/scsi_debug/parameters
4991 directory) is that auxiliary actions can be triggered when an attribute
4992 is changed. For example see: sdebug_add_host_store() above.
4993 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004994
Akinobu Mita82069372013-10-14 22:48:04 +09004995static struct attribute *sdebug_drv_attrs[] = {
4996 &driver_attr_delay.attr,
4997 &driver_attr_opts.attr,
4998 &driver_attr_ptype.attr,
4999 &driver_attr_dsense.attr,
5000 &driver_attr_fake_rw.attr,
5001 &driver_attr_no_lun_0.attr,
5002 &driver_attr_num_tgts.attr,
5003 &driver_attr_dev_size_mb.attr,
5004 &driver_attr_num_parts.attr,
5005 &driver_attr_every_nth.attr,
5006 &driver_attr_max_luns.attr,
5007 &driver_attr_max_queue.attr,
5008 &driver_attr_no_uld.attr,
5009 &driver_attr_scsi_level.attr,
5010 &driver_attr_virtual_gb.attr,
5011 &driver_attr_add_host.attr,
5012 &driver_attr_vpd_use_hostno.attr,
5013 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005014 &driver_attr_statistics.attr,
5015 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005016 &driver_attr_dix.attr,
5017 &driver_attr_dif.attr,
5018 &driver_attr_guard.attr,
5019 &driver_attr_ato.attr,
5020 &driver_attr_map.attr,
5021 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005022 &driver_attr_host_lock.attr,
5023 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005024 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005025 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005026 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005027 NULL,
5028};
5029ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005031static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005032
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033static int __init scsi_debug_init(void)
5034{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005035 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 int host_to_add;
5037 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005038 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005040 atomic_set(&retired_max_queue, 0);
5041
Douglas Gilbert773642d2016-04-25 12:16:28 -04005042 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005043 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005044 sdebug_ndelay = 0;
5045 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005046 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005047
Douglas Gilbert773642d2016-04-25 12:16:28 -04005048 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04005049 case 512:
5050 case 1024:
5051 case 2048:
5052 case 4096:
5053 break;
5054 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005055 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005056 return -EINVAL;
5057 }
5058
Douglas Gilbert773642d2016-04-25 12:16:28 -04005059 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005060 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005061 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005062 case T10_PI_TYPE1_PROTECTION:
5063 case T10_PI_TYPE2_PROTECTION:
5064 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005065 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005066 break;
5067
5068 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005069 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005070 return -EINVAL;
5071 }
5072
Douglas Gilbert773642d2016-04-25 12:16:28 -04005073 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005074 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005075 return -EINVAL;
5076 }
5077
Douglas Gilbert773642d2016-04-25 12:16:28 -04005078 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005079 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005080 return -EINVAL;
5081 }
5082
Douglas Gilbert773642d2016-04-25 12:16:28 -04005083 if (sdebug_physblk_exp > 15) {
5084 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005085 return -EINVAL;
5086 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005087 if (sdebug_max_luns > 256) {
5088 pr_warn("max_luns can be no more than 256, use default\n");
5089 sdebug_max_luns = DEF_MAX_LUNS;
5090 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005091
Douglas Gilbert773642d2016-04-25 12:16:28 -04005092 if (sdebug_lowest_aligned > 0x3fff) {
5093 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005094 return -EINVAL;
5095 }
5096
Douglas Gilbertc4837392016-05-06 00:40:26 -04005097 if (submit_queues < 1) {
5098 pr_err("submit_queues must be 1 or more\n");
5099 return -EINVAL;
5100 }
5101 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5102 GFP_KERNEL);
5103 if (sdebug_q_arr == NULL)
5104 return -ENOMEM;
5105 for (k = 0; k < submit_queues; ++k)
5106 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5107
Douglas Gilbert773642d2016-04-25 12:16:28 -04005108 if (sdebug_dev_size_mb < 1)
5109 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5110 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5111 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005112 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113
5114 /* play around with geometry, don't waste too much on track 0 */
5115 sdebug_heads = 8;
5116 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005117 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005119 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005120 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5122 (sdebug_sectors_per * sdebug_heads);
5123 if (sdebug_cylinders_per >= 1024) {
5124 /* other LLDs do this; implies >= 1GB ram disk ... */
5125 sdebug_heads = 255;
5126 sdebug_sectors_per = 63;
5127 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5128 (sdebug_sectors_per * sdebug_heads);
5129 }
5130
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005131 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005132 fake_storep = vmalloc(sz);
5133 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005134 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005135 ret = -ENOMEM;
5136 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005137 }
5138 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005139 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005140 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142
Douglas Gilbert773642d2016-04-25 12:16:28 -04005143 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005144 int dif_size;
5145
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005146 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005147 dif_storep = vmalloc(dif_size);
5148
Tomas Winklerc12879702015-07-28 16:54:20 +03005149 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005150
5151 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005152 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005153 ret = -ENOMEM;
5154 goto free_vm;
5155 }
5156
5157 memset(dif_storep, 0xff, dif_size);
5158 }
5159
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005160 /* Logical Block Provisioning */
5161 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005162 sdebug_unmap_max_blocks =
5163 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005164
Douglas Gilbert773642d2016-04-25 12:16:28 -04005165 sdebug_unmap_max_desc =
5166 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005167
Douglas Gilbert773642d2016-04-25 12:16:28 -04005168 sdebug_unmap_granularity =
5169 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005170
Douglas Gilbert773642d2016-04-25 12:16:28 -04005171 if (sdebug_unmap_alignment &&
5172 sdebug_unmap_granularity <=
5173 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005174 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005175 ret = -EINVAL;
5176 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005177 }
5178
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005179 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5180 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005181
Tomas Winklerc12879702015-07-28 16:54:20 +03005182 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005183
5184 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005185 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005186 ret = -ENOMEM;
5187 goto free_vm;
5188 }
5189
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005190 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005191
5192 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005193 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005194 map_region(0, 2);
5195 }
5196
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005197 pseudo_primary = root_device_register("pseudo_0");
5198 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005199 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005200 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005201 goto free_vm;
5202 }
5203 ret = bus_register(&pseudo_lld_bus);
5204 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005205 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005206 goto dev_unreg;
5207 }
5208 ret = driver_register(&sdebug_driverfs_driver);
5209 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005210 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005211 goto bus_unreg;
5212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213
Douglas Gilbert773642d2016-04-25 12:16:28 -04005214 host_to_add = sdebug_add_host;
5215 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216
Douglas Gilbert9a051012017-12-23 12:48:10 -05005217 for (k = 0; k < host_to_add; k++) {
5218 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005219 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005220 break;
5221 }
5222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223
Douglas Gilbert773642d2016-04-25 12:16:28 -04005224 if (sdebug_verbose)
5225 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005226
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005228
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005229bus_unreg:
5230 bus_unregister(&pseudo_lld_bus);
5231dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005232 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005233free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005234 vfree(map_storep);
5235 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005236 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005237free_q_arr:
5238 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005239 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240}
5241
5242static void __exit scsi_debug_exit(void)
5243{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005244 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245
5246 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005247 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 for (; k; k--)
5249 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 driver_unregister(&sdebug_driverfs_driver);
5251 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005252 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005254 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005255 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005257 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258}
5259
5260device_initcall(scsi_debug_init);
5261module_exit(scsi_debug_exit);
5262
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263static void sdebug_release_adapter(struct device * dev)
5264{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005265 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266
5267 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005268 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269}
5270
5271static int sdebug_add_adapter(void)
5272{
5273 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005274 int error = 0;
5275 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005276 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277
Douglas Gilbert9a051012017-12-23 12:48:10 -05005278 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5279 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005280 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005281 return -ENOMEM;
5282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283
Douglas Gilbert9a051012017-12-23 12:48:10 -05005284 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285
Douglas Gilbert773642d2016-04-25 12:16:28 -04005286 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005287 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005288 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5289 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005290 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005291 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005293 }
5294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295
Douglas Gilbert9a051012017-12-23 12:48:10 -05005296 spin_lock(&sdebug_host_list_lock);
5297 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5298 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299
Douglas Gilbert9a051012017-12-23 12:48:10 -05005300 sdbg_host->dev.bus = &pseudo_lld_bus;
5301 sdbg_host->dev.parent = pseudo_primary;
5302 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005303 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304
Douglas Gilbert9a051012017-12-23 12:48:10 -05005305 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306
Douglas Gilbert9a051012017-12-23 12:48:10 -05005307 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 goto clean;
5309
Douglas Gilbert773642d2016-04-25 12:16:28 -04005310 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005311 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312
5313clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005314 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5315 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 list_del(&sdbg_devinfo->dev_list);
5317 kfree(sdbg_devinfo);
5318 }
5319
5320 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005321 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322}
5323
5324static void sdebug_remove_adapter(void)
5325{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005326 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327
Douglas Gilbert9a051012017-12-23 12:48:10 -05005328 spin_lock(&sdebug_host_list_lock);
5329 if (!list_empty(&sdebug_host_list)) {
5330 sdbg_host = list_entry(sdebug_host_list.prev,
5331 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 list_del(&sdbg_host->host_list);
5333 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005334 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335
5336 if (!sdbg_host)
5337 return;
5338
Douglas Gilbert773642d2016-04-25 12:16:28 -04005339 device_unregister(&sdbg_host->dev);
5340 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341}
5342
Douglas Gilbertfd321192016-04-25 12:16:33 -04005343static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005344{
5345 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005346 struct sdebug_dev_info *devip;
5347
Douglas Gilbertc4837392016-05-06 00:40:26 -04005348 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005349 devip = (struct sdebug_dev_info *)sdev->hostdata;
5350 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005351 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005352 return -ENODEV;
5353 }
5354 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005355
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005356 if (qdepth < 1)
5357 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005358 /* allow to exceed max host qc_arr elements for testing */
5359 if (qdepth > SDEBUG_CANQUEUE + 10)
5360 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005361 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005362
Douglas Gilbert773642d2016-04-25 12:16:28 -04005363 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005364 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005365 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005366 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005367 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005368 return sdev->queue_depth;
5369}
5370
Douglas Gilbertc4837392016-05-06 00:40:26 -04005371static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005372{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005373 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005374 if (sdebug_every_nth < -1)
5375 sdebug_every_nth = -1;
5376 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005377 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005378 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005379 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005380 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005381 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005382 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005383}
5384
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005385static bool fake_host_busy(struct scsi_cmnd *scp)
5386{
5387 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5388 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5389}
5390
Douglas Gilbertfd321192016-04-25 12:16:33 -04005391static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5392 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005393{
5394 u8 sdeb_i;
5395 struct scsi_device *sdp = scp->device;
5396 const struct opcode_info_t *oip;
5397 const struct opcode_info_t *r_oip;
5398 struct sdebug_dev_info *devip;
5399 u8 *cmd = scp->cmnd;
5400 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5401 int k, na;
5402 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005403 u32 flags;
5404 u16 sa;
5405 u8 opcode = cmd[0];
5406 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005407
5408 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005409 if (sdebug_statistics)
5410 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005411 if (unlikely(sdebug_verbose &&
5412 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005413 char b[120];
5414 int n, len, sb;
5415
5416 len = scp->cmd_len;
5417 sb = (int)sizeof(b);
5418 if (len > 32)
5419 strcpy(b, "too long, over 32 bytes");
5420 else {
5421 for (k = 0, n = 0; k < len && n < sb; ++k)
5422 n += scnprintf(b + n, sb - n, "%02x ",
5423 (u32)cmd[k]);
5424 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005425 if (sdebug_mq_active)
5426 sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5427 my_name, blk_mq_unique_tag(scp->request),
5428 b);
5429 else
5430 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5431 b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005432 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005433 if (fake_host_busy(scp))
5434 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005435 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005436 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5437 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005438
5439 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5440 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5441 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005442 if (unlikely(!devip)) {
5443 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005444 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005445 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005446 }
5447 na = oip->num_attached;
5448 r_pfp = oip->pfp;
5449 if (na) { /* multiple commands with this opcode */
5450 r_oip = oip;
5451 if (FF_SA & r_oip->flags) {
5452 if (F_SA_LOW & oip->flags)
5453 sa = 0x1f & cmd[1];
5454 else
5455 sa = get_unaligned_be16(cmd + 8);
5456 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5457 if (opcode == oip->opcode && sa == oip->sa)
5458 break;
5459 }
5460 } else { /* since no service action only check opcode */
5461 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5462 if (opcode == oip->opcode)
5463 break;
5464 }
5465 }
5466 if (k > na) {
5467 if (F_SA_LOW & r_oip->flags)
5468 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5469 else if (F_SA_HIGH & r_oip->flags)
5470 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5471 else
5472 mk_sense_invalid_opcode(scp);
5473 goto check_cond;
5474 }
5475 } /* else (when na==0) we assume the oip is a match */
5476 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005477 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005478 mk_sense_invalid_opcode(scp);
5479 goto check_cond;
5480 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005481 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005482 if (sdebug_verbose)
5483 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5484 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005485 mk_sense_invalid_opcode(scp);
5486 goto check_cond;
5487 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005488 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005489 u8 rem;
5490 int j;
5491
5492 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5493 rem = ~oip->len_mask[k] & cmd[k];
5494 if (rem) {
5495 for (j = 7; j >= 0; --j, rem <<= 1) {
5496 if (0x80 & rem)
5497 break;
5498 }
5499 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5500 goto check_cond;
5501 }
5502 }
5503 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005504 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005505 find_first_bit(devip->uas_bm,
5506 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005507 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005508 if (errsts)
5509 goto check_cond;
5510 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005511 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005512 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005513 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005514 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5515 "%s\n", my_name, "initializing command "
5516 "required");
5517 errsts = check_condition_result;
5518 goto fini;
5519 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005520 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005521 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005522 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005523 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005524 return 0; /* ignore command: make trouble */
5525 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005526 if (likely(oip->pfp))
5527 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005528 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5529 errsts = r_pfp(scp, devip);
5530
5531fini:
5532 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005533 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005534check_cond:
5535 return schedule_resp(scp, devip, check_condition_result, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005536err_out:
5537 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005538}
5539
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005540static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005541 .show_info = scsi_debug_show_info,
5542 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005543 .proc_name = sdebug_proc_name,
5544 .name = "SCSI DEBUG",
5545 .info = scsi_debug_info,
5546 .slave_alloc = scsi_debug_slave_alloc,
5547 .slave_configure = scsi_debug_slave_configure,
5548 .slave_destroy = scsi_debug_slave_destroy,
5549 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005550 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005551 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005552 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005553 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005554 .eh_target_reset_handler = scsi_debug_target_reset,
5555 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005556 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005557 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005558 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005559 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005560 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005561 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005562 .use_clustering = DISABLE_CLUSTERING,
5563 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005564 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005565};
5566
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567static int sdebug_driver_probe(struct device * dev)
5568{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005569 int error = 0;
5570 struct sdebug_host_info *sdbg_host;
5571 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005572 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573
5574 sdbg_host = to_sdebug_host(dev);
5575
Douglas Gilbert773642d2016-04-25 12:16:28 -04005576 sdebug_driver_template.can_queue = sdebug_max_queue;
5577 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005578 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005579 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5580 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005581 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005582 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005584 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005585 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005586 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005587 my_name, submit_queues, nr_cpu_ids);
5588 submit_queues = nr_cpu_ids;
5589 }
5590 /* Decide whether to tell scsi subsystem that we want mq */
5591 /* Following should give the same answer for each host */
5592 sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5593 if (sdebug_mq_active)
5594 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595
Douglas Gilbert9a051012017-12-23 12:48:10 -05005596 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005598 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5599 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005601 hpnt->max_id = sdebug_num_tgts;
5602 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005603 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005605 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005606
Douglas Gilbert773642d2016-04-25 12:16:28 -04005607 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005608
Christoph Hellwig8475c812016-09-11 19:35:41 +02005609 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005610 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005611 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005612 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005613 break;
5614
Christoph Hellwig8475c812016-09-11 19:35:41 +02005615 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005616 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005617 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005618 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005619 break;
5620
Christoph Hellwig8475c812016-09-11 19:35:41 +02005621 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005622 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005623 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005624 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005625 break;
5626
5627 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005628 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005629 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005630 break;
5631 }
5632
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005633 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005634
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005635 if (have_dif_prot || sdebug_dix)
5636 pr_info("host protection%s%s%s%s%s%s%s\n",
5637 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5638 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5639 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5640 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5641 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5642 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5643 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005644
Douglas Gilbert773642d2016-04-25 12:16:28 -04005645 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005646 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5647 else
5648 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5649
Douglas Gilbert773642d2016-04-25 12:16:28 -04005650 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5651 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005652 if (sdebug_every_nth) /* need stats counters for every_nth */
5653 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005654 error = scsi_add_host(hpnt, &sdbg_host->dev);
5655 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005656 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005657 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005659 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 scsi_scan_host(hpnt);
5661
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005662 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663}
5664
5665static int sdebug_driver_remove(struct device * dev)
5666{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005667 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005668 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
5670 sdbg_host = to_sdebug_host(dev);
5671
5672 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005673 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674 return -ENODEV;
5675 }
5676
Douglas Gilbert9a051012017-12-23 12:48:10 -05005677 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005679 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5680 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005681 list_del(&sdbg_devinfo->dev_list);
5682 kfree(sdbg_devinfo);
5683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684
Douglas Gilbert9a051012017-12-23 12:48:10 -05005685 scsi_host_put(sdbg_host->shost);
5686 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687}
5688
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005689static int pseudo_lld_bus_match(struct device *dev,
5690 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005692 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005693}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005694
5695static struct bus_type pseudo_lld_bus = {
5696 .name = "pseudo",
5697 .match = pseudo_lld_bus_match,
5698 .probe = sdebug_driver_probe,
5699 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005700 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005701};