blob: b8f83c4e2c81ca9ea5b18e9d6ba79e2114313e8d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05009 * Copyright (C) 2001 - 2017 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Douglas Gilbert773642d2016-04-25 12:16:28 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040016 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Tomas Winklerc12879702015-07-28 16:54:20 +030020
21#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040027#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/types.h>
30#include <linux/string.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <linux/init.h>
34#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/vmalloc.h>
36#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020037#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050039#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040040#include <linux/spinlock.h>
41#include <linux/interrupt.h>
42#include <linux/atomic.h>
43#include <linux/hrtimer.h>
Douglas Gilbert09ba24c2016-05-06 00:40:28 -040044#include <linux/uuid.h>
Christoph Hellwig6ebf1052016-09-11 19:35:39 +020045#include <linux/t10-pi.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050046
47#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090048
Martin K. Petersen44d92692009-10-15 14:45:27 -040049#include <asm/unaligned.h>
50
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090051#include <scsi/scsi.h>
52#include <scsi/scsi_cmnd.h>
53#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <scsi/scsi_host.h>
55#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090056#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040057#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040058#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Martin K. Petersenc6a44282009-01-04 03:08:19 -050060#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Douglas Gilbert773642d2016-04-25 12:16:28 -040063/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbert9b760fd2017-12-05 00:05:49 -050064#define SDEBUG_VERSION "0187" /* format to fit INQUIRY revision field */
65static const char *sdebug_version_date = "20171202";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040066
67#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define NO_ADDITIONAL_SENSE 0x0
71#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050072#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040074#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050076#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040078#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040079#define UA_RESET_ASC 0x29
80#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050081#define TARGET_CHANGED_ASC 0x3f
82#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050083#define INSUFF_RES_ASC 0x55
84#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040085#define POWER_ON_RESET_ASCQ 0x0
86#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
87#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050088#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050090#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define THRESHOLD_EXCEEDED 0x5d
92#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050093#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050094#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
95#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Douglas Gilbert481b5e52017-12-23 12:48:14 -050096#define WRITE_ERROR_ASC 0xc
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050098/* Additional Sense Code Qualifier (ASCQ) */
99#define ACK_NAK_TO 0x3
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/* Default values for driver parameters */
102#define DEF_NUM_HOST 1
103#define DEF_NUM_TGTS 1
104#define DEF_MAX_LUNS 1
105/* With these defaults, this driver will make 1 host with 1 target
106 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
107 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500108#define DEF_ATO 1
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500109#define DEF_CDB_LEN 10
Douglas Gilbertc2206092016-04-25 12:16:31 -0400110#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500112#define DEF_DIF 0
113#define DEF_DIX 0
114#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500116#define DEF_FAKE_RW 0
117#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400118#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_LBPU 0
120#define DEF_LBPWS 0
121#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600122#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500123#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400124#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500125#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#define DEF_NUM_PARTS 0
127#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500128#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500129#define DEF_PHYSBLK_EXP 0
Lukas Herbolt86e68282017-01-26 10:00:37 +0100130#define DEF_OPT_XFERLEN_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400131#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200132#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400133#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500134#define DEF_SECTOR_SIZE 512
135#define DEF_UNMAP_ALIGNMENT 0
136#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400137#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
138#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500139#define DEF_VIRTUAL_GB 0
140#define DEF_VPD_USE_HOSTNO 1
141#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500142#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400143#define DEF_STATISTICS false
144#define DEF_SUBMIT_QUEUES 1
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400145#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400146#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400148#define SDEBUG_LUN_0_VAL 0
149
Douglas Gilbert773642d2016-04-25 12:16:28 -0400150/* bit mask values for sdebug_opts */
151#define SDEBUG_OPT_NOISE 1
152#define SDEBUG_OPT_MEDIUM_ERR 2
153#define SDEBUG_OPT_TIMEOUT 4
154#define SDEBUG_OPT_RECOVERED_ERR 8
155#define SDEBUG_OPT_TRANSPORT_ERR 16
156#define SDEBUG_OPT_DIF_ERR 32
157#define SDEBUG_OPT_DIX_ERR 64
158#define SDEBUG_OPT_MAC_TIMEOUT 128
159#define SDEBUG_OPT_SHORT_TRANSFER 0x100
160#define SDEBUG_OPT_Q_NOISE 0x200
161#define SDEBUG_OPT_ALL_TSF 0x400
162#define SDEBUG_OPT_RARE_TSF 0x800
163#define SDEBUG_OPT_N_WCE 0x1000
164#define SDEBUG_OPT_RESET_NOISE 0x2000
165#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800166#define SDEBUG_OPT_HOST_BUSY 0x8000
Douglas Gilbert773642d2016-04-25 12:16:28 -0400167#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
168 SDEBUG_OPT_RESET_NOISE)
169#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
170 SDEBUG_OPT_TRANSPORT_ERR | \
171 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800172 SDEBUG_OPT_SHORT_TRANSFER | \
173 SDEBUG_OPT_HOST_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400175 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400177 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500178 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400179 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 *
181 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400182 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400184 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500185 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400186 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
187 * This will continue on every subsequent command until some other action
188 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
189 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 */
191
Douglas Gilbertfd321192016-04-25 12:16:33 -0400192/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400193 * priority order. In the subset implemented here lower numbers have higher
194 * priority. The UA numbers should be a sequence starting from 0 with
195 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
196#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
197#define SDEBUG_UA_BUS_RESET 1
198#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500199#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500200#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500201#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
202#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
203#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400204
Douglas Gilbert773642d2016-04-25 12:16:28 -0400205/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 * sector on read commands: */
207#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500208#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
211 * or "peripheral device" addressing (value 0) */
212#define SAM2_LUN_ADDRESS_METHOD 0
213
Douglas Gilbertc4837392016-05-06 00:40:26 -0400214/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215 * (for response) per submit queue at one time. Can be reduced by max_queue
216 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219 * but cannot exceed SDEBUG_CANQUEUE .
220 */
221#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
222#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400223#define DEF_CMD_PER_LUN 255
224
Douglas Gilbertfd321192016-04-25 12:16:33 -0400225#define F_D_IN 1
226#define F_D_OUT 2
227#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
228#define F_D_UNKN 8
229#define F_RL_WLUN_OK 0x10
230#define F_SKIP_UA 0x20
231#define F_DELAY_OVERR 0x40
232#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
233#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
234#define F_INV_OP 0x200
235#define F_FAKE_RW 0x400
236#define F_M_ACCESS 0x800 /* media access */
237
238#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500239#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400240#define FF_SA (F_SA_HIGH | F_SA_LOW)
241
242#define SDEBUG_MAX_PARTS 4
243
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400244#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400245
246
247struct sdebug_dev_info {
248 struct list_head dev_list;
249 unsigned int channel;
250 unsigned int target;
251 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200252 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400253 struct sdebug_host_info *sdbg_host;
254 unsigned long uas_bm[1];
255 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400256 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400257 bool used;
258};
259
260struct sdebug_host_info {
261 struct list_head host_list;
262 struct Scsi_Host *shost;
263 struct device dev;
264 struct list_head dev_info_list;
265};
266
267#define to_sdebug_host(d) \
268 container_of(d, struct sdebug_host_info, dev)
269
270struct sdebug_defer {
271 struct hrtimer hrt;
272 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400273 int sqa_idx; /* index of sdebug_queue array */
274 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
275 int issuing_cpu;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400276};
277
278struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400279 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
280 * instance indicates this slot is in use.
281 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400282 struct sdebug_defer *sd_dp;
283 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400284 unsigned int inj_recovered:1;
285 unsigned int inj_transport:1;
286 unsigned int inj_dif:1;
287 unsigned int inj_dix:1;
288 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800289 unsigned int inj_host_busy:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400290};
291
Douglas Gilbertc4837392016-05-06 00:40:26 -0400292struct sdebug_queue {
293 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
294 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
295 spinlock_t qc_lock;
296 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400297};
298
Douglas Gilbertc4837392016-05-06 00:40:26 -0400299static atomic_t sdebug_cmnd_count; /* number of incoming commands */
300static atomic_t sdebug_completions; /* count of deferred completions */
301static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
302static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
303
Douglas Gilbertfd321192016-04-25 12:16:33 -0400304struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400305 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
306 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400307 u8 opcode; /* if num_attached > 0, preferred */
308 u16 sa; /* service action */
309 u32 flags; /* OR-ed set of SDEB_F_* */
310 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
311 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500312 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
313 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400314};
315
316/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500317enum sdeb_opcode_index {
318 SDEB_I_INVALID_OPCODE = 0,
319 SDEB_I_INQUIRY = 1,
320 SDEB_I_REPORT_LUNS = 2,
321 SDEB_I_REQUEST_SENSE = 3,
322 SDEB_I_TEST_UNIT_READY = 4,
323 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
324 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
325 SDEB_I_LOG_SENSE = 7,
326 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
327 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
328 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
329 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500330 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
331 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500332 SDEB_I_MAINT_IN = 14,
333 SDEB_I_MAINT_OUT = 15,
334 SDEB_I_VERIFY = 16, /* 10 only */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500335 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500336 SDEB_I_RESERVE = 18, /* 6, 10 */
337 SDEB_I_RELEASE = 19, /* 6, 10 */
338 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
339 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
340 SDEB_I_ATA_PT = 22, /* 12, 16 */
341 SDEB_I_SEND_DIAG = 23,
342 SDEB_I_UNMAP = 24,
343 SDEB_I_XDWRITEREAD = 25, /* 10 only */
344 SDEB_I_WRITE_BUFFER = 26,
345 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
346 SDEB_I_SYNC_CACHE = 28, /* 10 only */
347 SDEB_I_COMP_WRITE = 29,
Douglas Gilbert9a051012017-12-23 12:48:10 -0500348 SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500349};
350
Douglas Gilbertc4837392016-05-06 00:40:26 -0400351
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500352static const unsigned char opcode_ind_arr[256] = {
353/* 0x0; 0x0->0x1f: 6 byte cdbs */
354 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
355 0, 0, 0, 0,
356 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
357 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
358 SDEB_I_RELEASE,
359 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
360 SDEB_I_ALLOW_REMOVAL, 0,
361/* 0x20; 0x20->0x3f: 10 byte cdbs */
362 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
363 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
364 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
365 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
366/* 0x40; 0x40->0x5f: 10 byte cdbs */
367 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
369 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
370 SDEB_I_RELEASE,
371 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400372/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
375 0, SDEB_I_VARIABLE_LEN,
376/* 0x80; 0x80->0x9f: 16 byte cdbs */
377 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
378 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
379 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500380 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 -0500381/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
382 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
383 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500384 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
385 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500386 0, 0, 0, 0, 0, 0, 0, 0,
387 0, 0, 0, 0, 0, 0, 0, 0,
388/* 0xc0; 0xc0->0xff: vendor specific */
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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
393};
394
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500395static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
396static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
397static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
398static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
399static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
400static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
401static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
402static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
403static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500404static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500405static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
406static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
407static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
408static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
409static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500410static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
411static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500412static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
413static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
414static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500415static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500416static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500417
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500418/*
419 * The following are overflow arrays for cdbs that "hit" the same index in
420 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
421 * should be placed in opcode_info_arr[], the others should be placed here.
422 */
423static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500424 {0, 0x1a, 0, F_D_IN, NULL, NULL,
425 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
426};
427
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500428static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500429 {0, 0x15, 0, F_D_OUT, NULL, NULL,
430 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
431};
432
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500433static const struct opcode_info_t read_iarr[] = {
434 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500435 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500436 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500437 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500438 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500439 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500440 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500441 0xc7, 0, 0, 0, 0} },
442};
443
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500444static const struct opcode_info_t write_iarr[] = {
445 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
446 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
447 0, 0, 0, 0, 0, 0} },
448 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
449 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
450 0, 0, 0} },
451 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
452 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
453 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500454};
455
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500456static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500457 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
458 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500459 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500460};
461
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500462static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
463 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500464 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500465 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500466 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
467 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
468 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500469};
470
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500471static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500472 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500473 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500474 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500475 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500476 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500477 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500478};
479
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500480static const struct opcode_info_t write_same_iarr[] = {
481 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500482 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500483 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500484};
485
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500486static const struct opcode_info_t reserve_iarr[] = {
487 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500488 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
489};
490
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500491static const struct opcode_info_t release_iarr[] = {
492 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500493 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
494};
495
496
497/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
498 * plus the terminating elements for logic that scans this table such as
499 * REPORT SUPPORTED OPERATION CODES. */
500static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
501/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500502 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500503 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500504 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500505 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
506 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
507 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500508 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500509 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
510 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
511 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
512 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500513/* 5 */
514 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
515 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
516 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
517 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
518 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
519 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
520 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500521 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
522 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500523 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500524 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
525 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500526 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
527 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
528 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500529/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500530 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
531 resp_write_dt0, write_iarr, /* WRITE(16) */
532 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
533 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* WRITE(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500534 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
535 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500536 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
537 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
538 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
539 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500540 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
541 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
542 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500543 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
544 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
545 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
546 0xff, 0, 0xc7, 0, 0, 0, 0} },
547/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500548 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
549 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500550 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500551 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
552 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500553 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
554 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
555 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
556 0xff, 0xff} },
557 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
558 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500559 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
560 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500561 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
562 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500563 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
564 0} },
565/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500566 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
567 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500568 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
569 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
570 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
571 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
572 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
573 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500574 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500575 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500576/* 25 */
577 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500578 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500579 0, 0, 0, 0, 0, 0} }, /* XDWRITEREAD(10) */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500580 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
581 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
582 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500583 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
584 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
585 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
586 0, 0, 0, 0, 0} },
587 {0, 0x35, 0, F_DELAY_OVERR | FF_MEDIA_IO, NULL, NULL, /* SYNC_CACHE */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500588 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500589 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500590 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500591 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500592 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500593
594/* 30 */
595 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
596 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
597};
598
Douglas Gilbert773642d2016-04-25 12:16:28 -0400599static int sdebug_add_host = DEF_NUM_HOST;
600static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500601static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400602static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400603static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
604static int sdebug_dif = DEF_DIF;
605static int sdebug_dix = DEF_DIX;
606static int sdebug_dsense = DEF_D_SENSE;
607static int sdebug_every_nth = DEF_EVERY_NTH;
608static int sdebug_fake_rw = DEF_FAKE_RW;
609static unsigned int sdebug_guard = DEF_GUARD;
610static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
611static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400612static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400613static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400614static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400615static int sdebug_no_lun_0 = DEF_NO_LUN_0;
616static int sdebug_no_uld;
617static int sdebug_num_parts = DEF_NUM_PARTS;
618static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
619static int sdebug_opt_blks = DEF_OPT_BLKS;
620static int sdebug_opts = DEF_OPTS;
621static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100622static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400623static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400624static int sdebug_scsi_level = DEF_SCSI_LEVEL;
625static int sdebug_sector_size = DEF_SECTOR_SIZE;
626static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
627static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
628static unsigned int sdebug_lbpu = DEF_LBPU;
629static unsigned int sdebug_lbpws = DEF_LBPWS;
630static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
631static unsigned int sdebug_lbprz = DEF_LBPRZ;
632static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
633static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
634static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
635static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
636static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400637static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400638static bool sdebug_removable = DEF_REMOVABLE;
639static bool sdebug_clustering;
640static bool sdebug_host_lock = DEF_HOST_LOCK;
641static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500642static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400643static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400644static bool have_dif_prot;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400645static bool sdebug_statistics = DEF_STATISTICS;
646static bool sdebug_mq_active;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400648static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649static sector_t sdebug_capacity; /* in sectors */
650
651/* old BIOS stuff, kernel may get rid of them but some mode sense pages
652 may still need them */
653static int sdebug_heads; /* heads per disk */
654static int sdebug_cylinders_per; /* cylinders per surface */
655static int sdebug_sectors_per; /* sectors per cylinder */
656
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657static LIST_HEAD(sdebug_host_list);
658static DEFINE_SPINLOCK(sdebug_host_list_lock);
659
Douglas Gilbertfd321192016-04-25 12:16:33 -0400660static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200661static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400662static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Martin K. Petersen44d92692009-10-15 14:45:27 -0400664static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400665static int num_aborts;
666static int num_dev_resets;
667static int num_target_resets;
668static int num_bus_resets;
669static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500670static int dix_writes;
671static int dix_reads;
672static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
Douglas Gilbertc4837392016-05-06 00:40:26 -0400674static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
675static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677static DEFINE_RWLOCK(atomic_rw);
678
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400679static char sdebug_proc_name[] = MY_NAME;
680static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682static struct bus_type pseudo_lld_bus;
683
684static struct device_driver sdebug_driverfs_driver = {
685 .name = sdebug_proc_name,
686 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687};
688
689static const int check_condition_result =
690 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
691
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500692static const int illegal_condition_result =
693 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
694
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400695static const int device_qfull_result =
696 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
697
Douglas Gilbertfd321192016-04-25 12:16:33 -0400698
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400699/* Only do the extra work involved in logical block provisioning if one or
700 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
701 * real reads and writes (i.e. not skipping them for speed).
702 */
703static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400704{
705 return 0 == sdebug_fake_rw &&
706 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
707}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400708
Akinobu Mita14faa942013-09-18 21:27:24 +0900709static void *fake_store(unsigned long long lba)
710{
711 lba = do_div(lba, sdebug_store_sectors);
712
Douglas Gilbert773642d2016-04-25 12:16:28 -0400713 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900714}
715
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200716static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900717{
Arnd Bergmann49413112015-11-20 17:38:28 +0100718 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900719
720 return dif_storep + sector;
721}
722
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900723static void sdebug_max_tgts_luns(void)
724{
725 struct sdebug_host_info *sdbg_host;
726 struct Scsi_Host *hpnt;
727
728 spin_lock(&sdebug_host_list_lock);
729 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
730 hpnt = sdbg_host->shost;
731 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400732 (sdebug_num_tgts > hpnt->this_id))
733 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900734 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400735 hpnt->max_id = sdebug_num_tgts;
736 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300737 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900738 }
739 spin_unlock(&sdebug_host_list_lock);
740}
741
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500742enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
743
744/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400745static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
746 enum sdeb_cmd_data c_d,
747 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500748{
749 unsigned char *sbuff;
750 u8 sks[4];
751 int sl, asc;
752
753 sbuff = scp->sense_buffer;
754 if (!sbuff) {
755 sdev_printk(KERN_ERR, scp->device,
756 "%s: sense_buffer is NULL\n", __func__);
757 return;
758 }
759 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
760 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400761 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500762 memset(sks, 0, sizeof(sks));
763 sks[0] = 0x80;
764 if (c_d)
765 sks[0] |= 0x40;
766 if (in_bit >= 0) {
767 sks[0] |= 0x8;
768 sks[0] |= 0x7 & in_bit;
769 }
770 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400771 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500772 sl = sbuff[7] + 8;
773 sbuff[7] = sl;
774 sbuff[sl] = 0x2;
775 sbuff[sl + 1] = 0x6;
776 memcpy(sbuff + sl + 4, sks, 3);
777 } else
778 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400779 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500780 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
781 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
782 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
783}
784
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400785static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900786{
787 unsigned char *sbuff;
788
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400789 sbuff = scp->sense_buffer;
790 if (!sbuff) {
791 sdev_printk(KERN_ERR, scp->device,
792 "%s: sense_buffer is NULL\n", __func__);
793 return;
794 }
795 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900796
Douglas Gilbert773642d2016-04-25 12:16:28 -0400797 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900798
Douglas Gilbert773642d2016-04-25 12:16:28 -0400799 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400800 sdev_printk(KERN_INFO, scp->device,
801 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
802 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900803}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Douglas Gilbertfd321192016-04-25 12:16:33 -0400805static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500806{
807 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
808}
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
811{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400812 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400813 if (0x1261 == cmd)
814 sdev_printk(KERN_INFO, dev,
815 "%s: BLKFLSBUF [0x1261]\n", __func__);
816 else if (0x5331 == cmd)
817 sdev_printk(KERN_INFO, dev,
818 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
819 __func__);
820 else
821 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
822 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 }
824 return -EINVAL;
825 /* return -ENOTTY; // correct return but upsets fdisk */
826}
827
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500828static void config_cdb_len(struct scsi_device *sdev)
829{
830 switch (sdebug_cdb_len) {
831 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
832 sdev->use_10_for_rw = false;
833 sdev->use_16_for_rw = false;
834 sdev->use_10_for_ms = false;
835 break;
836 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
837 sdev->use_10_for_rw = true;
838 sdev->use_16_for_rw = false;
839 sdev->use_10_for_ms = false;
840 break;
841 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
842 sdev->use_10_for_rw = true;
843 sdev->use_16_for_rw = false;
844 sdev->use_10_for_ms = true;
845 break;
846 case 16:
847 sdev->use_10_for_rw = false;
848 sdev->use_16_for_rw = true;
849 sdev->use_10_for_ms = true;
850 break;
851 case 32: /* No knobs to suggest this so same as 16 for now */
852 sdev->use_10_for_rw = false;
853 sdev->use_16_for_rw = true;
854 sdev->use_10_for_ms = true;
855 break;
856 default:
857 pr_warn("unexpected cdb_len=%d, force to 10\n",
858 sdebug_cdb_len);
859 sdev->use_10_for_rw = true;
860 sdev->use_16_for_rw = false;
861 sdev->use_10_for_ms = false;
862 sdebug_cdb_len = 10;
863 break;
864 }
865}
866
867static void all_config_cdb_len(void)
868{
869 struct sdebug_host_info *sdbg_host;
870 struct Scsi_Host *shost;
871 struct scsi_device *sdev;
872
873 spin_lock(&sdebug_host_list_lock);
874 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
875 shost = sdbg_host->shost;
876 shost_for_each_device(sdev, shost) {
877 config_cdb_len(sdev);
878 }
879 }
880 spin_unlock(&sdebug_host_list_lock);
881}
882
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500883static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
884{
885 struct sdebug_host_info *sdhp;
886 struct sdebug_dev_info *dp;
887
888 spin_lock(&sdebug_host_list_lock);
889 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
890 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
891 if ((devip->sdbg_host == dp->sdbg_host) &&
892 (devip->target == dp->target))
893 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
894 }
895 }
896 spin_unlock(&sdebug_host_list_lock);
897}
898
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400899static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400901 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400902
903 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
904 if (k != SDEBUG_NUM_UAS) {
905 const char *cp = NULL;
906
907 switch (k) {
908 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400909 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
910 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400911 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400912 cp = "power on reset";
913 break;
914 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400915 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
916 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400917 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400918 cp = "bus reset";
919 break;
920 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400921 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
922 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400923 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400924 cp = "mode parameters changed";
925 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500926 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400927 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
928 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400929 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500930 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500931 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500932 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400933 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400934 TARGET_CHANGED_ASC,
935 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400936 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500937 cp = "microcode has been changed";
938 break;
939 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400940 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500941 TARGET_CHANGED_ASC,
942 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400943 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500944 cp = "microcode has been changed without reset";
945 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500946 case SDEBUG_UA_LUNS_CHANGED:
947 /*
948 * SPC-3 behavior is to report a UNIT ATTENTION with
949 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
950 * on the target, until a REPORT LUNS command is
951 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400952 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500953 * values as struct scsi_device->scsi_level.
954 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400955 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500956 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400957 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500958 TARGET_CHANGED_ASC,
959 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400960 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500961 cp = "reported luns data has changed";
962 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400963 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400964 pr_warn("unexpected unit attention code=%d\n", k);
965 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400966 cp = "unknown";
967 break;
968 }
969 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400970 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400971 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400972 "%s reports: Unit attention: %s\n",
973 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return check_condition_result;
975 }
976 return 0;
977}
978
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400979/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900980static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 int arr_len)
982{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900983 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900984 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900986 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900988 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400989 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900990
991 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
992 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700993 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900994
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 return 0;
996}
997
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400998/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
999 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1000 * calls, not required to write in ascending offset order. Assumes resid
1001 * set to scsi_bufflen() prior to any calls.
1002 */
1003static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1004 int arr_len, unsigned int off_dst)
1005{
1006 int act_len, n;
1007 struct scsi_data_buffer *sdb = scsi_in(scp);
1008 off_t skip = off_dst;
1009
1010 if (sdb->length <= off_dst)
1011 return 0;
1012 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
1013 return DID_ERROR << 16;
1014
1015 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1016 arr, arr_len, skip);
1017 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
1018 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
1019 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
1020 sdb->resid = min(sdb->resid, n);
1021 return 0;
1022}
1023
1024/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1025 * 'arr' or -1 if error.
1026 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001027static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1028 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001030 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001032 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001034
1035 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036}
1037
1038
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001039static char sdebug_inq_vendor_id[9] = "Linux ";
1040static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001041static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001042/* Use some locally assigned NAAs for SAS addresses. */
1043static const u64 naa3_comp_a = 0x3222222000000000ULL;
1044static const u64 naa3_comp_b = 0x3333333000000000ULL;
1045static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001047/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001048static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1049 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001050 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001051 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001053 int num, port_a;
1054 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001056 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 /* T10 vendor identifier field format (faked) */
1058 arr[0] = 0x2; /* ASCII */
1059 arr[1] = 0x1;
1060 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001061 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1062 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1064 num = 8 + 16 + dev_id_str_len;
1065 arr[3] = num;
1066 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001067 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001068 if (sdebug_uuid_ctl) {
1069 /* Locally assigned UUID */
1070 arr[num++] = 0x1; /* binary (not necessarily sas) */
1071 arr[num++] = 0xa; /* PIV=0, lu, naa */
1072 arr[num++] = 0x0;
1073 arr[num++] = 0x12;
1074 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1075 arr[num++] = 0x0;
1076 memcpy(arr + num, lu_name, 16);
1077 num += 16;
1078 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001079 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001080 arr[num++] = 0x1; /* binary (not necessarily sas) */
1081 arr[num++] = 0x3; /* PIV=0, lu, naa */
1082 arr[num++] = 0x0;
1083 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001084 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001085 num += 8;
1086 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001087 /* Target relative port number */
1088 arr[num++] = 0x61; /* proto=sas, binary */
1089 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1090 arr[num++] = 0x0; /* reserved */
1091 arr[num++] = 0x4; /* length */
1092 arr[num++] = 0x0; /* reserved */
1093 arr[num++] = 0x0; /* reserved */
1094 arr[num++] = 0x0;
1095 arr[num++] = 0x1; /* relative port A */
1096 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001097 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001098 arr[num++] = 0x61; /* proto=sas, binary */
1099 arr[num++] = 0x93; /* piv=1, target port, naa */
1100 arr[num++] = 0x0;
1101 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001102 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001103 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001104 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001105 arr[num++] = 0x61; /* proto=sas, binary */
1106 arr[num++] = 0x95; /* piv=1, target port group id */
1107 arr[num++] = 0x0;
1108 arr[num++] = 0x4;
1109 arr[num++] = 0;
1110 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001111 put_unaligned_be16(port_group_id, arr + num);
1112 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001113 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001114 arr[num++] = 0x61; /* proto=sas, binary */
1115 arr[num++] = 0xa3; /* piv=1, target device, naa */
1116 arr[num++] = 0x0;
1117 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001118 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001119 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001120 /* SCSI name string: Target device identifier */
1121 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1122 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1123 arr[num++] = 0x0;
1124 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001125 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001126 num += 12;
1127 snprintf(b, sizeof(b), "%08X", target_dev_id);
1128 memcpy(arr + num, b, 8);
1129 num += 8;
1130 memset(arr + num, 0, 4);
1131 num += 4;
1132 return num;
1133}
1134
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001135static unsigned char vpd84_data[] = {
1136/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1137 0x22,0x22,0x22,0x0,0xbb,0x1,
1138 0x22,0x22,0x22,0x0,0xbb,0x2,
1139};
1140
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001141/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001142static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001143{
1144 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1145 return sizeof(vpd84_data);
1146}
1147
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001148/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001149static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001150{
1151 int num = 0;
1152 const char * na1 = "https://www.kernel.org/config";
1153 const char * na2 = "http://www.kernel.org/log";
1154 int plen, olen;
1155
1156 arr[num++] = 0x1; /* lu, storage config */
1157 arr[num++] = 0x0; /* reserved */
1158 arr[num++] = 0x0;
1159 olen = strlen(na1);
1160 plen = olen + 1;
1161 if (plen % 4)
1162 plen = ((plen / 4) + 1) * 4;
1163 arr[num++] = plen; /* length, null termianted, padded */
1164 memcpy(arr + num, na1, olen);
1165 memset(arr + num + olen, 0, plen - olen);
1166 num += plen;
1167
1168 arr[num++] = 0x4; /* lu, logging */
1169 arr[num++] = 0x0; /* reserved */
1170 arr[num++] = 0x0;
1171 olen = strlen(na2);
1172 plen = olen + 1;
1173 if (plen % 4)
1174 plen = ((plen / 4) + 1) * 4;
1175 arr[num++] = plen; /* length, null terminated, padded */
1176 memcpy(arr + num, na2, olen);
1177 memset(arr + num + olen, 0, plen - olen);
1178 num += plen;
1179
1180 return num;
1181}
1182
1183/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001184static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001185{
1186 int num = 0;
1187 int port_a, port_b;
1188
1189 port_a = target_dev_id + 1;
1190 port_b = port_a + 1;
1191 arr[num++] = 0x0; /* reserved */
1192 arr[num++] = 0x0; /* reserved */
1193 arr[num++] = 0x0;
1194 arr[num++] = 0x1; /* relative port 1 (primary) */
1195 memset(arr + num, 0, 6);
1196 num += 6;
1197 arr[num++] = 0x0;
1198 arr[num++] = 12; /* length tp descriptor */
1199 /* naa-5 target port identifier (A) */
1200 arr[num++] = 0x61; /* proto=sas, binary */
1201 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1202 arr[num++] = 0x0; /* reserved */
1203 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001204 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001205 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001206 arr[num++] = 0x0; /* reserved */
1207 arr[num++] = 0x0; /* reserved */
1208 arr[num++] = 0x0;
1209 arr[num++] = 0x2; /* relative port 2 (secondary) */
1210 memset(arr + num, 0, 6);
1211 num += 6;
1212 arr[num++] = 0x0;
1213 arr[num++] = 12; /* length tp descriptor */
1214 /* naa-5 target port identifier (B) */
1215 arr[num++] = 0x61; /* proto=sas, binary */
1216 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1217 arr[num++] = 0x0; /* reserved */
1218 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001219 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001220 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001221
1222 return num;
1223}
1224
1225
1226static unsigned char vpd89_data[] = {
1227/* from 4th byte */ 0,0,0,0,
1228'l','i','n','u','x',' ',' ',' ',
1229'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1230'1','2','3','4',
12310x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12320xec,0,0,0,
12330x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12340,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12350x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12360x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12370x53,0x41,
12380x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12390x20,0x20,
12400x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12410x10,0x80,
12420,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12430x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12440x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12450,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12460x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12470x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12480,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12490,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,
12520x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12530,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12540xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12550,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
12620,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12640,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12670,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1268};
1269
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001270/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001271static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001272{
1273 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1274 return sizeof(vpd89_data);
1275}
1276
1277
1278static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001279 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1280 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1281 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1282 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001283};
1284
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001285/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001286static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001287{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001288 unsigned int gran;
1289
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001290 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001291
1292 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001293 if (sdebug_opt_xferlen_exp != 0 &&
1294 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1295 gran = 1 << sdebug_opt_xferlen_exp;
1296 else
1297 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001298 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001299
1300 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001301 if (sdebug_store_sectors > 0x400)
1302 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001303
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001304 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001305 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001306
Douglas Gilbert773642d2016-04-25 12:16:28 -04001307 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001308 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001309 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001310
1311 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001312 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001313 }
1314
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001315 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001316 if (sdebug_unmap_alignment) {
1317 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001318 arr[28] |= 0x80; /* UGAVALID */
1319 }
1320
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001321 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001322 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001323
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001324 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001325 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001326
1327 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001328
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001329 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330}
1331
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001332/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001333static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001334{
1335 memset(arr, 0, 0x3c);
1336 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001337 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1338 arr[2] = 0;
1339 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001340
1341 return 0x3c;
1342}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001344/* Logical block provisioning VPD page (SBC-4) */
1345static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001346{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001347 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001348 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001349 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001350 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001351 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001352 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001353 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001354 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001355 if (sdebug_lbprz && scsi_debug_lbp())
1356 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1357 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1358 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1359 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001360 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001361}
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001364#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001366static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367{
1368 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001369 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001370 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001371 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001372 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Douglas Gilbert773642d2016-04-25 12:16:28 -04001374 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001375 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1376 if (! arr)
1377 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001378 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001379 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001380 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001381 pq_pdt = TYPE_WLUN; /* present, wlun */
1382 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1383 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001384 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001385 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 arr[0] = pq_pdt;
1387 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001388 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001389 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 return check_condition_result;
1391 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001392 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001393 char lu_id_str[6];
1394 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001396 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1397 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001398 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001399 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001400 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001401 (devip->target * 1000) + devip->lun);
1402 target_dev_id = ((host_no + 1) * 2000) +
1403 (devip->target * 1000) - 3;
1404 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001406 arr[1] = cmd[2]; /*sanity */
1407 n = 4;
1408 arr[n++] = 0x0; /* this page */
1409 arr[n++] = 0x80; /* unit serial number */
1410 arr[n++] = 0x83; /* device identification */
1411 arr[n++] = 0x84; /* software interface ident. */
1412 arr[n++] = 0x85; /* management network addresses */
1413 arr[n++] = 0x86; /* extended inquiry */
1414 arr[n++] = 0x87; /* mode page policy */
1415 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001416 if (is_disk) { /* SBC only */
1417 arr[n++] = 0x89; /* ATA information */
1418 arr[n++] = 0xb0; /* Block limits */
1419 arr[n++] = 0xb1; /* Block characteristics */
1420 arr[n++] = 0xb2; /* Logical Block Prov */
1421 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001422 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001424 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001426 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001428 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001429 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1430 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001431 lu_id_str, len,
1432 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001433 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1434 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001435 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001436 } else if (0x85 == cmd[2]) { /* Management network addresses */
1437 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001438 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001439 } else if (0x86 == cmd[2]) { /* extended inquiry */
1440 arr[1] = cmd[2]; /*sanity */
1441 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001442 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001443 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001444 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001445 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1446 else
1447 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001448 arr[5] = 0x7; /* head of q, ordered + simple q's */
1449 } else if (0x87 == cmd[2]) { /* mode page policy */
1450 arr[1] = cmd[2]; /*sanity */
1451 arr[3] = 0x8; /* number of following entries */
1452 arr[4] = 0x2; /* disconnect-reconnect mp */
1453 arr[6] = 0x80; /* mlus, shared */
1454 arr[8] = 0x18; /* protocol specific lu */
1455 arr[10] = 0x82; /* mlus, per initiator port */
1456 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1457 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001458 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1459 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001460 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001461 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001462 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001463 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001464 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001465 arr[3] = inquiry_vpd_b0(&arr[4]);
1466 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001467 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001468 arr[3] = inquiry_vpd_b1(&arr[4]);
1469 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001470 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001471 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001473 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001474 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 return check_condition_result;
1476 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001477 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001478 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001479 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001480 kfree(arr);
1481 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 }
1483 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001484 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1485 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 arr[3] = 2; /* response_data_format==2 */
1487 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001488 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001489 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001490 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001491 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001493 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001494 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1495 memcpy(&arr[16], sdebug_inq_product_id, 16);
1496 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001497 /* Use Vendor Specific area to place driver date in ASCII hex */
1498 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001500 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1501 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001502 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001503 if (is_disk) { /* SBC-4 no version claimed */
1504 put_unaligned_be16(0x600, arr + n);
1505 n += 2;
1506 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1507 put_unaligned_be16(0x525, arr + n);
1508 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001510 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001511 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001513 kfree(arr);
1514 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515}
1516
Douglas Gilbertfd321192016-04-25 12:16:33 -04001517static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1518 0, 0, 0x0, 0x0};
1519
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520static int resp_requests(struct scsi_cmnd * scp,
1521 struct sdebug_dev_info * devip)
1522{
1523 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001524 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001525 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001526 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 int len = 18;
1528
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001529 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001530 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001531 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001532 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001533 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001534 arr[0] = 0x72;
1535 arr[1] = 0x0; /* NO_SENSE in sense_key */
1536 arr[2] = THRESHOLD_EXCEEDED;
1537 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001538 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001539 } else {
1540 arr[0] = 0x70;
1541 arr[2] = 0x0; /* NO_SENSE in sense_key */
1542 arr[7] = 0xa; /* 18 byte sense buffer */
1543 arr[12] = THRESHOLD_EXCEEDED;
1544 arr[13] = 0xff; /* TEST set and MRIE==6 */
1545 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001546 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001547 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001548 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001549 ; /* have sense and formats match */
1550 else if (arr[0] <= 0x70) {
1551 if (dsense) {
1552 memset(arr, 0, 8);
1553 arr[0] = 0x72;
1554 len = 8;
1555 } else {
1556 memset(arr, 0, 18);
1557 arr[0] = 0x70;
1558 arr[7] = 0xa;
1559 }
1560 } else if (dsense) {
1561 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001562 arr[0] = 0x72;
1563 arr[1] = sbuff[2]; /* sense key */
1564 arr[2] = sbuff[12]; /* asc */
1565 arr[3] = sbuff[13]; /* ascq */
1566 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001567 } else {
1568 memset(arr, 0, 18);
1569 arr[0] = 0x70;
1570 arr[2] = sbuff[1];
1571 arr[7] = 0xa;
1572 arr[12] = sbuff[1];
1573 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001574 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001575
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001576 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001577 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 return fill_from_dev_buffer(scp, arr, len);
1579}
1580
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001581static int resp_start_stop(struct scsi_cmnd * scp,
1582 struct sdebug_dev_info * devip)
1583{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001584 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001585 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001586
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001587 power_cond = (cmd[4] & 0xf0) >> 4;
1588 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001589 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001590 return check_condition_result;
1591 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001592 stop = !(cmd[4] & 1);
1593 atomic_xchg(&devip->stopped, stop);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001594 return 0;
1595}
1596
FUJITA Tomonori28898872008-03-30 00:59:55 +09001597static sector_t get_sdebug_capacity(void)
1598{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001599 static const unsigned int gibibyte = 1073741824;
1600
1601 if (sdebug_virtual_gb > 0)
1602 return (sector_t)sdebug_virtual_gb *
1603 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001604 else
1605 return sdebug_store_sectors;
1606}
1607
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608#define SDEBUG_READCAP_ARR_SZ 8
1609static int resp_readcap(struct scsi_cmnd * scp,
1610 struct sdebug_dev_info * devip)
1611{
1612 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001613 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001615 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001616 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001618 if (sdebug_capacity < 0xffffffff) {
1619 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001620 put_unaligned_be32(capac, arr + 0);
1621 } else
1622 put_unaligned_be32(0xffffffff, arr + 0);
1623 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1625}
1626
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627#define SDEBUG_READCAP16_ARR_SZ 32
1628static int resp_readcap16(struct scsi_cmnd * scp,
1629 struct sdebug_dev_info * devip)
1630{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001631 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001632 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001633 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001634
Douglas Gilbert773642d2016-04-25 12:16:28 -04001635 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001636 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001637 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001638 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001639 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1640 put_unaligned_be32(sdebug_sector_size, arr + 8);
1641 arr[13] = sdebug_physblk_exp & 0xf;
1642 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001643
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001644 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001645 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001646 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1647 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1648 * in the wider field maps to 0 in this field.
1649 */
1650 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1651 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001652 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001653
Douglas Gilbert773642d2016-04-25 12:16:28 -04001654 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001655
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001656 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001657 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001658 arr[12] |= 1; /* PROT_EN */
1659 }
1660
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001661 return fill_from_dev_buffer(scp, arr,
1662 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1663}
1664
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001665#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1666
1667static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1668 struct sdebug_dev_info * devip)
1669{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001670 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001671 unsigned char * arr;
1672 int host_no = devip->sdbg_host->shost->host_no;
1673 int n, ret, alen, rlen;
1674 int port_group_a, port_group_b, port_a, port_b;
1675
Douglas Gilbert773642d2016-04-25 12:16:28 -04001676 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001677 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1678 if (! arr)
1679 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001680 /*
1681 * EVPD page 0x88 states we have two ports, one
1682 * real and a fake port with no device connected.
1683 * So we create two port groups with one port each
1684 * and set the group with port B to unavailable.
1685 */
1686 port_a = 0x1; /* relative port A */
1687 port_b = 0x2; /* relative port B */
1688 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001689 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001690 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001691 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001692
1693 /*
1694 * The asymmetric access state is cycled according to the host_id.
1695 */
1696 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001697 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001698 arr[n++] = host_no % 3; /* Asymm access state */
1699 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001700 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001701 arr[n++] = 0x0; /* Active/Optimized path */
1702 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001703 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001704 put_unaligned_be16(port_group_a, arr + n);
1705 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001706 arr[n++] = 0; /* Reserved */
1707 arr[n++] = 0; /* Status code */
1708 arr[n++] = 0; /* Vendor unique */
1709 arr[n++] = 0x1; /* One port per group */
1710 arr[n++] = 0; /* Reserved */
1711 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001712 put_unaligned_be16(port_a, arr + n);
1713 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001714 arr[n++] = 3; /* Port unavailable */
1715 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001716 put_unaligned_be16(port_group_b, arr + n);
1717 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001718 arr[n++] = 0; /* Reserved */
1719 arr[n++] = 0; /* Status code */
1720 arr[n++] = 0; /* Vendor unique */
1721 arr[n++] = 0x1; /* One port per group */
1722 arr[n++] = 0; /* Reserved */
1723 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001724 put_unaligned_be16(port_b, arr + n);
1725 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001726
1727 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001728 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001729
1730 /*
1731 * Return the smallest value of either
1732 * - The allocated length
1733 * - The constructed command length
1734 * - The maximum array size
1735 */
1736 rlen = min(alen,n);
1737 ret = fill_from_dev_buffer(scp, arr,
1738 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1739 kfree(arr);
1740 return ret;
1741}
1742
Douglas Gilbertfd321192016-04-25 12:16:33 -04001743static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1744 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001745{
1746 bool rctd;
1747 u8 reporting_opts, req_opcode, sdeb_i, supp;
1748 u16 req_sa, u;
1749 u32 alloc_len, a_len;
1750 int k, offset, len, errsts, count, bump, na;
1751 const struct opcode_info_t *oip;
1752 const struct opcode_info_t *r_oip;
1753 u8 *arr;
1754 u8 *cmd = scp->cmnd;
1755
1756 rctd = !!(cmd[2] & 0x80);
1757 reporting_opts = cmd[2] & 0x7;
1758 req_opcode = cmd[3];
1759 req_sa = get_unaligned_be16(cmd + 4);
1760 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001761 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001762 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1763 return check_condition_result;
1764 }
1765 if (alloc_len > 8192)
1766 a_len = 8192;
1767 else
1768 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001769 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001770 if (NULL == arr) {
1771 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1772 INSUFF_RES_ASCQ);
1773 return check_condition_result;
1774 }
1775 switch (reporting_opts) {
1776 case 0: /* all commands */
1777 /* count number of commands */
1778 for (count = 0, oip = opcode_info_arr;
1779 oip->num_attached != 0xff; ++oip) {
1780 if (F_INV_OP & oip->flags)
1781 continue;
1782 count += (oip->num_attached + 1);
1783 }
1784 bump = rctd ? 20 : 8;
1785 put_unaligned_be32(count * bump, arr);
1786 for (offset = 4, oip = opcode_info_arr;
1787 oip->num_attached != 0xff && offset < a_len; ++oip) {
1788 if (F_INV_OP & oip->flags)
1789 continue;
1790 na = oip->num_attached;
1791 arr[offset] = oip->opcode;
1792 put_unaligned_be16(oip->sa, arr + offset + 2);
1793 if (rctd)
1794 arr[offset + 5] |= 0x2;
1795 if (FF_SA & oip->flags)
1796 arr[offset + 5] |= 0x1;
1797 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1798 if (rctd)
1799 put_unaligned_be16(0xa, arr + offset + 8);
1800 r_oip = oip;
1801 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1802 if (F_INV_OP & oip->flags)
1803 continue;
1804 offset += bump;
1805 arr[offset] = oip->opcode;
1806 put_unaligned_be16(oip->sa, arr + offset + 2);
1807 if (rctd)
1808 arr[offset + 5] |= 0x2;
1809 if (FF_SA & oip->flags)
1810 arr[offset + 5] |= 0x1;
1811 put_unaligned_be16(oip->len_mask[0],
1812 arr + offset + 6);
1813 if (rctd)
1814 put_unaligned_be16(0xa,
1815 arr + offset + 8);
1816 }
1817 oip = r_oip;
1818 offset += bump;
1819 }
1820 break;
1821 case 1: /* one command: opcode only */
1822 case 2: /* one command: opcode plus service action */
1823 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1824 sdeb_i = opcode_ind_arr[req_opcode];
1825 oip = &opcode_info_arr[sdeb_i];
1826 if (F_INV_OP & oip->flags) {
1827 supp = 1;
1828 offset = 4;
1829 } else {
1830 if (1 == reporting_opts) {
1831 if (FF_SA & oip->flags) {
1832 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1833 2, 2);
1834 kfree(arr);
1835 return check_condition_result;
1836 }
1837 req_sa = 0;
1838 } else if (2 == reporting_opts &&
1839 0 == (FF_SA & oip->flags)) {
1840 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1841 kfree(arr); /* point at requested sa */
1842 return check_condition_result;
1843 }
1844 if (0 == (FF_SA & oip->flags) &&
1845 req_opcode == oip->opcode)
1846 supp = 3;
1847 else if (0 == (FF_SA & oip->flags)) {
1848 na = oip->num_attached;
1849 for (k = 0, oip = oip->arrp; k < na;
1850 ++k, ++oip) {
1851 if (req_opcode == oip->opcode)
1852 break;
1853 }
1854 supp = (k >= na) ? 1 : 3;
1855 } else if (req_sa != oip->sa) {
1856 na = oip->num_attached;
1857 for (k = 0, oip = oip->arrp; k < na;
1858 ++k, ++oip) {
1859 if (req_sa == oip->sa)
1860 break;
1861 }
1862 supp = (k >= na) ? 1 : 3;
1863 } else
1864 supp = 3;
1865 if (3 == supp) {
1866 u = oip->len_mask[0];
1867 put_unaligned_be16(u, arr + 2);
1868 arr[4] = oip->opcode;
1869 for (k = 1; k < u; ++k)
1870 arr[4 + k] = (k < 16) ?
1871 oip->len_mask[k] : 0xff;
1872 offset = 4 + u;
1873 } else
1874 offset = 4;
1875 }
1876 arr[1] = (rctd ? 0x80 : 0) | supp;
1877 if (rctd) {
1878 put_unaligned_be16(0xa, arr + offset);
1879 offset += 12;
1880 }
1881 break;
1882 default:
1883 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1884 kfree(arr);
1885 return check_condition_result;
1886 }
1887 offset = (offset < a_len) ? offset : a_len;
1888 len = (offset < alloc_len) ? offset : alloc_len;
1889 errsts = fill_from_dev_buffer(scp, arr, len);
1890 kfree(arr);
1891 return errsts;
1892}
1893
Douglas Gilbertfd321192016-04-25 12:16:33 -04001894static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1895 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001896{
1897 bool repd;
1898 u32 alloc_len, len;
1899 u8 arr[16];
1900 u8 *cmd = scp->cmnd;
1901
1902 memset(arr, 0, sizeof(arr));
1903 repd = !!(cmd[2] & 0x80);
1904 alloc_len = get_unaligned_be32(cmd + 6);
1905 if (alloc_len < 4) {
1906 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1907 return check_condition_result;
1908 }
1909 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1910 arr[1] = 0x1; /* ITNRS */
1911 if (repd) {
1912 arr[3] = 0xc;
1913 len = 16;
1914 } else
1915 len = 4;
1916
1917 len = (len < alloc_len) ? len : alloc_len;
1918 return fill_from_dev_buffer(scp, arr, len);
1919}
1920
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921/* <<Following mode page info copied from ST318451LW>> */
1922
1923static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1924{ /* Read-Write Error Recovery page for mode_sense */
1925 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1926 5, 0, 0xff, 0xff};
1927
1928 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1929 if (1 == pcontrol)
1930 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1931 return sizeof(err_recov_pg);
1932}
1933
1934static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1935{ /* Disconnect-Reconnect page for mode_sense */
1936 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1937 0, 0, 0, 0, 0, 0, 0, 0};
1938
1939 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1940 if (1 == pcontrol)
1941 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1942 return sizeof(disconnect_pg);
1943}
1944
1945static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1946{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001947 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1948 0, 0, 0, 0, 0, 0, 0, 0,
1949 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
Martin K. Petersen597136a2008-06-05 00:12:59 -04001951 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001952 put_unaligned_be16(sdebug_sectors_per, p + 10);
1953 put_unaligned_be16(sdebug_sector_size, p + 12);
1954 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001955 p[20] |= 0x20; /* should agree with INQUIRY */
1956 if (1 == pcontrol)
1957 memset(p + 2, 0, sizeof(format_pg) - 2);
1958 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959}
1960
Douglas Gilbertfd321192016-04-25 12:16:33 -04001961static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1962 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1963 0, 0, 0, 0};
1964
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1966{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001967 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1968 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1969 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1971
Douglas Gilbert773642d2016-04-25 12:16:28 -04001972 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001973 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 memcpy(p, caching_pg, sizeof(caching_pg));
1975 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001976 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1977 else if (2 == pcontrol)
1978 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 return sizeof(caching_pg);
1980}
1981
Douglas Gilbertfd321192016-04-25 12:16:33 -04001982static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1983 0, 0, 0x2, 0x4b};
1984
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1986{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001987 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05001988 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001989 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 0, 0, 0x2, 0x4b};
1991
Douglas Gilbert773642d2016-04-25 12:16:28 -04001992 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001994 else
1995 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001996
Douglas Gilbert773642d2016-04-25 12:16:28 -04001997 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001998 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1999
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2001 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002002 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2003 else if (2 == pcontrol)
2004 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 return sizeof(ctrl_m_pg);
2006}
2007
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
2010{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002011 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2012 0, 0, 0x0, 0x0};
2013 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2014 0, 0, 0x0, 0x0};
2015
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2017 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002018 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2019 else if (2 == pcontrol)
2020 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 return sizeof(iec_m_pg);
2022}
2023
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002024static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
2025{ /* SAS SSP mode page - short format for mode_sense */
2026 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2027 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2028
2029 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2030 if (1 == pcontrol)
2031 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2032 return sizeof(sas_sf_m_pg);
2033}
2034
2035
2036static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
2037 int target_dev_id)
2038{ /* SAS phy control and discover mode page for mode_sense */
2039 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2040 0, 0, 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 0x2, 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 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002047 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2048 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002049 0x3, 0, 0, 0, 0, 0, 0, 0,
2050 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2051 0, 0, 0, 0, 0, 0, 0, 0,
2052 };
2053 int port_a, port_b;
2054
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002055 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2056 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2057 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2058 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002059 port_a = target_dev_id + 1;
2060 port_b = port_a + 1;
2061 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002062 put_unaligned_be32(port_a, p + 20);
2063 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002064 if (1 == pcontrol)
2065 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2066 return sizeof(sas_pcd_m_pg);
2067}
2068
2069static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
2070{ /* SAS SSP shared protocol specific port mode subpage */
2071 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2072 0, 0, 0, 0, 0, 0, 0, 0,
2073 };
2074
2075 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2076 if (1 == pcontrol)
2077 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2078 return sizeof(sas_sha_m_pg);
2079}
2080
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081#define SDEBUG_MAX_MSENSE_SZ 256
2082
Douglas Gilbertfd321192016-04-25 12:16:33 -04002083static int resp_mode_sense(struct scsi_cmnd *scp,
2084 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085{
Douglas Gilbert23183912006-09-16 20:30:47 -04002086 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002088 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002089 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 unsigned char * ap;
2091 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002092 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002093 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002095 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 pcontrol = (cmd[2] & 0xc0) >> 6;
2097 pcode = cmd[2] & 0x3f;
2098 subpcode = cmd[3];
2099 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002100 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2101 is_disk = (sdebug_ptype == TYPE_DISK);
2102 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002103 bd_len = llbaa ? 16 : 8;
2104 else
2105 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002106 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2108 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002109 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 return check_condition_result;
2111 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002112 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2113 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002114 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002115 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002116 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002117 else
2118 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 if (msense_6) {
2120 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002121 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 offset = 4;
2123 } else {
2124 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002125 if (16 == bd_len)
2126 arr[4] = 0x1; /* set LONGLBA bit */
2127 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 offset = 8;
2129 }
2130 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002131 if ((bd_len > 0) && (!sdebug_capacity))
2132 sdebug_capacity = get_sdebug_capacity();
2133
Douglas Gilbert23183912006-09-16 20:30:47 -04002134 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002135 if (sdebug_capacity > 0xfffffffe)
2136 put_unaligned_be32(0xffffffff, ap + 0);
2137 else
2138 put_unaligned_be32(sdebug_capacity, ap + 0);
2139 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002140 offset += bd_len;
2141 ap = arr + offset;
2142 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002143 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2144 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002145 offset += bd_len;
2146 ap = arr + offset;
2147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002149 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2150 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002151 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 return check_condition_result;
2153 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002154 bad_pcode = false;
2155
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 switch (pcode) {
2157 case 0x1: /* Read-Write error recovery page, direct access */
2158 len = resp_err_recov_pg(ap, pcontrol, target);
2159 offset += len;
2160 break;
2161 case 0x2: /* Disconnect-Reconnect page, all devices */
2162 len = resp_disconnect_pg(ap, pcontrol, target);
2163 offset += len;
2164 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002165 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002166 if (is_disk) {
2167 len = resp_format_pg(ap, pcontrol, target);
2168 offset += len;
2169 } else
2170 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002171 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002173 if (is_disk) {
2174 len = resp_caching_pg(ap, pcontrol, target);
2175 offset += len;
2176 } else
2177 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 break;
2179 case 0xa: /* Control Mode page, all devices */
2180 len = resp_ctrl_m_pg(ap, pcontrol, target);
2181 offset += len;
2182 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002183 case 0x19: /* if spc==1 then sas phy, control+discover */
2184 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002185 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002186 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002187 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002188 len = 0;
2189 if ((0x0 == subpcode) || (0xff == subpcode))
2190 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2191 if ((0x1 == subpcode) || (0xff == subpcode))
2192 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2193 target_dev_id);
2194 if ((0x2 == subpcode) || (0xff == subpcode))
2195 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2196 offset += len;
2197 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 case 0x1c: /* Informational Exceptions Mode page, all devices */
2199 len = resp_iec_m_pg(ap, pcontrol, target);
2200 offset += len;
2201 break;
2202 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002203 if ((0 == subpcode) || (0xff == subpcode)) {
2204 len = resp_err_recov_pg(ap, pcontrol, target);
2205 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002206 if (is_disk) {
2207 len += resp_format_pg(ap + len, pcontrol,
2208 target);
2209 len += resp_caching_pg(ap + len, pcontrol,
2210 target);
2211 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002212 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2213 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2214 if (0xff == subpcode) {
2215 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2216 target, target_dev_id);
2217 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2218 }
2219 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002220 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002221 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002222 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002223 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 break;
2226 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002227 bad_pcode = true;
2228 break;
2229 }
2230 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002231 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 return check_condition_result;
2233 }
2234 if (msense_6)
2235 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002236 else
2237 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2239}
2240
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002241#define SDEBUG_MAX_MSELECT_SZ 512
2242
Douglas Gilbertfd321192016-04-25 12:16:33 -04002243static int resp_mode_select(struct scsi_cmnd *scp,
2244 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002245{
2246 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002247 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002248 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002249 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002250 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002251
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002252 memset(arr, 0, sizeof(arr));
2253 pf = cmd[1] & 0x10;
2254 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002255 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002256 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002257 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002258 return check_condition_result;
2259 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002260 res = fetch_to_dev_buffer(scp, arr, param_len);
2261 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002262 return DID_ERROR << 16;
2263 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002264 sdev_printk(KERN_INFO, scp->device,
2265 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2266 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002267 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2268 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002269 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002270 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002271 return check_condition_result;
2272 }
2273 off = bd_len + (mselect6 ? 4 : 8);
2274 mpage = arr[off] & 0x3f;
2275 ps = !!(arr[off] & 0x80);
2276 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002277 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002278 return check_condition_result;
2279 }
2280 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002281 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002282 (arr[off + 1] + 2);
2283 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002284 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002285 PARAMETER_LIST_LENGTH_ERR, 0);
2286 return check_condition_result;
2287 }
2288 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002289 case 0x8: /* Caching Mode page */
2290 if (caching_pg[1] == arr[off + 1]) {
2291 memcpy(caching_pg + 2, arr + off + 2,
2292 sizeof(caching_pg) - 2);
2293 goto set_mode_changed_ua;
2294 }
2295 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002296 case 0xa: /* Control Mode page */
2297 if (ctrl_m_pg[1] == arr[off + 1]) {
2298 memcpy(ctrl_m_pg + 2, arr + off + 2,
2299 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002300 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002301 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002302 }
2303 break;
2304 case 0x1c: /* Informational Exceptions Mode page */
2305 if (iec_m_pg[1] == arr[off + 1]) {
2306 memcpy(iec_m_pg + 2, arr + off + 2,
2307 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002308 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002309 }
2310 break;
2311 default:
2312 break;
2313 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002314 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002315 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002316set_mode_changed_ua:
2317 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2318 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002319}
2320
2321static int resp_temp_l_pg(unsigned char * arr)
2322{
2323 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2324 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2325 };
2326
Douglas Gilbert9a051012017-12-23 12:48:10 -05002327 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2328 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002329}
2330
2331static int resp_ie_l_pg(unsigned char * arr)
2332{
2333 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2334 };
2335
Douglas Gilbert9a051012017-12-23 12:48:10 -05002336 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002337 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2338 arr[4] = THRESHOLD_EXCEEDED;
2339 arr[5] = 0xff;
2340 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002341 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002342}
2343
2344#define SDEBUG_MAX_LSENSE_SZ 512
2345
Douglas Gilbert9a051012017-12-23 12:48:10 -05002346static int resp_log_sense(struct scsi_cmnd *scp,
2347 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002348{
Bart Van Asscheab172412017-08-25 13:46:42 -07002349 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002350 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002351 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002352
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002353 memset(arr, 0, sizeof(arr));
2354 ppc = cmd[1] & 0x2;
2355 sp = cmd[1] & 0x1;
2356 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002357 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002358 return check_condition_result;
2359 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002360 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002361 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002362 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002363 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002364 if (0 == subpcode) {
2365 switch (pcode) {
2366 case 0x0: /* Supported log pages log page */
2367 n = 4;
2368 arr[n++] = 0x0; /* this page */
2369 arr[n++] = 0xd; /* Temperature */
2370 arr[n++] = 0x2f; /* Informational exceptions */
2371 arr[3] = n - 4;
2372 break;
2373 case 0xd: /* Temperature log page */
2374 arr[3] = resp_temp_l_pg(arr + 4);
2375 break;
2376 case 0x2f: /* Informational exceptions log page */
2377 arr[3] = resp_ie_l_pg(arr + 4);
2378 break;
2379 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002380 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002381 return check_condition_result;
2382 }
2383 } else if (0xff == subpcode) {
2384 arr[0] |= 0x40;
2385 arr[1] = subpcode;
2386 switch (pcode) {
2387 case 0x0: /* Supported log pages and subpages log page */
2388 n = 4;
2389 arr[n++] = 0x0;
2390 arr[n++] = 0x0; /* 0,0 page */
2391 arr[n++] = 0x0;
2392 arr[n++] = 0xff; /* this page */
2393 arr[n++] = 0xd;
2394 arr[n++] = 0x0; /* Temperature */
2395 arr[n++] = 0x2f;
2396 arr[n++] = 0x0; /* Informational exceptions */
2397 arr[3] = n - 4;
2398 break;
2399 case 0xd: /* Temperature subpages */
2400 n = 4;
2401 arr[n++] = 0xd;
2402 arr[n++] = 0x0; /* Temperature */
2403 arr[3] = n - 4;
2404 break;
2405 case 0x2f: /* Informational exceptions subpages */
2406 n = 4;
2407 arr[n++] = 0x2f;
2408 arr[n++] = 0x0; /* Informational exceptions */
2409 arr[3] = n - 4;
2410 break;
2411 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002412 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002413 return check_condition_result;
2414 }
2415 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002416 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002417 return check_condition_result;
2418 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002419 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002420 return fill_from_dev_buffer(scp, arr,
2421 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2422}
2423
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002424static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002425 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002427 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002428 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 return check_condition_result;
2430 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002431 /* transfer length excessive (tie in to block limits VPD page) */
2432 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002433 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002434 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002435 return check_condition_result;
2436 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002437 return 0;
2438}
2439
Akinobu Mitaa4517512013-07-08 16:01:57 -07002440/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002441static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2442 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002443{
2444 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002445 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002446 struct scsi_data_buffer *sdb;
2447 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002448
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002449 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002450 sdb = scsi_out(scmd);
2451 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002452 } else {
2453 sdb = scsi_in(scmd);
2454 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002455 }
2456
2457 if (!sdb->length)
2458 return 0;
2459 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2460 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002461
2462 block = do_div(lba, sdebug_store_sectors);
2463 if (block + num > sdebug_store_sectors)
2464 rest = block + num - sdebug_store_sectors;
2465
Dave Gordon386ecb12015-06-30 14:58:57 -07002466 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002467 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002468 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002469 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002470 return ret;
2471
2472 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002473 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002474 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002475 sg_skip + ((num - rest) * sdebug_sector_size),
2476 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002477 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002478
2479 return ret;
2480}
2481
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002482/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2483 * arr into fake_store(lba,num) and return true. If comparison fails then
2484 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002485static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002486{
2487 bool res;
2488 u64 block, rest = 0;
2489 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002490 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002491
2492 block = do_div(lba, store_blks);
2493 if (block + num > store_blks)
2494 rest = block + num - store_blks;
2495
2496 res = !memcmp(fake_storep + (block * lb_size), arr,
2497 (num - rest) * lb_size);
2498 if (!res)
2499 return res;
2500 if (rest)
2501 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2502 rest * lb_size);
2503 if (!res)
2504 return res;
2505 arr += num * lb_size;
2506 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2507 if (rest)
2508 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2509 rest * lb_size);
2510 return res;
2511}
2512
Akinobu Mita51d648a2013-09-18 21:27:28 +09002513static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002514{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002515 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002516
Douglas Gilbert773642d2016-04-25 12:16:28 -04002517 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002518 csum = (__force __be16)ip_compute_csum(buf, len);
2519 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002520 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002521
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002522 return csum;
2523}
2524
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002525static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002526 sector_t sector, u32 ei_lba)
2527{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002528 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002529
2530 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002531 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002532 (unsigned long)sector,
2533 be16_to_cpu(sdt->guard_tag),
2534 be16_to_cpu(csum));
2535 return 0x01;
2536 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002537 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002538 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
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 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002543 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002544 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002545 pr_err("REF check failed on sector %lu\n",
2546 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002547 return 0x03;
2548 }
2549 return 0;
2550}
2551
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002552static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002553 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002554{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002555 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002556 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002557 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002558 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002559
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002560 /* Bytes of protection data to copy into sgl */
2561 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002562
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002563 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2564 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2565 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2566
2567 while (sg_miter_next(&miter) && resid > 0) {
2568 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002569 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002570 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002571
2572 if (dif_store_end < start + len)
2573 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002574
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002575 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002576
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002577 if (read)
2578 memcpy(paddr, start, len - rest);
2579 else
2580 memcpy(start, paddr, len - rest);
2581
2582 if (rest) {
2583 if (read)
2584 memcpy(paddr + len - rest, dif_storep, rest);
2585 else
2586 memcpy(dif_storep, paddr + len - rest, rest);
2587 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002588
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002589 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002590 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002591 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002592 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002593}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002594
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002595static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2596 unsigned int sectors, u32 ei_lba)
2597{
2598 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002599 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002600 sector_t sector;
2601
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002602 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002603 int ret;
2604
2605 sector = start_sec + i;
2606 sdt = dif_store(sector);
2607
Akinobu Mita51d648a2013-09-18 21:27:28 +09002608 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002609 continue;
2610
2611 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2612 if (ret) {
2613 dif_errors++;
2614 return ret;
2615 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002616 }
2617
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002618 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002619 dix_reads++;
2620
2621 return 0;
2622}
2623
Douglas Gilbertfd321192016-04-25 12:16:33 -04002624static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002625{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002626 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002627 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002628 u64 lba;
2629 u32 num;
2630 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002631 unsigned long iflags;
2632 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002633 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002634
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002635 switch (cmd[0]) {
2636 case READ_16:
2637 ei_lba = 0;
2638 lba = get_unaligned_be64(cmd + 2);
2639 num = get_unaligned_be32(cmd + 10);
2640 check_prot = true;
2641 break;
2642 case READ_10:
2643 ei_lba = 0;
2644 lba = get_unaligned_be32(cmd + 2);
2645 num = get_unaligned_be16(cmd + 7);
2646 check_prot = true;
2647 break;
2648 case READ_6:
2649 ei_lba = 0;
2650 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2651 (u32)(cmd[1] & 0x1f) << 16;
2652 num = (0 == cmd[4]) ? 256 : cmd[4];
2653 check_prot = true;
2654 break;
2655 case READ_12:
2656 ei_lba = 0;
2657 lba = get_unaligned_be32(cmd + 2);
2658 num = get_unaligned_be32(cmd + 6);
2659 check_prot = true;
2660 break;
2661 case XDWRITEREAD_10:
2662 ei_lba = 0;
2663 lba = get_unaligned_be32(cmd + 2);
2664 num = get_unaligned_be16(cmd + 7);
2665 check_prot = false;
2666 break;
2667 default: /* assume READ(32) */
2668 lba = get_unaligned_be64(cmd + 12);
2669 ei_lba = get_unaligned_be32(cmd + 20);
2670 num = get_unaligned_be32(cmd + 28);
2671 check_prot = false;
2672 break;
2673 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002674 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002675 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002676 (cmd[1] & 0xe0)) {
2677 mk_sense_invalid_opcode(scp);
2678 return check_condition_result;
2679 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002680 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2681 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002682 (cmd[1] & 0xe0) == 0)
2683 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2684 "to DIF device\n");
2685 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002686 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002687 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002688
Douglas Gilbertc4837392016-05-06 00:40:26 -04002689 if (sqcp) {
2690 if (sqcp->inj_short)
2691 num /= 2;
2692 }
2693 } else
2694 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002695
2696 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002697 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002698 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2699 return check_condition_result;
2700 }
2701 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002702 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002703 /* needs work to find which cdb byte 'num' comes from */
2704 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2705 return check_condition_result;
2706 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002707
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002708 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2709 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2710 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002711 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002712 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002713 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002714 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2715 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002716 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2717 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002718 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002719 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002720 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 return check_condition_result;
2722 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002723
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002724 read_lock_irqsave(&atomic_rw, iflags);
2725
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002726 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002727 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002728 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002729
2730 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002731 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002732 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002733 return illegal_condition_result;
2734 }
2735 }
2736
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002737 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002739 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002740 return DID_ERROR << 16;
2741
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002742 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002743
Douglas Gilbertc4837392016-05-06 00:40:26 -04002744 if (unlikely(sqcp)) {
2745 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002746 mk_sense_buffer(scp, RECOVERED_ERROR,
2747 THRESHOLD_EXCEEDED, 0);
2748 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002749 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002750 mk_sense_buffer(scp, ABORTED_COMMAND,
2751 TRANSPORT_PROBLEM, ACK_NAK_TO);
2752 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002753 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002754 /* Logical block guard check failed */
2755 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2756 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002757 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002758 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2759 return illegal_condition_result;
2760 }
2761 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002762 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763}
2764
Tomas Winkler58a86352015-07-28 16:54:23 +03002765static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002766{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002767 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002768
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002769 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002770 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002771 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002772
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002773 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002774 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002775
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002776 if (c >= 0x20 && c < 0x7e)
2777 n += scnprintf(b + n, sizeof(b) - n,
2778 " %c ", buf[i+j]);
2779 else
2780 n += scnprintf(b + n, sizeof(b) - n,
2781 "%02x ", buf[i+j]);
2782 }
2783 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002784 }
2785}
2786
2787static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002788 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002789{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002790 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002791 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002792 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002793 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002794 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002795 int dpage_offset;
2796 struct sg_mapping_iter diter;
2797 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002798
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002799 BUG_ON(scsi_sg_count(SCpnt) == 0);
2800 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2801
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002802 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2803 scsi_prot_sg_count(SCpnt),
2804 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2805 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2806 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002807
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002808 /* For each protection page */
2809 while (sg_miter_next(&piter)) {
2810 dpage_offset = 0;
2811 if (WARN_ON(!sg_miter_next(&diter))) {
2812 ret = 0x01;
2813 goto out;
2814 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002815
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002816 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002817 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002818 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002819 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002820 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002821 if (dpage_offset >= diter.length) {
2822 if (WARN_ON(!sg_miter_next(&diter))) {
2823 ret = 0x01;
2824 goto out;
2825 }
2826 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002827 }
2828
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002829 sdt = piter.addr + ppage_offset;
2830 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002831
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002832 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002833 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002834 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002835 goto out;
2836 }
2837
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002838 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002839 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002840 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002841 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002842 diter.consumed = dpage_offset;
2843 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002844 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002845 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002846
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002847 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002848 dix_writes++;
2849
2850 return 0;
2851
2852out:
2853 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002854 sg_miter_stop(&diter);
2855 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002856 return ret;
2857}
2858
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002859static unsigned long lba_to_map_index(sector_t lba)
2860{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002861 if (sdebug_unmap_alignment)
2862 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2863 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002864 return lba;
2865}
2866
2867static sector_t map_index_to_lba(unsigned long index)
2868{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002869 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002870
Douglas Gilbert773642d2016-04-25 12:16:28 -04002871 if (sdebug_unmap_alignment)
2872 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002873 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002874}
2875
Martin K. Petersen44d92692009-10-15 14:45:27 -04002876static unsigned int map_state(sector_t lba, unsigned int *num)
2877{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002878 sector_t end;
2879 unsigned int mapped;
2880 unsigned long index;
2881 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002882
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002883 index = lba_to_map_index(lba);
2884 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002885
2886 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002887 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002888 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002889 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002890
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002891 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002892 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002893 return mapped;
2894}
2895
2896static void map_region(sector_t lba, unsigned int len)
2897{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002898 sector_t end = lba + len;
2899
Martin K. Petersen44d92692009-10-15 14:45:27 -04002900 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002901 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002902
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002903 if (index < map_size)
2904 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002905
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002906 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002907 }
2908}
2909
2910static void unmap_region(sector_t lba, unsigned int len)
2911{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002912 sector_t end = lba + len;
2913
Martin K. Petersen44d92692009-10-15 14:45:27 -04002914 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002915 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002916
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002917 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002918 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002919 index < map_size) {
2920 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002921 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002922 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002923 lba * sdebug_sector_size,
2924 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002925 sdebug_sector_size *
2926 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002927 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002928 if (dif_storep) {
2929 memset(dif_storep + lba, 0xff,
2930 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002931 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002932 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002933 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002934 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002935 }
2936}
2937
Douglas Gilbertfd321192016-04-25 12:16:33 -04002938static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002940 u8 *cmd = scp->cmnd;
2941 u64 lba;
2942 u32 num;
2943 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002945 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002946 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002948 switch (cmd[0]) {
2949 case WRITE_16:
2950 ei_lba = 0;
2951 lba = get_unaligned_be64(cmd + 2);
2952 num = get_unaligned_be32(cmd + 10);
2953 check_prot = true;
2954 break;
2955 case WRITE_10:
2956 ei_lba = 0;
2957 lba = get_unaligned_be32(cmd + 2);
2958 num = get_unaligned_be16(cmd + 7);
2959 check_prot = true;
2960 break;
2961 case WRITE_6:
2962 ei_lba = 0;
2963 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2964 (u32)(cmd[1] & 0x1f) << 16;
2965 num = (0 == cmd[4]) ? 256 : cmd[4];
2966 check_prot = true;
2967 break;
2968 case WRITE_12:
2969 ei_lba = 0;
2970 lba = get_unaligned_be32(cmd + 2);
2971 num = get_unaligned_be32(cmd + 6);
2972 check_prot = true;
2973 break;
2974 case 0x53: /* XDWRITEREAD(10) */
2975 ei_lba = 0;
2976 lba = get_unaligned_be32(cmd + 2);
2977 num = get_unaligned_be16(cmd + 7);
2978 check_prot = false;
2979 break;
2980 default: /* assume WRITE(32) */
2981 lba = get_unaligned_be64(cmd + 12);
2982 ei_lba = get_unaligned_be32(cmd + 20);
2983 num = get_unaligned_be32(cmd + 28);
2984 check_prot = false;
2985 break;
2986 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002987 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002988 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002989 (cmd[1] & 0xe0)) {
2990 mk_sense_invalid_opcode(scp);
2991 return check_condition_result;
2992 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002993 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2994 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002995 (cmd[1] & 0xe0) == 0)
2996 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2997 "to DIF device\n");
2998 }
2999
3000 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003001 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003002 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3003 return check_condition_result;
3004 }
3005 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003006 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003007 /* needs work to find which cdb byte 'num' comes from */
3008 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3009 return check_condition_result;
3010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003012 write_lock_irqsave(&atomic_rw, iflags);
3013
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003014 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003015 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003016 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003017
3018 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003019 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003020 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003021 return illegal_condition_result;
3022 }
3023 }
3024
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003025 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003026 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003027 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003029 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003030 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003031 else if (unlikely(sdebug_verbose &&
3032 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003033 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003034 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003035 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003036
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003037 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003038 struct sdebug_queued_cmd *sqcp =
3039 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003040
Douglas Gilbertc4837392016-05-06 00:40:26 -04003041 if (sqcp) {
3042 if (sqcp->inj_recovered) {
3043 mk_sense_buffer(scp, RECOVERED_ERROR,
3044 THRESHOLD_EXCEEDED, 0);
3045 return check_condition_result;
3046 } else if (sqcp->inj_dif) {
3047 /* Logical block guard check failed */
3048 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3049 return illegal_condition_result;
3050 } else if (sqcp->inj_dix) {
3051 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3052 return illegal_condition_result;
3053 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003054 }
3055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 return 0;
3057}
3058
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003059/*
3060 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3061 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3062 */
3063static int resp_write_scat(struct scsi_cmnd *scp,
3064 struct sdebug_dev_info *devip)
3065{
3066 u8 *cmd = scp->cmnd;
3067 u8 *lrdp = NULL;
3068 u8 *up;
3069 u8 wrprotect;
3070 u16 lbdof, num_lrd, k;
3071 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3072 u32 lb_size = sdebug_sector_size;
3073 u32 ei_lba;
3074 u64 lba;
3075 unsigned long iflags;
3076 int ret, res;
3077 bool is_16;
3078 static const u32 lrd_size = 32; /* + parameter list header size */
3079
3080 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3081 is_16 = false;
3082 wrprotect = (cmd[10] >> 5) & 0x7;
3083 lbdof = get_unaligned_be16(cmd + 12);
3084 num_lrd = get_unaligned_be16(cmd + 16);
3085 bt_len = get_unaligned_be32(cmd + 28);
3086 } else { /* that leaves WRITE SCATTERED(16) */
3087 is_16 = true;
3088 wrprotect = (cmd[2] >> 5) & 0x7;
3089 lbdof = get_unaligned_be16(cmd + 4);
3090 num_lrd = get_unaligned_be16(cmd + 8);
3091 bt_len = get_unaligned_be32(cmd + 10);
3092 if (unlikely(have_dif_prot)) {
3093 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3094 wrprotect) {
3095 mk_sense_invalid_opcode(scp);
3096 return illegal_condition_result;
3097 }
3098 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3099 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3100 wrprotect == 0)
3101 sdev_printk(KERN_ERR, scp->device,
3102 "Unprotected WR to DIF device\n");
3103 }
3104 }
3105 if ((num_lrd == 0) || (bt_len == 0))
3106 return 0; /* T10 says these do-nothings are not errors */
3107 if (lbdof == 0) {
3108 if (sdebug_verbose)
3109 sdev_printk(KERN_INFO, scp->device,
3110 "%s: %s: LB Data Offset field bad\n",
3111 my_name, __func__);
3112 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3113 return illegal_condition_result;
3114 }
3115 lbdof_blen = lbdof * lb_size;
3116 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3117 if (sdebug_verbose)
3118 sdev_printk(KERN_INFO, scp->device,
3119 "%s: %s: LBA range descriptors don't fit\n",
3120 my_name, __func__);
3121 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3122 return illegal_condition_result;
3123 }
3124 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3125 if (lrdp == NULL)
3126 return SCSI_MLQUEUE_HOST_BUSY;
3127 if (sdebug_verbose)
3128 sdev_printk(KERN_INFO, scp->device,
3129 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3130 my_name, __func__, lbdof_blen);
3131 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3132 if (res == -1) {
3133 ret = DID_ERROR << 16;
3134 goto err_out;
3135 }
3136
3137 write_lock_irqsave(&atomic_rw, iflags);
3138 sg_off = lbdof_blen;
3139 /* Spec says Buffer xfer Length field in number of LBs in dout */
3140 cum_lb = 0;
3141 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3142 lba = get_unaligned_be64(up + 0);
3143 num = get_unaligned_be32(up + 8);
3144 if (sdebug_verbose)
3145 sdev_printk(KERN_INFO, scp->device,
3146 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3147 my_name, __func__, k, lba, num, sg_off);
3148 if (num == 0)
3149 continue;
3150 ret = check_device_access_params(scp, lba, num);
3151 if (ret)
3152 goto err_out_unlock;
3153 num_by = num * lb_size;
3154 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3155
3156 if ((cum_lb + num) > bt_len) {
3157 if (sdebug_verbose)
3158 sdev_printk(KERN_INFO, scp->device,
3159 "%s: %s: sum of blocks > data provided\n",
3160 my_name, __func__);
3161 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3162 0);
3163 ret = illegal_condition_result;
3164 goto err_out_unlock;
3165 }
3166
3167 /* DIX + T10 DIF */
3168 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3169 int prot_ret = prot_verify_write(scp, lba, num,
3170 ei_lba);
3171
3172 if (prot_ret) {
3173 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3174 prot_ret);
3175 ret = illegal_condition_result;
3176 goto err_out_unlock;
3177 }
3178 }
3179
3180 ret = do_device_access(scp, sg_off, lba, num, true);
3181 if (unlikely(scsi_debug_lbp()))
3182 map_region(lba, num);
3183 if (unlikely(-1 == ret)) {
3184 ret = DID_ERROR << 16;
3185 goto err_out_unlock;
3186 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3187 sdev_printk(KERN_INFO, scp->device,
3188 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3189 my_name, num_by, ret);
3190
3191 if (unlikely(sdebug_any_injecting_opt)) {
3192 struct sdebug_queued_cmd *sqcp =
3193 (struct sdebug_queued_cmd *)scp->host_scribble;
3194
3195 if (sqcp) {
3196 if (sqcp->inj_recovered) {
3197 mk_sense_buffer(scp, RECOVERED_ERROR,
3198 THRESHOLD_EXCEEDED, 0);
3199 ret = illegal_condition_result;
3200 goto err_out_unlock;
3201 } else if (sqcp->inj_dif) {
3202 /* Logical block guard check failed */
3203 mk_sense_buffer(scp, ABORTED_COMMAND,
3204 0x10, 1);
3205 ret = illegal_condition_result;
3206 goto err_out_unlock;
3207 } else if (sqcp->inj_dix) {
3208 mk_sense_buffer(scp, ILLEGAL_REQUEST,
3209 0x10, 1);
3210 ret = illegal_condition_result;
3211 goto err_out_unlock;
3212 }
3213 }
3214 }
3215 sg_off += num_by;
3216 cum_lb += num;
3217 }
3218 ret = 0;
3219err_out_unlock:
3220 write_unlock_irqrestore(&atomic_rw, iflags);
3221err_out:
3222 kfree(lrdp);
3223 return ret;
3224}
3225
Douglas Gilbertfd321192016-04-25 12:16:33 -04003226static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3227 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003228{
3229 unsigned long iflags;
3230 unsigned long long i;
3231 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003232 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003233
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003234 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003235 if (ret)
3236 return ret;
3237
3238 write_lock_irqsave(&atomic_rw, iflags);
3239
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003240 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003241 unmap_region(lba, num);
3242 goto out;
3243 }
3244
Douglas Gilbert773642d2016-04-25 12:16:28 -04003245 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003246 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3247 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003248 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003249 ret = 0;
3250 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003251 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3252 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003253
3254 if (-1 == ret) {
3255 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003256 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003257 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003258 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003259 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003260 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003261 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003262
3263 /* Copy first sector to remaining blocks */
3264 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003265 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3266 fake_storep + lba_off,
3267 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003268
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003269 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003270 map_region(lba, num);
3271out:
3272 write_unlock_irqrestore(&atomic_rw, iflags);
3273
3274 return 0;
3275}
3276
Douglas Gilbertfd321192016-04-25 12:16:33 -04003277static int resp_write_same_10(struct scsi_cmnd *scp,
3278 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003279{
3280 u8 *cmd = scp->cmnd;
3281 u32 lba;
3282 u16 num;
3283 u32 ei_lba = 0;
3284 bool unmap = false;
3285
3286 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003287 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003288 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3289 return check_condition_result;
3290 } else
3291 unmap = true;
3292 }
3293 lba = get_unaligned_be32(cmd + 2);
3294 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003295 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003296 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3297 return check_condition_result;
3298 }
3299 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3300}
3301
Douglas Gilbertfd321192016-04-25 12:16:33 -04003302static int resp_write_same_16(struct scsi_cmnd *scp,
3303 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003304{
3305 u8 *cmd = scp->cmnd;
3306 u64 lba;
3307 u32 num;
3308 u32 ei_lba = 0;
3309 bool unmap = false;
3310 bool ndob = false;
3311
3312 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003313 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003314 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3315 return check_condition_result;
3316 } else
3317 unmap = true;
3318 }
3319 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3320 ndob = true;
3321 lba = get_unaligned_be64(cmd + 2);
3322 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003323 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003324 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3325 return check_condition_result;
3326 }
3327 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3328}
3329
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003330/* Note the mode field is in the same position as the (lower) service action
3331 * field. For the Report supported operation codes command, SPC-4 suggests
3332 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003333static int resp_write_buffer(struct scsi_cmnd *scp,
3334 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003335{
3336 u8 *cmd = scp->cmnd;
3337 struct scsi_device *sdp = scp->device;
3338 struct sdebug_dev_info *dp;
3339 u8 mode;
3340
3341 mode = cmd[1] & 0x1f;
3342 switch (mode) {
3343 case 0x4: /* download microcode (MC) and activate (ACT) */
3344 /* set UAs on this device only */
3345 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3346 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3347 break;
3348 case 0x5: /* download MC, save and ACT */
3349 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3350 break;
3351 case 0x6: /* download MC with offsets and ACT */
3352 /* set UAs on most devices (LUs) in this target */
3353 list_for_each_entry(dp,
3354 &devip->sdbg_host->dev_info_list,
3355 dev_list)
3356 if (dp->target == sdp->id) {
3357 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3358 if (devip != dp)
3359 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3360 dp->uas_bm);
3361 }
3362 break;
3363 case 0x7: /* download MC with offsets, save, and ACT */
3364 /* set UA on all devices (LUs) in this target */
3365 list_for_each_entry(dp,
3366 &devip->sdbg_host->dev_info_list,
3367 dev_list)
3368 if (dp->target == sdp->id)
3369 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3370 dp->uas_bm);
3371 break;
3372 default:
3373 /* do nothing for this command for other mode values */
3374 break;
3375 }
3376 return 0;
3377}
3378
Douglas Gilbertfd321192016-04-25 12:16:33 -04003379static int resp_comp_write(struct scsi_cmnd *scp,
3380 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003381{
3382 u8 *cmd = scp->cmnd;
3383 u8 *arr;
3384 u8 *fake_storep_hold;
3385 u64 lba;
3386 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003387 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003388 u8 num;
3389 unsigned long iflags;
3390 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003391 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003392
Douglas Gilbertd467d312014-11-26 12:33:48 -05003393 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003394 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3395 if (0 == num)
3396 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003397 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003398 (cmd[1] & 0xe0)) {
3399 mk_sense_invalid_opcode(scp);
3400 return check_condition_result;
3401 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003402 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3403 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003404 (cmd[1] & 0xe0) == 0)
3405 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3406 "to DIF device\n");
3407
3408 /* inline check_device_access_params() */
3409 if (lba + num > sdebug_capacity) {
3410 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3411 return check_condition_result;
3412 }
3413 /* transfer length excessive (tie in to block limits VPD page) */
3414 if (num > sdebug_store_sectors) {
3415 /* needs work to find which cdb byte 'num' comes from */
3416 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3417 return check_condition_result;
3418 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003419 dnum = 2 * num;
3420 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3421 if (NULL == arr) {
3422 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3423 INSUFF_RES_ASCQ);
3424 return check_condition_result;
3425 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003426
3427 write_lock_irqsave(&atomic_rw, iflags);
3428
3429 /* trick do_device_access() to fetch both compare and write buffers
3430 * from data-in into arr. Safe (atomic) since write_lock held. */
3431 fake_storep_hold = fake_storep;
3432 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003433 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003434 fake_storep = fake_storep_hold;
3435 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003436 retval = DID_ERROR << 16;
3437 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003438 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003439 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3440 "indicated=%u, IO sent=%d bytes\n", my_name,
3441 dnum * lb_size, ret);
3442 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003443 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003444 retval = check_condition_result;
3445 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003446 }
3447 if (scsi_debug_lbp())
3448 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003449cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003450 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003451 kfree(arr);
3452 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003453}
3454
Martin K. Petersen44d92692009-10-15 14:45:27 -04003455struct unmap_block_desc {
3456 __be64 lba;
3457 __be32 blocks;
3458 __be32 __reserved;
3459};
3460
Douglas Gilbertfd321192016-04-25 12:16:33 -04003461static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003462{
3463 unsigned char *buf;
3464 struct unmap_block_desc *desc;
3465 unsigned int i, payload_len, descriptors;
3466 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003467 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003468
Martin K. Petersen44d92692009-10-15 14:45:27 -04003469
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003470 if (!scsi_debug_lbp())
3471 return 0; /* fib and say its done */
3472 payload_len = get_unaligned_be16(scp->cmnd + 7);
3473 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003474
3475 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003476 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003477 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003478 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003479 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003480
Douglas Gilbertb333a812016-04-25 12:16:30 -04003481 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003482 if (!buf) {
3483 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3484 INSUFF_RES_ASCQ);
3485 return check_condition_result;
3486 }
3487
3488 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003489
3490 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3491 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3492
3493 desc = (void *)&buf[8];
3494
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003495 write_lock_irqsave(&atomic_rw, iflags);
3496
Martin K. Petersen44d92692009-10-15 14:45:27 -04003497 for (i = 0 ; i < descriptors ; i++) {
3498 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3499 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3500
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003501 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003502 if (ret)
3503 goto out;
3504
3505 unmap_region(lba, num);
3506 }
3507
3508 ret = 0;
3509
3510out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003511 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003512 kfree(buf);
3513
3514 return ret;
3515}
3516
3517#define SDEBUG_GET_LBA_STATUS_LEN 32
3518
Douglas Gilbertfd321192016-04-25 12:16:33 -04003519static int resp_get_lba_status(struct scsi_cmnd *scp,
3520 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003521{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003522 u8 *cmd = scp->cmnd;
3523 u64 lba;
3524 u32 alloc_len, mapped, num;
3525 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003526 int ret;
3527
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003528 lba = get_unaligned_be64(cmd + 2);
3529 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003530
3531 if (alloc_len < 24)
3532 return 0;
3533
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003534 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003535 if (ret)
3536 return ret;
3537
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003538 if (scsi_debug_lbp())
3539 mapped = map_state(lba, &num);
3540 else {
3541 mapped = 1;
3542 /* following just in case virtual_gb changed */
3543 sdebug_capacity = get_sdebug_capacity();
3544 if (sdebug_capacity - lba <= 0xffffffff)
3545 num = sdebug_capacity - lba;
3546 else
3547 num = 0xffffffff;
3548 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003549
3550 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003551 put_unaligned_be32(20, arr); /* Parameter Data Length */
3552 put_unaligned_be64(lba, arr + 8); /* LBA */
3553 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3554 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003555
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003556 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003557}
3558
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003559#define RL_BUCKET_ELEMS 8
3560
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003561/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3562 * (W-LUN), the normal Linux scanning logic does not associate it with a
3563 * device (e.g. /dev/sg7). The following magic will make that association:
3564 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3565 * where <n> is a host number. If there are multiple targets in a host then
3566 * the above will associate a W-LUN to each target. To only get a W-LUN
3567 * for target 2, then use "echo '- 2 49409' > scan" .
3568 */
3569static int resp_report_luns(struct scsi_cmnd *scp,
3570 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003572 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003573 unsigned int alloc_len;
3574 unsigned char select_report;
3575 u64 lun;
3576 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003577 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003578 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3579 unsigned int wlun_cnt; /* report luns W-LUN count */
3580 unsigned int tlun_cnt; /* total LUN count */
3581 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003582 int k, j, n, res;
3583 unsigned int off_rsp = 0;
3584 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003586 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003587
3588 select_report = cmd[2];
3589 alloc_len = get_unaligned_be32(cmd + 6);
3590
3591 if (alloc_len < 4) {
3592 pr_err("alloc len too small %d\n", alloc_len);
3593 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 return check_condition_result;
3595 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003596
3597 switch (select_report) {
3598 case 0: /* all LUNs apart from W-LUNs */
3599 lun_cnt = sdebug_max_luns;
3600 wlun_cnt = 0;
3601 break;
3602 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003603 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003604 wlun_cnt = 1;
3605 break;
3606 case 2: /* all LUNs */
3607 lun_cnt = sdebug_max_luns;
3608 wlun_cnt = 1;
3609 break;
3610 case 0x10: /* only administrative LUs */
3611 case 0x11: /* see SPC-5 */
3612 case 0x12: /* only subsiduary LUs owned by referenced LU */
3613 default:
3614 pr_debug("select report invalid %d\n", select_report);
3615 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3616 return check_condition_result;
3617 }
3618
3619 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003620 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003621
3622 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003623 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3624 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003625 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3626 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3627
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003628 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003629 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003630 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3631 memset(arr, 0, sizeof(arr));
3632 lun_p = (struct scsi_lun *)&arr[0];
3633 if (k == 0) {
3634 put_unaligned_be32(rlen, &arr[0]);
3635 ++lun_p;
3636 j = 1;
3637 }
3638 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3639 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3640 break;
3641 int_to_scsilun(lun++, lun_p);
3642 }
3643 if (j < RL_BUCKET_ELEMS)
3644 break;
3645 n = j * sz_lun;
3646 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3647 if (res)
3648 return res;
3649 off_rsp += n;
3650 }
3651 if (wlun_cnt) {
3652 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3653 ++j;
3654 }
3655 if (j > 0)
3656 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003657 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658}
3659
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003660static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3661 unsigned int num, struct sdebug_dev_info *devip)
3662{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003663 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003664 unsigned char *kaddr, *buf;
3665 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003666 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003667 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003668
3669 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003670 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003671 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003672 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3673 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003674 return check_condition_result;
3675 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003676
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003677 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003678
3679 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003680 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3681 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003682
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003683 while (sg_miter_next(&miter)) {
3684 kaddr = miter.addr;
3685 for (j = 0; j < miter.length; j++)
3686 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003687
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003688 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003689 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003690 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003691 kfree(buf);
3692
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003693 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003694}
3695
Douglas Gilbertfd321192016-04-25 12:16:33 -04003696static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3697 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003698{
3699 u8 *cmd = scp->cmnd;
3700 u64 lba;
3701 u32 num;
3702 int errsts;
3703
3704 if (!scsi_bidi_cmnd(scp)) {
3705 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3706 INSUFF_RES_ASCQ);
3707 return check_condition_result;
3708 }
3709 errsts = resp_read_dt0(scp, devip);
3710 if (errsts)
3711 return errsts;
3712 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3713 errsts = resp_write_dt0(scp, devip);
3714 if (errsts)
3715 return errsts;
3716 }
3717 lba = get_unaligned_be32(cmd + 2);
3718 num = get_unaligned_be16(cmd + 7);
3719 return resp_xdwriteread(scp, lba, num, devip);
3720}
3721
Douglas Gilbertc4837392016-05-06 00:40:26 -04003722static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3723{
3724 struct sdebug_queue *sqp = sdebug_q_arr;
3725
3726 if (sdebug_mq_active) {
3727 u32 tag = blk_mq_unique_tag(cmnd->request);
3728 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3729
3730 if (unlikely(hwq >= submit_queues)) {
3731 pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3732 hwq %= submit_queues;
3733 }
3734 pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3735 return sqp + hwq;
3736 } else
3737 return sqp;
3738}
3739
3740/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003741static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003743 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003744 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003746 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003747 struct sdebug_queued_cmd *sqcp;
3748 struct scsi_cmnd *scp;
3749 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
Douglas Gilbertc4837392016-05-06 00:40:26 -04003751 qc_idx = sd_dp->qc_idx;
3752 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3753 if (sdebug_statistics) {
3754 atomic_inc(&sdebug_completions);
3755 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3756 atomic_inc(&sdebug_miss_cpus);
3757 }
3758 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3759 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 return;
3761 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003762 spin_lock_irqsave(&sqp->qc_lock, iflags);
3763 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003764 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003765 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003766 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3767 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3768 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 return;
3770 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003771 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003772 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003773 atomic_dec(&devip->num_in_q);
3774 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003775 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003776 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003777 retiring = 1;
3778
3779 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003780 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3781 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003782 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003783 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003785
3786 if (unlikely(retiring)) { /* user has reduced max_queue */
3787 int k, retval;
3788
3789 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003790 if (qc_idx >= retval) {
3791 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003792 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003793 return;
3794 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003795 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003796 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003797 atomic_set(&retired_max_queue, 0);
3798 else
3799 atomic_set(&retired_max_queue, k + 1);
3800 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003801 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003802 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803}
3804
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003805/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003806static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003807{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003808 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3809 hrt);
3810 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003811 return HRTIMER_NORESTART;
3812}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813
Douglas Gilberta10bc122016-04-25 12:16:32 -04003814/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003815static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003816{
3817 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3818 ew.work);
3819 sdebug_q_cmd_complete(sd_dp);
3820}
3821
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003822static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003823static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003824
Douglas Gilbertfd321192016-04-25 12:16:33 -04003825static struct sdebug_dev_info *sdebug_device_create(
3826 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003827{
3828 struct sdebug_dev_info *devip;
3829
3830 devip = kzalloc(sizeof(*devip), flags);
3831 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003832 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003833 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003834 else if (sdebug_uuid_ctl == 2) {
3835 if (got_shared_uuid)
3836 devip->lu_name = shared_uuid;
3837 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003838 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003839 got_shared_uuid = true;
3840 devip->lu_name = shared_uuid;
3841 }
3842 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003843 devip->sdbg_host = sdbg_host;
3844 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3845 }
3846 return devip;
3847}
3848
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003849static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003851 struct sdebug_host_info *sdbg_host;
3852 struct sdebug_dev_info *open_devip = NULL;
3853 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003855 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3856 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003857 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3861 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003862 (devip->target == sdev->id) &&
3863 (devip->lun == sdev->lun))
3864 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 else {
3866 if ((!devip->used) && (!open_devip))
3867 open_devip = devip;
3868 }
3869 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003870 if (!open_devip) { /* try and make a new one */
3871 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3872 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003873 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 return NULL;
3875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003877
3878 open_devip->channel = sdev->channel;
3879 open_devip->target = sdev->id;
3880 open_devip->lun = sdev->lun;
3881 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003882 atomic_set(&open_devip->num_in_q, 0);
3883 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003884 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003885 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886}
3887
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003888static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003890 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003891 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003892 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003893 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003894 return 0;
3895}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003897static int scsi_debug_slave_configure(struct scsi_device *sdp)
3898{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003899 struct sdebug_dev_info *devip =
3900 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003901
Douglas Gilbert773642d2016-04-25 12:16:28 -04003902 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003903 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003904 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003905 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3906 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3907 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003908 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003909 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003910 return 1; /* no resources, will be marked offline */
3911 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003912 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003913 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003914 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003915 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003916 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003917 return 0;
3918}
3919
3920static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3921{
3922 struct sdebug_dev_info *devip =
3923 (struct sdebug_dev_info *)sdp->hostdata;
3924
Douglas Gilbert773642d2016-04-25 12:16:28 -04003925 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003926 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003927 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3928 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003929 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003930 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003931 sdp->hostdata = NULL;
3932 }
3933}
3934
Douglas Gilbertc4837392016-05-06 00:40:26 -04003935static void stop_qc_helper(struct sdebug_defer *sd_dp)
3936{
3937 if (!sd_dp)
3938 return;
3939 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3940 hrtimer_cancel(&sd_dp->hrt);
3941 else if (sdebug_jdelay < 0)
3942 cancel_work_sync(&sd_dp->ew.work);
3943}
3944
Douglas Gilberta10bc122016-04-25 12:16:32 -04003945/* If @cmnd found deletes its timer or work queue and returns true; else
3946 returns false */
3947static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003948{
3949 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003950 int j, k, qmax, r_qmax;
3951 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003952 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003953 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003954 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003955
Douglas Gilbertc4837392016-05-06 00:40:26 -04003956 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3957 spin_lock_irqsave(&sqp->qc_lock, iflags);
3958 qmax = sdebug_max_queue;
3959 r_qmax = atomic_read(&retired_max_queue);
3960 if (r_qmax > qmax)
3961 qmax = r_qmax;
3962 for (k = 0; k < qmax; ++k) {
3963 if (test_bit(k, sqp->in_use_bm)) {
3964 sqcp = &sqp->qc_arr[k];
3965 if (cmnd != sqcp->a_cmnd)
3966 continue;
3967 /* found */
3968 devip = (struct sdebug_dev_info *)
3969 cmnd->device->hostdata;
3970 if (devip)
3971 atomic_dec(&devip->num_in_q);
3972 sqcp->a_cmnd = NULL;
3973 sd_dp = sqcp->sd_dp;
3974 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3975 stop_qc_helper(sd_dp);
3976 clear_bit(k, sqp->in_use_bm);
3977 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003978 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003979 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003980 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003981 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003982 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003983}
3984
Douglas Gilberta10bc122016-04-25 12:16:32 -04003985/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003986static void stop_all_queued(void)
3987{
3988 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003989 int j, k;
3990 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003991 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003992 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003993 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003994
Douglas Gilbertc4837392016-05-06 00:40:26 -04003995 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3996 spin_lock_irqsave(&sqp->qc_lock, iflags);
3997 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3998 if (test_bit(k, sqp->in_use_bm)) {
3999 sqcp = &sqp->qc_arr[k];
4000 if (sqcp->a_cmnd == NULL)
4001 continue;
4002 devip = (struct sdebug_dev_info *)
4003 sqcp->a_cmnd->device->hostdata;
4004 if (devip)
4005 atomic_dec(&devip->num_in_q);
4006 sqcp->a_cmnd = NULL;
4007 sd_dp = sqcp->sd_dp;
4008 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4009 stop_qc_helper(sd_dp);
4010 clear_bit(k, sqp->in_use_bm);
4011 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004012 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004013 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004014 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016}
4017
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004018/* Free queued command memory on heap */
4019static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004021 int j, k;
4022 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004023 struct sdebug_queued_cmd *sqcp;
4024
Douglas Gilbertc4837392016-05-06 00:40:26 -04004025 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4026 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4027 sqcp = &sqp->qc_arr[k];
4028 kfree(sqcp->sd_dp);
4029 sqcp->sd_dp = NULL;
4030 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032}
4033
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004034static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004036 bool ok;
4037
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004038 ++num_aborts;
4039 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004040 ok = stop_queued_cmnd(SCpnt);
4041 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4042 sdev_printk(KERN_INFO, SCpnt->device,
4043 "%s: command%s found\n", __func__,
4044 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004046 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047}
4048
4049static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
4050{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004052 if (SCpnt && SCpnt->device) {
4053 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004054 struct sdebug_dev_info *devip =
4055 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004056
Douglas Gilbert773642d2016-04-25 12:16:28 -04004057 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004058 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004060 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 }
4062 return SUCCESS;
4063}
4064
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004065static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4066{
4067 struct sdebug_host_info *sdbg_host;
4068 struct sdebug_dev_info *devip;
4069 struct scsi_device *sdp;
4070 struct Scsi_Host *hp;
4071 int k = 0;
4072
4073 ++num_target_resets;
4074 if (!SCpnt)
4075 goto lie;
4076 sdp = SCpnt->device;
4077 if (!sdp)
4078 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004079 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004080 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4081 hp = sdp->host;
4082 if (!hp)
4083 goto lie;
4084 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4085 if (sdbg_host) {
4086 list_for_each_entry(devip,
4087 &sdbg_host->dev_info_list,
4088 dev_list)
4089 if (devip->target == sdp->id) {
4090 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4091 ++k;
4092 }
4093 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004094 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004095 sdev_printk(KERN_INFO, sdp,
4096 "%s: %d device(s) found in target\n", __func__, k);
4097lie:
4098 return SUCCESS;
4099}
4100
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
4102{
4103 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004104 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004105 struct scsi_device *sdp;
4106 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004107 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004110 if (!(SCpnt && SCpnt->device))
4111 goto lie;
4112 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004113 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004114 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4115 hp = sdp->host;
4116 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004117 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004119 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05004120 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004121 dev_list) {
4122 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4123 ++k;
4124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 }
4126 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004127 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004128 sdev_printk(KERN_INFO, sdp,
4129 "%s: %d device(s) found in host\n", __func__, k);
4130lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 return SUCCESS;
4132}
4133
4134static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
4135{
4136 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004137 struct sdebug_dev_info *devip;
4138 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004141 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004142 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05004143 spin_lock(&sdebug_host_list_lock);
4144 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004145 list_for_each_entry(devip, &sdbg_host->dev_info_list,
4146 dev_list) {
4147 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4148 ++k;
4149 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05004150 }
4151 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004153 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004154 sdev_printk(KERN_INFO, SCpnt->device,
4155 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 return SUCCESS;
4157}
4158
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09004159static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004160 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161{
4162 struct partition * pp;
4163 int starts[SDEBUG_MAX_PARTS + 2];
4164 int sectors_per_part, num_sectors, k;
4165 int heads_by_sects, start_sec, end_sec;
4166
4167 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004168 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004170 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4171 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03004172 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004174 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004176 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004178 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004179 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4181 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004182 starts[sdebug_num_parts] = num_sectors;
4183 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184
4185 ramp[510] = 0x55; /* magic partition markings */
4186 ramp[511] = 0xAA;
4187 pp = (struct partition *)(ramp + 0x1be);
4188 for (k = 0; starts[k + 1]; ++k, ++pp) {
4189 start_sec = starts[k];
4190 end_sec = starts[k + 1] - 1;
4191 pp->boot_ind = 0;
4192
4193 pp->cyl = start_sec / heads_by_sects;
4194 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4195 / sdebug_sectors_per;
4196 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4197
4198 pp->end_cyl = end_sec / heads_by_sects;
4199 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4200 / sdebug_sectors_per;
4201 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4202
Akinobu Mita150c3542013-08-26 22:08:40 +09004203 pp->start_sect = cpu_to_le32(start_sec);
4204 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 pp->sys_ind = 0x83; /* plain Linux partition */
4206 }
4207}
4208
Douglas Gilbertc4837392016-05-06 00:40:26 -04004209static void block_unblock_all_queues(bool block)
4210{
4211 int j;
4212 struct sdebug_queue *sqp;
4213
4214 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4215 atomic_set(&sqp->blocked, (int)block);
4216}
4217
4218/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4219 * commands will be processed normally before triggers occur.
4220 */
4221static void tweak_cmnd_count(void)
4222{
4223 int count, modulo;
4224
4225 modulo = abs(sdebug_every_nth);
4226 if (modulo < 2)
4227 return;
4228 block_unblock_all_queues(true);
4229 count = atomic_read(&sdebug_cmnd_count);
4230 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4231 block_unblock_all_queues(false);
4232}
4233
4234static void clear_queue_stats(void)
4235{
4236 atomic_set(&sdebug_cmnd_count, 0);
4237 atomic_set(&sdebug_completions, 0);
4238 atomic_set(&sdebug_miss_cpus, 0);
4239 atomic_set(&sdebug_a_tsf, 0);
4240}
4241
4242static void setup_inject(struct sdebug_queue *sqp,
4243 struct sdebug_queued_cmd *sqcp)
4244{
4245 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4246 return;
4247 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4248 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4249 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4250 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4251 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004252 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004253}
4254
4255/* Complete the processing of the thread that queued a SCSI command to this
4256 * driver. It either completes the command by calling cmnd_done() or
4257 * schedules a hr timer or work queue then returns 0. Returns
4258 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4259 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004260static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4261 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004263 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004264 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004265 struct sdebug_queue *sqp;
4266 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004267 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004268 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004270 if (unlikely(devip == NULL)) {
4271 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004272 scsi_result = DID_NO_CONNECT << 16;
4273 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004275 sdp = cmnd->device;
4276
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004277 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004278 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4279 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004280 if (delta_jiff == 0)
4281 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004283 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004284 sqp = get_queue(cmnd);
4285 spin_lock_irqsave(&sqp->qc_lock, iflags);
4286 if (unlikely(atomic_read(&sqp->blocked))) {
4287 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4288 return SCSI_MLQUEUE_HOST_BUSY;
4289 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004290 num_in_q = atomic_read(&devip->num_in_q);
4291 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004292 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004293 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004294 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004295 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004296 goto respond_in_thread;
4297 } else
4298 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004299 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004300 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4301 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004302 if ((num_in_q == (qdepth - 1)) &&
4303 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004304 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004305 atomic_set(&sdebug_a_tsf, 0);
4306 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004307 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004309 }
4310
Douglas Gilbertc4837392016-05-06 00:40:26 -04004311 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004312 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004313 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004314 if (scsi_result)
4315 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004316 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004317 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004318 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004319 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004320 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004321 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004322 (scsi_result ? "status: TASK SET FULL" :
4323 "report: host busy"));
4324 if (scsi_result)
4325 goto respond_in_thread;
4326 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004327 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004329 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004330 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004331 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004332 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004333 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004334 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004335 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004336 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4337 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4338 setup_inject(sqp, sqcp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004339 if (delta_jiff > 0 || sdebug_ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004340 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004341
Douglas Gilbertb333a812016-04-25 12:16:30 -04004342 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004343 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004344 } else
Thomas Gleixner8b0e1952016-12-25 12:30:41 +01004345 kt = sdebug_ndelay;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004346 if (NULL == sd_dp) {
4347 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4348 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004349 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004350 sqcp->sd_dp = sd_dp;
4351 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004352 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004353 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004354 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4355 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004356 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004357 if (sdebug_statistics)
4358 sd_dp->issuing_cpu = raw_smp_processor_id();
4359 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4360 } else { /* jdelay < 0, use work queue */
Douglas Gilberta10bc122016-04-25 12:16:32 -04004361 if (NULL == sd_dp) {
4362 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4363 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004364 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004365 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004366 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4367 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004368 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004369 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004370 if (sdebug_statistics)
4371 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilberta10bc122016-04-25 12:16:32 -04004372 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004373 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004374 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4375 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004376 sdev_printk(KERN_INFO, sdp,
4377 "%s: num_in_q=%d +1, %s%s\n", __func__,
4378 num_in_q, (inject ? "<inject> " : ""),
4379 "status: TASK SET FULL");
4380 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004381
4382respond_in_thread: /* call back to mid-layer using invocation thread */
4383 cmnd->result = scsi_result;
4384 cmnd->scsi_done(cmnd);
4385 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004387
Douglas Gilbert23183912006-09-16 20:30:47 -04004388/* Note: The following macros create attribute files in the
4389 /sys/module/scsi_debug/parameters directory. Unfortunately this
4390 driver is unaware of a change and cannot trigger auxiliary actions
4391 as it can when the corresponding attribute in the
4392 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4393 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004394module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4395module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004396module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004397module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004398module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004399module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4400module_param_named(dif, sdebug_dif, int, S_IRUGO);
4401module_param_named(dix, sdebug_dix, int, S_IRUGO);
4402module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4403module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4404module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4405module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4406module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004407module_param_string(inq_vendor, sdebug_inq_vendor_id,
4408 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4409module_param_string(inq_product, sdebug_inq_product_id,
4410 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4411module_param_string(inq_rev, sdebug_inq_product_rev,
4412 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004413module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4414module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4415module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4416module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4417module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4418module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4419module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4420module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4421module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4422module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4423module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4424module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4425module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4426module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4427module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004428module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004429module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4430module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4431module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4432module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004433module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004434module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004435module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004436module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4437module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4438module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4439module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4440module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004441module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004442module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004443 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004444module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004445 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446
4447MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4448MODULE_DESCRIPTION("SCSI debug adapter driver");
4449MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004450MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451
4452MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004453MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004454MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004455MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004456MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004457MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004458MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4459MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004460MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004461MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004462MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004463MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004464MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004465MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4466MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004467MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4468 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004469MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4470MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4471MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004472MODULE_PARM_DESC(lbprz,
4473 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004474MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004475MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004476MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4477MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004478MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004479MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004481MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004482MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004483MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004484MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004485MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004487MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004488MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004489MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004490MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004491MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004492MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004493MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4494MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004495MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4496MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004497MODULE_PARM_DESC(uuid_ctl,
4498 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004499MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004500MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4501MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004503#define SDEBUG_INFO_LEN 256
4504static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505
4506static const char * scsi_debug_info(struct Scsi_Host * shp)
4507{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004508 int k;
4509
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004510 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4511 my_name, SDEBUG_VERSION, sdebug_version_date);
4512 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004513 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004514 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4515 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4516 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4517 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 return sdebug_info;
4519}
4520
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004521/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004522static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4523 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524{
Al Viroc8ed5552013-03-31 01:46:06 -04004525 char arr[16];
4526 int opts;
4527 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528
Al Viroc8ed5552013-03-31 01:46:06 -04004529 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4530 return -EACCES;
4531 memcpy(arr, buffer, minLen);
4532 arr[minLen] = '\0';
4533 if (1 != sscanf(arr, "%d", &opts))
4534 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004535 sdebug_opts = opts;
4536 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4537 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4538 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004539 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004540 return length;
4541}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004543/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4544 * same for each scsi_debug host (if more than one). Some of the counters
4545 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004546static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4547{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004548 int f, j, l;
4549 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004550
Douglas Gilbertc4837392016-05-06 00:40:26 -04004551 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4552 SDEBUG_VERSION, sdebug_version_date);
4553 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4554 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4555 sdebug_opts, sdebug_every_nth);
4556 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4557 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4558 sdebug_sector_size, "bytes");
4559 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4560 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4561 num_aborts);
4562 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4563 num_dev_resets, num_target_resets, num_bus_resets,
4564 num_host_resets);
4565 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4566 dix_reads, dix_writes, dif_errors);
4567 seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4568 TICK_NSEC / 1000, "statistics", sdebug_statistics,
4569 sdebug_mq_active);
4570 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4571 atomic_read(&sdebug_cmnd_count),
4572 atomic_read(&sdebug_completions),
4573 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4574 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004575
Douglas Gilbertc4837392016-05-06 00:40:26 -04004576 seq_printf(m, "submit_queues=%d\n", submit_queues);
4577 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4578 seq_printf(m, " queue %d:\n", j);
4579 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4580 if (f != sdebug_max_queue) {
4581 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4582 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4583 "first,last bits", f, l);
4584 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004585 }
Al Viroc8ed5552013-03-31 01:46:06 -04004586 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587}
4588
Akinobu Mita82069372013-10-14 22:48:04 +09004589static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004591 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004593/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4594 * of delay is jiffies.
4595 */
Akinobu Mita82069372013-10-14 22:48:04 +09004596static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4597 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004599 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004601 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004602 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004603 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004604 int j, k;
4605 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004606
Douglas Gilbertc4837392016-05-06 00:40:26 -04004607 block_unblock_all_queues(true);
4608 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4609 ++j, ++sqp) {
4610 k = find_first_bit(sqp->in_use_bm,
4611 sdebug_max_queue);
4612 if (k != sdebug_max_queue) {
4613 res = -EBUSY; /* queued commands */
4614 break;
4615 }
4616 }
4617 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004618 /* make sure sdebug_defer instances get
4619 * re-allocated for new delay variant */
4620 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004621 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004622 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004623 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004624 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004626 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 }
4628 return -EINVAL;
4629}
Akinobu Mita82069372013-10-14 22:48:04 +09004630static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004632static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4633{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004634 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004635}
4636/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004637/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004638static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004639 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004640{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004641 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004642
4643 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004644 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004645 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004646 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004647 int j, k;
4648 struct sdebug_queue *sqp;
4649
4650 block_unblock_all_queues(true);
4651 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4652 ++j, ++sqp) {
4653 k = find_first_bit(sqp->in_use_bm,
4654 sdebug_max_queue);
4655 if (k != sdebug_max_queue) {
4656 res = -EBUSY; /* queued commands */
4657 break;
4658 }
4659 }
4660 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004661 /* make sure sdebug_defer instances get
4662 * re-allocated for new delay variant */
4663 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004664 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004665 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4666 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004667 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004668 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004669 }
4670 return res;
4671 }
4672 return -EINVAL;
4673}
4674static DRIVER_ATTR_RW(ndelay);
4675
Akinobu Mita82069372013-10-14 22:48:04 +09004676static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004678 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679}
4680
Akinobu Mita82069372013-10-14 22:48:04 +09004681static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4682 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004684 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 char work[20];
4686
Douglas Gilbert9a051012017-12-23 12:48:10 -05004687 if (sscanf(buf, "%10s", work) == 1) {
4688 if (strncasecmp(work, "0x", 2) == 0) {
4689 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 goto opts_done;
4691 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004692 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 goto opts_done;
4694 }
4695 }
4696 return -EINVAL;
4697opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004698 sdebug_opts = opts;
4699 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4700 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004701 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 return count;
4703}
Akinobu Mita82069372013-10-14 22:48:04 +09004704static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705
Akinobu Mita82069372013-10-14 22:48:04 +09004706static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004708 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709}
Akinobu Mita82069372013-10-14 22:48:04 +09004710static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4711 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004713 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714
4715 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004716 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 return count;
4718 }
4719 return -EINVAL;
4720}
Akinobu Mita82069372013-10-14 22:48:04 +09004721static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
Akinobu Mita82069372013-10-14 22:48:04 +09004723static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004725 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726}
Akinobu Mita82069372013-10-14 22:48:04 +09004727static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4728 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004730 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731
4732 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004733 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 return count;
4735 }
4736 return -EINVAL;
4737}
Akinobu Mita82069372013-10-14 22:48:04 +09004738static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739
Akinobu Mita82069372013-10-14 22:48:04 +09004740static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004741{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004742 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004743}
Akinobu Mita82069372013-10-14 22:48:04 +09004744static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4745 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004746{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004747 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004748
4749 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004750 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004751 sdebug_fake_rw = (sdebug_fake_rw > 0);
4752 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004753 if ((0 == n) && (NULL == fake_storep)) {
4754 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004755 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004756 1048576;
4757
4758 fake_storep = vmalloc(sz);
4759 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004760 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004761 return -ENOMEM;
4762 }
4763 memset(fake_storep, 0, sz);
4764 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004765 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004766 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004767 return count;
4768 }
4769 return -EINVAL;
4770}
Akinobu Mita82069372013-10-14 22:48:04 +09004771static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004772
Akinobu Mita82069372013-10-14 22:48:04 +09004773static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004774{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004775 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004776}
Akinobu Mita82069372013-10-14 22:48:04 +09004777static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4778 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004779{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004780 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004781
4782 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004783 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004784 return count;
4785 }
4786 return -EINVAL;
4787}
Akinobu Mita82069372013-10-14 22:48:04 +09004788static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004789
Akinobu Mita82069372013-10-14 22:48:04 +09004790static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004792 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793}
Akinobu Mita82069372013-10-14 22:48:04 +09004794static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4795 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004797 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798
4799 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004800 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 sdebug_max_tgts_luns();
4802 return count;
4803 }
4804 return -EINVAL;
4805}
Akinobu Mita82069372013-10-14 22:48:04 +09004806static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
Akinobu Mita82069372013-10-14 22:48:04 +09004808static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004810 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811}
Akinobu Mita82069372013-10-14 22:48:04 +09004812static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813
Akinobu Mita82069372013-10-14 22:48:04 +09004814static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004816 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817}
Akinobu Mita82069372013-10-14 22:48:04 +09004818static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819
Akinobu Mita82069372013-10-14 22:48:04 +09004820static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004822 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823}
Akinobu Mita82069372013-10-14 22:48:04 +09004824static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4825 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004827 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828
4829 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004830 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004831 if (nth && !sdebug_statistics) {
4832 pr_info("every_nth needs statistics=1, set it\n");
4833 sdebug_statistics = true;
4834 }
4835 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 return count;
4837 }
4838 return -EINVAL;
4839}
Akinobu Mita82069372013-10-14 22:48:04 +09004840static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841
Akinobu Mita82069372013-10-14 22:48:04 +09004842static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004844 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845}
Akinobu Mita82069372013-10-14 22:48:04 +09004846static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4847 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004849 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004850 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851
4852 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004853 if (n > 256) {
4854 pr_warn("max_luns can be no more than 256\n");
4855 return -EINVAL;
4856 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004857 changed = (sdebug_max_luns != n);
4858 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004860 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004861 struct sdebug_host_info *sdhp;
4862 struct sdebug_dev_info *dp;
4863
4864 spin_lock(&sdebug_host_list_lock);
4865 list_for_each_entry(sdhp, &sdebug_host_list,
4866 host_list) {
4867 list_for_each_entry(dp, &sdhp->dev_info_list,
4868 dev_list) {
4869 set_bit(SDEBUG_UA_LUNS_CHANGED,
4870 dp->uas_bm);
4871 }
4872 }
4873 spin_unlock(&sdebug_host_list_lock);
4874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 return count;
4876 }
4877 return -EINVAL;
4878}
Akinobu Mita82069372013-10-14 22:48:04 +09004879static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880
Akinobu Mita82069372013-10-14 22:48:04 +09004881static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004882{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004883 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004884}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004885/* N.B. max_queue can be changed while there are queued commands. In flight
4886 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004887static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4888 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004889{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004890 int j, n, k, a;
4891 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004892
4893 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004894 (n <= SDEBUG_CANQUEUE)) {
4895 block_unblock_all_queues(true);
4896 k = 0;
4897 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4898 ++j, ++sqp) {
4899 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4900 if (a > k)
4901 k = a;
4902 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004903 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004904 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004905 atomic_set(&retired_max_queue, 0);
4906 else if (k >= n)
4907 atomic_set(&retired_max_queue, k + 1);
4908 else
4909 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004910 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004911 return count;
4912 }
4913 return -EINVAL;
4914}
Akinobu Mita82069372013-10-14 22:48:04 +09004915static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004916
Akinobu Mita82069372013-10-14 22:48:04 +09004917static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004918{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004919 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004920}
Akinobu Mita82069372013-10-14 22:48:04 +09004921static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004922
Akinobu Mita82069372013-10-14 22:48:04 +09004923static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004925 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926}
Akinobu Mita82069372013-10-14 22:48:04 +09004927static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928
Akinobu Mita82069372013-10-14 22:48:04 +09004929static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004930{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004931 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004932}
Akinobu Mita82069372013-10-14 22:48:04 +09004933static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4934 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004935{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004936 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004937 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004938
4939 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004940 changed = (sdebug_virtual_gb != n);
4941 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004942 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004943 if (changed) {
4944 struct sdebug_host_info *sdhp;
4945 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004946
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004947 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004948 list_for_each_entry(sdhp, &sdebug_host_list,
4949 host_list) {
4950 list_for_each_entry(dp, &sdhp->dev_info_list,
4951 dev_list) {
4952 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4953 dp->uas_bm);
4954 }
4955 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004956 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004957 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004958 return count;
4959 }
4960 return -EINVAL;
4961}
Akinobu Mita82069372013-10-14 22:48:04 +09004962static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004963
Akinobu Mita82069372013-10-14 22:48:04 +09004964static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004966 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967}
4968
Douglas Gilbertfd321192016-04-25 12:16:33 -04004969static int sdebug_add_adapter(void);
4970static void sdebug_remove_adapter(void);
4971
Akinobu Mita82069372013-10-14 22:48:04 +09004972static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4973 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004975 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004976
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004977 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979 if (delta_hosts > 0) {
4980 do {
4981 sdebug_add_adapter();
4982 } while (--delta_hosts);
4983 } else if (delta_hosts < 0) {
4984 do {
4985 sdebug_remove_adapter();
4986 } while (++delta_hosts);
4987 }
4988 return count;
4989}
Akinobu Mita82069372013-10-14 22:48:04 +09004990static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991
Akinobu Mita82069372013-10-14 22:48:04 +09004992static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004993{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004994 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004995}
Akinobu Mita82069372013-10-14 22:48:04 +09004996static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4997 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004998{
4999 int n;
5000
5001 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005002 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04005003 return count;
5004 }
5005 return -EINVAL;
5006}
Akinobu Mita82069372013-10-14 22:48:04 +09005007static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005008
Douglas Gilbertc4837392016-05-06 00:40:26 -04005009static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5010{
5011 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5012}
5013static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5014 size_t count)
5015{
5016 int n;
5017
5018 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5019 if (n > 0)
5020 sdebug_statistics = true;
5021 else {
5022 clear_queue_stats();
5023 sdebug_statistics = false;
5024 }
5025 return count;
5026 }
5027 return -EINVAL;
5028}
5029static DRIVER_ATTR_RW(statistics);
5030
Akinobu Mita82069372013-10-14 22:48:04 +09005031static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04005032{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005033 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005034}
Akinobu Mita82069372013-10-14 22:48:04 +09005035static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005036
Douglas Gilbertc4837392016-05-06 00:40:26 -04005037static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5038{
5039 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5040}
5041static DRIVER_ATTR_RO(submit_queues);
5042
Akinobu Mita82069372013-10-14 22:48:04 +09005043static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005044{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005045 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005046}
Akinobu Mita82069372013-10-14 22:48:04 +09005047static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005048
Akinobu Mita82069372013-10-14 22:48:04 +09005049static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005050{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005051 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005052}
Akinobu Mita82069372013-10-14 22:48:04 +09005053static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005054
Akinobu Mita82069372013-10-14 22:48:04 +09005055static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005056{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005057 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005058}
Akinobu Mita82069372013-10-14 22:48:04 +09005059static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005060
Akinobu Mita82069372013-10-14 22:48:04 +09005061static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005062{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005063 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005064}
Akinobu Mita82069372013-10-14 22:48:04 +09005065static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005066
Akinobu Mita82069372013-10-14 22:48:04 +09005067static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005068{
5069 ssize_t count;
5070
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005071 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04005072 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
5073 sdebug_store_sectors);
5074
Tejun Heoc7badc92015-02-13 14:37:51 -08005075 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5076 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005077 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08005078 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04005079
5080 return count;
5081}
Akinobu Mita82069372013-10-14 22:48:04 +09005082static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005083
Akinobu Mita82069372013-10-14 22:48:04 +09005084static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02005085{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005086 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02005087}
Akinobu Mita82069372013-10-14 22:48:04 +09005088static ssize_t removable_store(struct device_driver *ddp, const char *buf,
5089 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02005090{
5091 int n;
5092
5093 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005094 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02005095 return count;
5096 }
5097 return -EINVAL;
5098}
Akinobu Mita82069372013-10-14 22:48:04 +09005099static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02005100
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005101static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5102{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005103 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005104}
Douglas Gilbert185dd232016-04-25 12:16:29 -04005105/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005106static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5107 size_t count)
5108{
Douglas Gilbert185dd232016-04-25 12:16:29 -04005109 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005110
5111 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04005112 sdebug_host_lock = (n > 0);
5113 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005114 }
5115 return -EINVAL;
5116}
5117static DRIVER_ATTR_RW(host_lock);
5118
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005119static ssize_t strict_show(struct device_driver *ddp, char *buf)
5120{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005121 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005122}
5123static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5124 size_t count)
5125{
5126 int n;
5127
5128 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005129 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005130 return count;
5131 }
5132 return -EINVAL;
5133}
5134static DRIVER_ATTR_RW(strict);
5135
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005136static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
5137{
5138 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
5139}
5140static DRIVER_ATTR_RO(uuid_ctl);
5141
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005142static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
5143{
5144 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
5145}
5146static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
5147 size_t count)
5148{
5149 int ret, n;
5150
5151 ret = kstrtoint(buf, 0, &n);
5152 if (ret)
5153 return ret;
5154 sdebug_cdb_len = n;
5155 all_config_cdb_len();
5156 return count;
5157}
5158static DRIVER_ATTR_RW(cdb_len);
5159
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005160
Akinobu Mita82069372013-10-14 22:48:04 +09005161/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04005162 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
5163 files (over those found in the /sys/module/scsi_debug/parameters
5164 directory) is that auxiliary actions can be triggered when an attribute
5165 is changed. For example see: sdebug_add_host_store() above.
5166 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005167
Akinobu Mita82069372013-10-14 22:48:04 +09005168static struct attribute *sdebug_drv_attrs[] = {
5169 &driver_attr_delay.attr,
5170 &driver_attr_opts.attr,
5171 &driver_attr_ptype.attr,
5172 &driver_attr_dsense.attr,
5173 &driver_attr_fake_rw.attr,
5174 &driver_attr_no_lun_0.attr,
5175 &driver_attr_num_tgts.attr,
5176 &driver_attr_dev_size_mb.attr,
5177 &driver_attr_num_parts.attr,
5178 &driver_attr_every_nth.attr,
5179 &driver_attr_max_luns.attr,
5180 &driver_attr_max_queue.attr,
5181 &driver_attr_no_uld.attr,
5182 &driver_attr_scsi_level.attr,
5183 &driver_attr_virtual_gb.attr,
5184 &driver_attr_add_host.attr,
5185 &driver_attr_vpd_use_hostno.attr,
5186 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005187 &driver_attr_statistics.attr,
5188 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005189 &driver_attr_dix.attr,
5190 &driver_attr_dif.attr,
5191 &driver_attr_guard.attr,
5192 &driver_attr_ato.attr,
5193 &driver_attr_map.attr,
5194 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005195 &driver_attr_host_lock.attr,
5196 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005197 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005198 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005199 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005200 NULL,
5201};
5202ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005204static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005205
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206static int __init scsi_debug_init(void)
5207{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005208 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 int host_to_add;
5210 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005211 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005213 atomic_set(&retired_max_queue, 0);
5214
Douglas Gilbert773642d2016-04-25 12:16:28 -04005215 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005216 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005217 sdebug_ndelay = 0;
5218 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005219 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005220
Douglas Gilbert773642d2016-04-25 12:16:28 -04005221 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04005222 case 512:
5223 case 1024:
5224 case 2048:
5225 case 4096:
5226 break;
5227 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005228 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005229 return -EINVAL;
5230 }
5231
Douglas Gilbert773642d2016-04-25 12:16:28 -04005232 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005233 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005234 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005235 case T10_PI_TYPE1_PROTECTION:
5236 case T10_PI_TYPE2_PROTECTION:
5237 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005238 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005239 break;
5240
5241 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005242 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005243 return -EINVAL;
5244 }
5245
Douglas Gilbert773642d2016-04-25 12:16:28 -04005246 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005247 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005248 return -EINVAL;
5249 }
5250
Douglas Gilbert773642d2016-04-25 12:16:28 -04005251 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005252 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005253 return -EINVAL;
5254 }
5255
Douglas Gilbert773642d2016-04-25 12:16:28 -04005256 if (sdebug_physblk_exp > 15) {
5257 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005258 return -EINVAL;
5259 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005260 if (sdebug_max_luns > 256) {
5261 pr_warn("max_luns can be no more than 256, use default\n");
5262 sdebug_max_luns = DEF_MAX_LUNS;
5263 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005264
Douglas Gilbert773642d2016-04-25 12:16:28 -04005265 if (sdebug_lowest_aligned > 0x3fff) {
5266 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005267 return -EINVAL;
5268 }
5269
Douglas Gilbertc4837392016-05-06 00:40:26 -04005270 if (submit_queues < 1) {
5271 pr_err("submit_queues must be 1 or more\n");
5272 return -EINVAL;
5273 }
5274 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5275 GFP_KERNEL);
5276 if (sdebug_q_arr == NULL)
5277 return -ENOMEM;
5278 for (k = 0; k < submit_queues; ++k)
5279 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5280
Douglas Gilbert773642d2016-04-25 12:16:28 -04005281 if (sdebug_dev_size_mb < 1)
5282 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5283 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5284 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005285 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286
5287 /* play around with geometry, don't waste too much on track 0 */
5288 sdebug_heads = 8;
5289 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005290 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005292 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005293 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5295 (sdebug_sectors_per * sdebug_heads);
5296 if (sdebug_cylinders_per >= 1024) {
5297 /* other LLDs do this; implies >= 1GB ram disk ... */
5298 sdebug_heads = 255;
5299 sdebug_sectors_per = 63;
5300 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5301 (sdebug_sectors_per * sdebug_heads);
5302 }
5303
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005304 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005305 fake_storep = vmalloc(sz);
5306 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005307 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005308 ret = -ENOMEM;
5309 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005310 }
5311 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005312 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005313 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315
Douglas Gilbert773642d2016-04-25 12:16:28 -04005316 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005317 int dif_size;
5318
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005319 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005320 dif_storep = vmalloc(dif_size);
5321
Tomas Winklerc12879702015-07-28 16:54:20 +03005322 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005323
5324 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005325 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005326 ret = -ENOMEM;
5327 goto free_vm;
5328 }
5329
5330 memset(dif_storep, 0xff, dif_size);
5331 }
5332
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005333 /* Logical Block Provisioning */
5334 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005335 sdebug_unmap_max_blocks =
5336 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005337
Douglas Gilbert773642d2016-04-25 12:16:28 -04005338 sdebug_unmap_max_desc =
5339 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005340
Douglas Gilbert773642d2016-04-25 12:16:28 -04005341 sdebug_unmap_granularity =
5342 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005343
Douglas Gilbert773642d2016-04-25 12:16:28 -04005344 if (sdebug_unmap_alignment &&
5345 sdebug_unmap_granularity <=
5346 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005347 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005348 ret = -EINVAL;
5349 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005350 }
5351
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005352 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5353 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005354
Tomas Winklerc12879702015-07-28 16:54:20 +03005355 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005356
5357 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005358 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005359 ret = -ENOMEM;
5360 goto free_vm;
5361 }
5362
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005363 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005364
5365 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005366 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005367 map_region(0, 2);
5368 }
5369
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005370 pseudo_primary = root_device_register("pseudo_0");
5371 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005372 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005373 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005374 goto free_vm;
5375 }
5376 ret = bus_register(&pseudo_lld_bus);
5377 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005378 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005379 goto dev_unreg;
5380 }
5381 ret = driver_register(&sdebug_driverfs_driver);
5382 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005383 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005384 goto bus_unreg;
5385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386
Douglas Gilbert773642d2016-04-25 12:16:28 -04005387 host_to_add = sdebug_add_host;
5388 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389
Douglas Gilbert9a051012017-12-23 12:48:10 -05005390 for (k = 0; k < host_to_add; k++) {
5391 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005392 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005393 break;
5394 }
5395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396
Douglas Gilbert773642d2016-04-25 12:16:28 -04005397 if (sdebug_verbose)
5398 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005399
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005401
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005402bus_unreg:
5403 bus_unregister(&pseudo_lld_bus);
5404dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005405 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005406free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005407 vfree(map_storep);
5408 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005409 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005410free_q_arr:
5411 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005412 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413}
5414
5415static void __exit scsi_debug_exit(void)
5416{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005417 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418
5419 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005420 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 for (; k; k--)
5422 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 driver_unregister(&sdebug_driverfs_driver);
5424 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005425 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005427 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005428 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005430 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431}
5432
5433device_initcall(scsi_debug_init);
5434module_exit(scsi_debug_exit);
5435
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436static void sdebug_release_adapter(struct device * dev)
5437{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005438 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439
5440 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005441 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442}
5443
5444static int sdebug_add_adapter(void)
5445{
5446 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005447 int error = 0;
5448 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005449 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450
Douglas Gilbert9a051012017-12-23 12:48:10 -05005451 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5452 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005453 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005454 return -ENOMEM;
5455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456
Douglas Gilbert9a051012017-12-23 12:48:10 -05005457 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458
Douglas Gilbert773642d2016-04-25 12:16:28 -04005459 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005460 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005461 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5462 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005463 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005464 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005466 }
5467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468
Douglas Gilbert9a051012017-12-23 12:48:10 -05005469 spin_lock(&sdebug_host_list_lock);
5470 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5471 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472
Douglas Gilbert9a051012017-12-23 12:48:10 -05005473 sdbg_host->dev.bus = &pseudo_lld_bus;
5474 sdbg_host->dev.parent = pseudo_primary;
5475 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005476 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
Douglas Gilbert9a051012017-12-23 12:48:10 -05005478 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
Douglas Gilbert9a051012017-12-23 12:48:10 -05005480 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 goto clean;
5482
Douglas Gilbert773642d2016-04-25 12:16:28 -04005483 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005484 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485
5486clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005487 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5488 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 list_del(&sdbg_devinfo->dev_list);
5490 kfree(sdbg_devinfo);
5491 }
5492
5493 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005494 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495}
5496
5497static void sdebug_remove_adapter(void)
5498{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005499 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500
Douglas Gilbert9a051012017-12-23 12:48:10 -05005501 spin_lock(&sdebug_host_list_lock);
5502 if (!list_empty(&sdebug_host_list)) {
5503 sdbg_host = list_entry(sdebug_host_list.prev,
5504 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 list_del(&sdbg_host->host_list);
5506 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005507 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508
5509 if (!sdbg_host)
5510 return;
5511
Douglas Gilbert773642d2016-04-25 12:16:28 -04005512 device_unregister(&sdbg_host->dev);
5513 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514}
5515
Douglas Gilbertfd321192016-04-25 12:16:33 -04005516static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005517{
5518 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005519 struct sdebug_dev_info *devip;
5520
Douglas Gilbertc4837392016-05-06 00:40:26 -04005521 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005522 devip = (struct sdebug_dev_info *)sdev->hostdata;
5523 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005524 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005525 return -ENODEV;
5526 }
5527 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005528
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005529 if (qdepth < 1)
5530 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005531 /* allow to exceed max host qc_arr elements for testing */
5532 if (qdepth > SDEBUG_CANQUEUE + 10)
5533 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005534 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005535
Douglas Gilbert773642d2016-04-25 12:16:28 -04005536 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005537 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005538 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005539 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005540 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005541 return sdev->queue_depth;
5542}
5543
Douglas Gilbertc4837392016-05-06 00:40:26 -04005544static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005545{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005546 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005547 if (sdebug_every_nth < -1)
5548 sdebug_every_nth = -1;
5549 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005550 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005551 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005552 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005553 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005554 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005555 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005556}
5557
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005558static bool fake_host_busy(struct scsi_cmnd *scp)
5559{
5560 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5561 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5562}
5563
Douglas Gilbertfd321192016-04-25 12:16:33 -04005564static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5565 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005566{
5567 u8 sdeb_i;
5568 struct scsi_device *sdp = scp->device;
5569 const struct opcode_info_t *oip;
5570 const struct opcode_info_t *r_oip;
5571 struct sdebug_dev_info *devip;
5572 u8 *cmd = scp->cmnd;
5573 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5574 int k, na;
5575 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005576 u32 flags;
5577 u16 sa;
5578 u8 opcode = cmd[0];
5579 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005580
5581 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005582 if (sdebug_statistics)
5583 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005584 if (unlikely(sdebug_verbose &&
5585 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005586 char b[120];
5587 int n, len, sb;
5588
5589 len = scp->cmd_len;
5590 sb = (int)sizeof(b);
5591 if (len > 32)
5592 strcpy(b, "too long, over 32 bytes");
5593 else {
5594 for (k = 0, n = 0; k < len && n < sb; ++k)
5595 n += scnprintf(b + n, sb - n, "%02x ",
5596 (u32)cmd[k]);
5597 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005598 if (sdebug_mq_active)
5599 sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5600 my_name, blk_mq_unique_tag(scp->request),
5601 b);
5602 else
5603 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5604 b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005605 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005606 if (fake_host_busy(scp))
5607 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005608 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005609 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5610 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005611
5612 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5613 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5614 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005615 if (unlikely(!devip)) {
5616 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005617 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005618 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005619 }
5620 na = oip->num_attached;
5621 r_pfp = oip->pfp;
5622 if (na) { /* multiple commands with this opcode */
5623 r_oip = oip;
5624 if (FF_SA & r_oip->flags) {
5625 if (F_SA_LOW & oip->flags)
5626 sa = 0x1f & cmd[1];
5627 else
5628 sa = get_unaligned_be16(cmd + 8);
5629 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5630 if (opcode == oip->opcode && sa == oip->sa)
5631 break;
5632 }
5633 } else { /* since no service action only check opcode */
5634 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5635 if (opcode == oip->opcode)
5636 break;
5637 }
5638 }
5639 if (k > na) {
5640 if (F_SA_LOW & r_oip->flags)
5641 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5642 else if (F_SA_HIGH & r_oip->flags)
5643 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5644 else
5645 mk_sense_invalid_opcode(scp);
5646 goto check_cond;
5647 }
5648 } /* else (when na==0) we assume the oip is a match */
5649 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005650 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005651 mk_sense_invalid_opcode(scp);
5652 goto check_cond;
5653 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005654 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005655 if (sdebug_verbose)
5656 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5657 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005658 mk_sense_invalid_opcode(scp);
5659 goto check_cond;
5660 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005661 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005662 u8 rem;
5663 int j;
5664
5665 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5666 rem = ~oip->len_mask[k] & cmd[k];
5667 if (rem) {
5668 for (j = 7; j >= 0; --j, rem <<= 1) {
5669 if (0x80 & rem)
5670 break;
5671 }
5672 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5673 goto check_cond;
5674 }
5675 }
5676 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005677 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005678 find_first_bit(devip->uas_bm,
5679 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005680 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005681 if (errsts)
5682 goto check_cond;
5683 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005684 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005685 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005686 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005687 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5688 "%s\n", my_name, "initializing command "
5689 "required");
5690 errsts = check_condition_result;
5691 goto fini;
5692 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005693 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005694 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005695 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005696 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005697 return 0; /* ignore command: make trouble */
5698 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005699 if (likely(oip->pfp))
5700 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005701 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5702 errsts = r_pfp(scp, devip);
5703
5704fini:
5705 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005706 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005707check_cond:
5708 return schedule_resp(scp, devip, check_condition_result, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005709err_out:
5710 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005711}
5712
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005713static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005714 .show_info = scsi_debug_show_info,
5715 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005716 .proc_name = sdebug_proc_name,
5717 .name = "SCSI DEBUG",
5718 .info = scsi_debug_info,
5719 .slave_alloc = scsi_debug_slave_alloc,
5720 .slave_configure = scsi_debug_slave_configure,
5721 .slave_destroy = scsi_debug_slave_destroy,
5722 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005723 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005724 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005725 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005726 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005727 .eh_target_reset_handler = scsi_debug_target_reset,
5728 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005729 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005730 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005731 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005732 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005733 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005734 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005735 .use_clustering = DISABLE_CLUSTERING,
5736 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005737 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005738};
5739
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740static int sdebug_driver_probe(struct device * dev)
5741{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005742 int error = 0;
5743 struct sdebug_host_info *sdbg_host;
5744 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005745 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746
5747 sdbg_host = to_sdebug_host(dev);
5748
Douglas Gilbert773642d2016-04-25 12:16:28 -04005749 sdebug_driver_template.can_queue = sdebug_max_queue;
5750 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005751 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005752 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5753 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005754 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005755 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005757 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005758 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005759 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005760 my_name, submit_queues, nr_cpu_ids);
5761 submit_queues = nr_cpu_ids;
5762 }
5763 /* Decide whether to tell scsi subsystem that we want mq */
5764 /* Following should give the same answer for each host */
5765 sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5766 if (sdebug_mq_active)
5767 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
Douglas Gilbert9a051012017-12-23 12:48:10 -05005769 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005771 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5772 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005774 hpnt->max_id = sdebug_num_tgts;
5775 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005776 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005778 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005779
Douglas Gilbert773642d2016-04-25 12:16:28 -04005780 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005781
Christoph Hellwig8475c812016-09-11 19:35:41 +02005782 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005783 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005784 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005785 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005786 break;
5787
Christoph Hellwig8475c812016-09-11 19:35:41 +02005788 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005789 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005790 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005791 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005792 break;
5793
Christoph Hellwig8475c812016-09-11 19:35:41 +02005794 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005795 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005796 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005797 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005798 break;
5799
5800 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005801 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005802 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005803 break;
5804 }
5805
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005806 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005807
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005808 if (have_dif_prot || sdebug_dix)
5809 pr_info("host protection%s%s%s%s%s%s%s\n",
5810 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5811 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5812 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5813 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5814 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5815 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5816 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005817
Douglas Gilbert773642d2016-04-25 12:16:28 -04005818 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005819 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5820 else
5821 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5822
Douglas Gilbert773642d2016-04-25 12:16:28 -04005823 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5824 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005825 if (sdebug_every_nth) /* need stats counters for every_nth */
5826 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005827 error = scsi_add_host(hpnt, &sdbg_host->dev);
5828 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005829 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005830 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005832 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833 scsi_scan_host(hpnt);
5834
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005835 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005836}
5837
5838static int sdebug_driver_remove(struct device * dev)
5839{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005840 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005841 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842
5843 sdbg_host = to_sdebug_host(dev);
5844
5845 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005846 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 return -ENODEV;
5848 }
5849
Douglas Gilbert9a051012017-12-23 12:48:10 -05005850 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005852 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5853 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005854 list_del(&sdbg_devinfo->dev_list);
5855 kfree(sdbg_devinfo);
5856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857
Douglas Gilbert9a051012017-12-23 12:48:10 -05005858 scsi_host_put(sdbg_host->shost);
5859 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860}
5861
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005862static int pseudo_lld_bus_match(struct device *dev,
5863 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005865 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005867
5868static struct bus_type pseudo_lld_bus = {
5869 .name = "pseudo",
5870 .match = pseudo_lld_bus_match,
5871 .probe = sdebug_driver_probe,
5872 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005873 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005874};