blob: 11ef3f19490d1d44179f20ad53a926f4f6dca9d1 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05009 * Copyright (C) 2001 - 2017 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Douglas Gilbert773642d2016-04-25 12:16:28 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040016 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Tomas Winklerc12879702015-07-28 16:54:20 +030020
21#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040027#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/types.h>
30#include <linux/string.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <linux/init.h>
34#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/vmalloc.h>
36#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020037#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050039#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040040#include <linux/spinlock.h>
41#include <linux/interrupt.h>
42#include <linux/atomic.h>
43#include <linux/hrtimer.h>
Douglas Gilbert09ba24c2016-05-06 00:40:28 -040044#include <linux/uuid.h>
Christoph Hellwig6ebf1052016-09-11 19:35:39 +020045#include <linux/t10-pi.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050046
47#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090048
Martin K. Petersen44d92692009-10-15 14:45:27 -040049#include <asm/unaligned.h>
50
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090051#include <scsi/scsi.h>
52#include <scsi/scsi_cmnd.h>
53#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <scsi/scsi_host.h>
55#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090056#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040057#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040058#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Martin K. Petersenc6a44282009-01-04 03:08:19 -050060#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Douglas Gilbert773642d2016-04-25 12:16:28 -040063/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbert9b760fd2017-12-05 00:05:49 -050064#define SDEBUG_VERSION "0187" /* format to fit INQUIRY revision field */
65static const char *sdebug_version_date = "20171202";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040066
67#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define NO_ADDITIONAL_SENSE 0x0
71#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050072#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040074#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050076#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040078#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040079#define UA_RESET_ASC 0x29
80#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050081#define TARGET_CHANGED_ASC 0x3f
82#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050083#define INSUFF_RES_ASC 0x55
84#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040085#define POWER_ON_RESET_ASCQ 0x0
86#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
87#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050088#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050090#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define THRESHOLD_EXCEEDED 0x5d
92#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050093#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050094#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
95#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050097/* Additional Sense Code Qualifier (ASCQ) */
98#define ACK_NAK_TO 0x3
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100/* Default values for driver parameters */
101#define DEF_NUM_HOST 1
102#define DEF_NUM_TGTS 1
103#define DEF_MAX_LUNS 1
104/* With these defaults, this driver will make 1 host with 1 target
105 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
106 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500107#define DEF_ATO 1
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500108#define DEF_CDB_LEN 10
Douglas Gilbertc2206092016-04-25 12:16:31 -0400109#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500111#define DEF_DIF 0
112#define DEF_DIX 0
113#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500115#define DEF_FAKE_RW 0
116#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400117#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500118#define DEF_LBPU 0
119#define DEF_LBPWS 0
120#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600121#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500122#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400123#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500124#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125#define DEF_NUM_PARTS 0
126#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500127#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500128#define DEF_PHYSBLK_EXP 0
Lukas Herbolt86e68282017-01-26 10:00:37 +0100129#define DEF_OPT_XFERLEN_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400130#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200131#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400132#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500133#define DEF_SECTOR_SIZE 512
134#define DEF_UNMAP_ALIGNMENT 0
135#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400136#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
137#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500138#define DEF_VIRTUAL_GB 0
139#define DEF_VPD_USE_HOSTNO 1
140#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500141#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400142#define DEF_STATISTICS false
143#define DEF_SUBMIT_QUEUES 1
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400144#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400145#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400147#define SDEBUG_LUN_0_VAL 0
148
Douglas Gilbert773642d2016-04-25 12:16:28 -0400149/* bit mask values for sdebug_opts */
150#define SDEBUG_OPT_NOISE 1
151#define SDEBUG_OPT_MEDIUM_ERR 2
152#define SDEBUG_OPT_TIMEOUT 4
153#define SDEBUG_OPT_RECOVERED_ERR 8
154#define SDEBUG_OPT_TRANSPORT_ERR 16
155#define SDEBUG_OPT_DIF_ERR 32
156#define SDEBUG_OPT_DIX_ERR 64
157#define SDEBUG_OPT_MAC_TIMEOUT 128
158#define SDEBUG_OPT_SHORT_TRANSFER 0x100
159#define SDEBUG_OPT_Q_NOISE 0x200
160#define SDEBUG_OPT_ALL_TSF 0x400
161#define SDEBUG_OPT_RARE_TSF 0x800
162#define SDEBUG_OPT_N_WCE 0x1000
163#define SDEBUG_OPT_RESET_NOISE 0x2000
164#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800165#define SDEBUG_OPT_HOST_BUSY 0x8000
Douglas Gilbert773642d2016-04-25 12:16:28 -0400166#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
167 SDEBUG_OPT_RESET_NOISE)
168#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
169 SDEBUG_OPT_TRANSPORT_ERR | \
170 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800171 SDEBUG_OPT_SHORT_TRANSFER | \
172 SDEBUG_OPT_HOST_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400174 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400176 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500177 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400178 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 *
180 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400181 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400183 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500184 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400185 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
186 * This will continue on every subsequent command until some other action
187 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
188 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 */
190
Douglas Gilbertfd321192016-04-25 12:16:33 -0400191/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400192 * priority order. In the subset implemented here lower numbers have higher
193 * priority. The UA numbers should be a sequence starting from 0 with
194 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
195#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
196#define SDEBUG_UA_BUS_RESET 1
197#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500198#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500199#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500200#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
201#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
202#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400203
Douglas Gilbert773642d2016-04-25 12:16:28 -0400204/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 * sector on read commands: */
206#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500207#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
210 * or "peripheral device" addressing (value 0) */
211#define SAM2_LUN_ADDRESS_METHOD 0
212
Douglas Gilbertc4837392016-05-06 00:40:26 -0400213/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
214 * (for response) per submit queue at one time. Can be reduced by max_queue
215 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
216 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
217 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
218 * but cannot exceed SDEBUG_CANQUEUE .
219 */
220#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
221#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400222#define DEF_CMD_PER_LUN 255
223
Douglas Gilbertfd321192016-04-25 12:16:33 -0400224#define F_D_IN 1
225#define F_D_OUT 2
226#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
227#define F_D_UNKN 8
228#define F_RL_WLUN_OK 0x10
229#define F_SKIP_UA 0x20
230#define F_DELAY_OVERR 0x40
231#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
232#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
233#define F_INV_OP 0x200
234#define F_FAKE_RW 0x400
235#define F_M_ACCESS 0x800 /* media access */
236
237#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
238#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
239#define FF_SA (F_SA_HIGH | F_SA_LOW)
240
241#define SDEBUG_MAX_PARTS 4
242
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400243#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400244
245
246struct sdebug_dev_info {
247 struct list_head dev_list;
248 unsigned int channel;
249 unsigned int target;
250 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200251 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400252 struct sdebug_host_info *sdbg_host;
253 unsigned long uas_bm[1];
254 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400255 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400256 bool used;
257};
258
259struct sdebug_host_info {
260 struct list_head host_list;
261 struct Scsi_Host *shost;
262 struct device dev;
263 struct list_head dev_info_list;
264};
265
266#define to_sdebug_host(d) \
267 container_of(d, struct sdebug_host_info, dev)
268
269struct sdebug_defer {
270 struct hrtimer hrt;
271 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400272 int sqa_idx; /* index of sdebug_queue array */
273 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
274 int issuing_cpu;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400275};
276
277struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400278 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
279 * instance indicates this slot is in use.
280 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400281 struct sdebug_defer *sd_dp;
282 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400283 unsigned int inj_recovered:1;
284 unsigned int inj_transport:1;
285 unsigned int inj_dif:1;
286 unsigned int inj_dix:1;
287 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800288 unsigned int inj_host_busy:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400289};
290
Douglas Gilbertc4837392016-05-06 00:40:26 -0400291struct sdebug_queue {
292 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
293 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
294 spinlock_t qc_lock;
295 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400296};
297
Douglas Gilbertc4837392016-05-06 00:40:26 -0400298static atomic_t sdebug_cmnd_count; /* number of incoming commands */
299static atomic_t sdebug_completions; /* count of deferred completions */
300static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
301static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
302
Douglas Gilbertfd321192016-04-25 12:16:33 -0400303struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400304 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
305 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400306 u8 opcode; /* if num_attached > 0, preferred */
307 u16 sa; /* service action */
308 u32 flags; /* OR-ed set of SDEB_F_* */
309 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
310 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500311 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
312 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400313};
314
315/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500316enum sdeb_opcode_index {
317 SDEB_I_INVALID_OPCODE = 0,
318 SDEB_I_INQUIRY = 1,
319 SDEB_I_REPORT_LUNS = 2,
320 SDEB_I_REQUEST_SENSE = 3,
321 SDEB_I_TEST_UNIT_READY = 4,
322 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
323 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
324 SDEB_I_LOG_SENSE = 7,
325 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
326 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
327 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
328 SDEB_I_START_STOP = 11,
329 SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
330 SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
331 SDEB_I_MAINT_IN = 14,
332 SDEB_I_MAINT_OUT = 15,
333 SDEB_I_VERIFY = 16, /* 10 only */
334 SDEB_I_VARIABLE_LEN = 17,
335 SDEB_I_RESERVE = 18, /* 6, 10 */
336 SDEB_I_RELEASE = 19, /* 6, 10 */
337 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
338 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
339 SDEB_I_ATA_PT = 22, /* 12, 16 */
340 SDEB_I_SEND_DIAG = 23,
341 SDEB_I_UNMAP = 24,
342 SDEB_I_XDWRITEREAD = 25, /* 10 only */
343 SDEB_I_WRITE_BUFFER = 26,
344 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
345 SDEB_I_SYNC_CACHE = 28, /* 10 only */
346 SDEB_I_COMP_WRITE = 29,
Douglas Gilbert9a051012017-12-23 12:48:10 -0500347 SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500348};
349
Douglas Gilbertc4837392016-05-06 00:40:26 -0400350
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500351static const unsigned char opcode_ind_arr[256] = {
352/* 0x0; 0x0->0x1f: 6 byte cdbs */
353 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
354 0, 0, 0, 0,
355 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
356 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
357 SDEB_I_RELEASE,
358 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
359 SDEB_I_ALLOW_REMOVAL, 0,
360/* 0x20; 0x20->0x3f: 10 byte cdbs */
361 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
362 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
363 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
364 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
365/* 0x40; 0x40->0x5f: 10 byte cdbs */
366 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
368 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
369 SDEB_I_RELEASE,
370 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400371/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
374 0, SDEB_I_VARIABLE_LEN,
375/* 0x80; 0x80->0x9f: 16 byte cdbs */
376 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
377 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
378 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
379 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
380/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
381 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
382 SDEB_I_MAINT_OUT, 0, 0, 0,
383 SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
384 0, 0, 0, 0,
385 0, 0, 0, 0, 0, 0, 0, 0,
386 0, 0, 0, 0, 0, 0, 0, 0,
387/* 0xc0; 0xc0->0xff: vendor specific */
388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
392};
393
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500394static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
395static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
396static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
397static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
398static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
399static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
400static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
401static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
402static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
403static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
404static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
405static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
406static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
407static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500408static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
409static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500410static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
411static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
412static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500413static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500414static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500415
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500416static const struct opcode_info_t msense_iarr[1] = {
417 {0, 0x1a, 0, F_D_IN, NULL, NULL,
418 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
419};
420
421static const struct opcode_info_t mselect_iarr[1] = {
422 {0, 0x15, 0, F_D_OUT, NULL, NULL,
423 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
424};
425
426static const struct opcode_info_t read_iarr[3] = {
427 {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500428 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500429 0, 0, 0, 0} },
430 {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
431 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
432 {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500433 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500434 0xc7, 0, 0, 0, 0} },
435};
436
437static const struct opcode_info_t write_iarr[3] = {
438 {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500439 {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500440 0, 0, 0, 0} },
441 {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
442 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
443 {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500444 {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500445 0xc7, 0, 0, 0, 0} },
446};
447
448static const struct opcode_info_t sa_in_iarr[1] = {
449 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
450 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
451 0xff, 0xff, 0xff, 0, 0xc7} },
452};
453
454static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
455 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500456 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500457 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
458};
459
460static const struct opcode_info_t maint_in_iarr[2] = {
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500461 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500462 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
463 0xc7, 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500464 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500465 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
466 0, 0} },
467};
468
469static const struct opcode_info_t write_same_iarr[1] = {
470 {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
471 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500472 0xff, 0xff, 0xff, 0x3f, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500473};
474
475static const struct opcode_info_t reserve_iarr[1] = {
476 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
477 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
478};
479
480static const struct opcode_info_t release_iarr[1] = {
481 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
482 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
483};
484
485
486/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
487 * plus the terminating elements for logic that scans this table such as
488 * REPORT SUPPORTED OPERATION CODES. */
489static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
490/* 0 */
491 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
492 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
493 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
494 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
495 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
496 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
497 0, 0} },
498 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
499 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
500 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
501 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
502 {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
503 {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
504 0} },
505 {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
506 {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
507 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
508 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
509 0, 0, 0} },
510 {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
511 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
512 0, 0} },
513 {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
514 {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500515 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* READ(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500516/* 10 */
517 {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
518 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500519 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* WRITE(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500520 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
521 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
522 {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
523 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
524 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
525 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
526 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
527 {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
528 {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
529 0} },
530 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
531 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500532 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
533 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
534 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500535 {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500536 vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500537 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
538 {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
539 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
540 0} },
541 {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
542 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
543 0} },
544/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500545 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
546 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500547 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
548 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
549 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
550 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
551 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
552 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
553 {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500554 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500555 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500556 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500557 0, 0, 0, 0, 0, 0} },
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500558 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
559 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
560 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500561 {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500562 write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500563 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
564 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500565 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500566 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500567 {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500568 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500569 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500570
571/* 30 */
572 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
573 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
574};
575
Douglas Gilbert773642d2016-04-25 12:16:28 -0400576static int sdebug_add_host = DEF_NUM_HOST;
577static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500578static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400579static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400580static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
581static int sdebug_dif = DEF_DIF;
582static int sdebug_dix = DEF_DIX;
583static int sdebug_dsense = DEF_D_SENSE;
584static int sdebug_every_nth = DEF_EVERY_NTH;
585static int sdebug_fake_rw = DEF_FAKE_RW;
586static unsigned int sdebug_guard = DEF_GUARD;
587static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
588static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400589static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400590static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400591static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400592static int sdebug_no_lun_0 = DEF_NO_LUN_0;
593static int sdebug_no_uld;
594static int sdebug_num_parts = DEF_NUM_PARTS;
595static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
596static int sdebug_opt_blks = DEF_OPT_BLKS;
597static int sdebug_opts = DEF_OPTS;
598static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100599static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400600static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400601static int sdebug_scsi_level = DEF_SCSI_LEVEL;
602static int sdebug_sector_size = DEF_SECTOR_SIZE;
603static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
604static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
605static unsigned int sdebug_lbpu = DEF_LBPU;
606static unsigned int sdebug_lbpws = DEF_LBPWS;
607static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
608static unsigned int sdebug_lbprz = DEF_LBPRZ;
609static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
610static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
611static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
612static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
613static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400614static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400615static bool sdebug_removable = DEF_REMOVABLE;
616static bool sdebug_clustering;
617static bool sdebug_host_lock = DEF_HOST_LOCK;
618static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500619static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400620static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400621static bool have_dif_prot;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400622static bool sdebug_statistics = DEF_STATISTICS;
623static bool sdebug_mq_active;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400625static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626static sector_t sdebug_capacity; /* in sectors */
627
628/* old BIOS stuff, kernel may get rid of them but some mode sense pages
629 may still need them */
630static int sdebug_heads; /* heads per disk */
631static int sdebug_cylinders_per; /* cylinders per surface */
632static int sdebug_sectors_per; /* sectors per cylinder */
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634static LIST_HEAD(sdebug_host_list);
635static DEFINE_SPINLOCK(sdebug_host_list_lock);
636
Douglas Gilbertfd321192016-04-25 12:16:33 -0400637static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200638static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400639static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Martin K. Petersen44d92692009-10-15 14:45:27 -0400641static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400642static int num_aborts;
643static int num_dev_resets;
644static int num_target_resets;
645static int num_bus_resets;
646static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500647static int dix_writes;
648static int dix_reads;
649static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Douglas Gilbertc4837392016-05-06 00:40:26 -0400651static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
652static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654static DEFINE_RWLOCK(atomic_rw);
655
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400656static char sdebug_proc_name[] = MY_NAME;
657static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659static struct bus_type pseudo_lld_bus;
660
661static struct device_driver sdebug_driverfs_driver = {
662 .name = sdebug_proc_name,
663 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664};
665
666static const int check_condition_result =
667 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
668
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500669static const int illegal_condition_result =
670 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
671
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400672static const int device_qfull_result =
673 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
674
Douglas Gilbertfd321192016-04-25 12:16:33 -0400675
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400676/* Only do the extra work involved in logical block provisioning if one or
677 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
678 * real reads and writes (i.e. not skipping them for speed).
679 */
680static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400681{
682 return 0 == sdebug_fake_rw &&
683 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
684}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400685
Akinobu Mita14faa942013-09-18 21:27:24 +0900686static void *fake_store(unsigned long long lba)
687{
688 lba = do_div(lba, sdebug_store_sectors);
689
Douglas Gilbert773642d2016-04-25 12:16:28 -0400690 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900691}
692
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200693static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900694{
Arnd Bergmann49413112015-11-20 17:38:28 +0100695 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900696
697 return dif_storep + sector;
698}
699
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900700static void sdebug_max_tgts_luns(void)
701{
702 struct sdebug_host_info *sdbg_host;
703 struct Scsi_Host *hpnt;
704
705 spin_lock(&sdebug_host_list_lock);
706 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
707 hpnt = sdbg_host->shost;
708 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400709 (sdebug_num_tgts > hpnt->this_id))
710 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900711 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400712 hpnt->max_id = sdebug_num_tgts;
713 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300714 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900715 }
716 spin_unlock(&sdebug_host_list_lock);
717}
718
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500719enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
720
721/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400722static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
723 enum sdeb_cmd_data c_d,
724 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500725{
726 unsigned char *sbuff;
727 u8 sks[4];
728 int sl, asc;
729
730 sbuff = scp->sense_buffer;
731 if (!sbuff) {
732 sdev_printk(KERN_ERR, scp->device,
733 "%s: sense_buffer is NULL\n", __func__);
734 return;
735 }
736 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
737 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400738 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500739 memset(sks, 0, sizeof(sks));
740 sks[0] = 0x80;
741 if (c_d)
742 sks[0] |= 0x40;
743 if (in_bit >= 0) {
744 sks[0] |= 0x8;
745 sks[0] |= 0x7 & in_bit;
746 }
747 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400748 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500749 sl = sbuff[7] + 8;
750 sbuff[7] = sl;
751 sbuff[sl] = 0x2;
752 sbuff[sl + 1] = 0x6;
753 memcpy(sbuff + sl + 4, sks, 3);
754 } else
755 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400756 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500757 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
758 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
759 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
760}
761
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400762static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900763{
764 unsigned char *sbuff;
765
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400766 sbuff = scp->sense_buffer;
767 if (!sbuff) {
768 sdev_printk(KERN_ERR, scp->device,
769 "%s: sense_buffer is NULL\n", __func__);
770 return;
771 }
772 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900773
Douglas Gilbert773642d2016-04-25 12:16:28 -0400774 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900775
Douglas Gilbert773642d2016-04-25 12:16:28 -0400776 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400777 sdev_printk(KERN_INFO, scp->device,
778 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
779 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900780}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Douglas Gilbertfd321192016-04-25 12:16:33 -0400782static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500783{
784 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
785}
786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
788{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400789 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400790 if (0x1261 == cmd)
791 sdev_printk(KERN_INFO, dev,
792 "%s: BLKFLSBUF [0x1261]\n", __func__);
793 else if (0x5331 == cmd)
794 sdev_printk(KERN_INFO, dev,
795 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
796 __func__);
797 else
798 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
799 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 }
801 return -EINVAL;
802 /* return -ENOTTY; // correct return but upsets fdisk */
803}
804
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500805static void config_cdb_len(struct scsi_device *sdev)
806{
807 switch (sdebug_cdb_len) {
808 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
809 sdev->use_10_for_rw = false;
810 sdev->use_16_for_rw = false;
811 sdev->use_10_for_ms = false;
812 break;
813 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
814 sdev->use_10_for_rw = true;
815 sdev->use_16_for_rw = false;
816 sdev->use_10_for_ms = false;
817 break;
818 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
819 sdev->use_10_for_rw = true;
820 sdev->use_16_for_rw = false;
821 sdev->use_10_for_ms = true;
822 break;
823 case 16:
824 sdev->use_10_for_rw = false;
825 sdev->use_16_for_rw = true;
826 sdev->use_10_for_ms = true;
827 break;
828 case 32: /* No knobs to suggest this so same as 16 for now */
829 sdev->use_10_for_rw = false;
830 sdev->use_16_for_rw = true;
831 sdev->use_10_for_ms = true;
832 break;
833 default:
834 pr_warn("unexpected cdb_len=%d, force to 10\n",
835 sdebug_cdb_len);
836 sdev->use_10_for_rw = true;
837 sdev->use_16_for_rw = false;
838 sdev->use_10_for_ms = false;
839 sdebug_cdb_len = 10;
840 break;
841 }
842}
843
844static void all_config_cdb_len(void)
845{
846 struct sdebug_host_info *sdbg_host;
847 struct Scsi_Host *shost;
848 struct scsi_device *sdev;
849
850 spin_lock(&sdebug_host_list_lock);
851 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
852 shost = sdbg_host->shost;
853 shost_for_each_device(sdev, shost) {
854 config_cdb_len(sdev);
855 }
856 }
857 spin_unlock(&sdebug_host_list_lock);
858}
859
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500860static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
861{
862 struct sdebug_host_info *sdhp;
863 struct sdebug_dev_info *dp;
864
865 spin_lock(&sdebug_host_list_lock);
866 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
867 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
868 if ((devip->sdbg_host == dp->sdbg_host) &&
869 (devip->target == dp->target))
870 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
871 }
872 }
873 spin_unlock(&sdebug_host_list_lock);
874}
875
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400876static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400878 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400879
880 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
881 if (k != SDEBUG_NUM_UAS) {
882 const char *cp = NULL;
883
884 switch (k) {
885 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400886 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
887 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400888 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400889 cp = "power on reset";
890 break;
891 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400892 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
893 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400894 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400895 cp = "bus reset";
896 break;
897 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400898 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
899 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400900 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400901 cp = "mode parameters changed";
902 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500903 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400904 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
905 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400906 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500907 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500908 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500909 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400910 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400911 TARGET_CHANGED_ASC,
912 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400913 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500914 cp = "microcode has been changed";
915 break;
916 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400917 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500918 TARGET_CHANGED_ASC,
919 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400920 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500921 cp = "microcode has been changed without reset";
922 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500923 case SDEBUG_UA_LUNS_CHANGED:
924 /*
925 * SPC-3 behavior is to report a UNIT ATTENTION with
926 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
927 * on the target, until a REPORT LUNS command is
928 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400929 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500930 * values as struct scsi_device->scsi_level.
931 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400932 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500933 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400934 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500935 TARGET_CHANGED_ASC,
936 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400937 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500938 cp = "reported luns data has changed";
939 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400940 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400941 pr_warn("unexpected unit attention code=%d\n", k);
942 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400943 cp = "unknown";
944 break;
945 }
946 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400947 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400948 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400949 "%s reports: Unit attention: %s\n",
950 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 return check_condition_result;
952 }
953 return 0;
954}
955
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400956/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900957static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 int arr_len)
959{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900960 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900961 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900963 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900965 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400966 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900967
968 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
969 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700970 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900971
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 return 0;
973}
974
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -0400975/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
976 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
977 * calls, not required to write in ascending offset order. Assumes resid
978 * set to scsi_bufflen() prior to any calls.
979 */
980static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
981 int arr_len, unsigned int off_dst)
982{
983 int act_len, n;
984 struct scsi_data_buffer *sdb = scsi_in(scp);
985 off_t skip = off_dst;
986
987 if (sdb->length <= off_dst)
988 return 0;
989 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
990 return DID_ERROR << 16;
991
992 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
993 arr, arr_len, skip);
994 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
995 __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
996 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
997 sdb->resid = min(sdb->resid, n);
998 return 0;
999}
1000
1001/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1002 * 'arr' or -1 if error.
1003 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001004static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1005 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001007 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001009 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001011
1012 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013}
1014
1015
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001016static char sdebug_inq_vendor_id[9] = "Linux ";
1017static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001018static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001019/* Use some locally assigned NAAs for SAS addresses. */
1020static const u64 naa3_comp_a = 0x3222222000000000ULL;
1021static const u64 naa3_comp_b = 0x3333333000000000ULL;
1022static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001024/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001025static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1026 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001027 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001028 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001030 int num, port_a;
1031 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001033 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 /* T10 vendor identifier field format (faked) */
1035 arr[0] = 0x2; /* ASCII */
1036 arr[1] = 0x1;
1037 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001038 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1039 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1041 num = 8 + 16 + dev_id_str_len;
1042 arr[3] = num;
1043 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001044 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001045 if (sdebug_uuid_ctl) {
1046 /* Locally assigned UUID */
1047 arr[num++] = 0x1; /* binary (not necessarily sas) */
1048 arr[num++] = 0xa; /* PIV=0, lu, naa */
1049 arr[num++] = 0x0;
1050 arr[num++] = 0x12;
1051 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1052 arr[num++] = 0x0;
1053 memcpy(arr + num, lu_name, 16);
1054 num += 16;
1055 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001056 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001057 arr[num++] = 0x1; /* binary (not necessarily sas) */
1058 arr[num++] = 0x3; /* PIV=0, lu, naa */
1059 arr[num++] = 0x0;
1060 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001061 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001062 num += 8;
1063 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001064 /* Target relative port number */
1065 arr[num++] = 0x61; /* proto=sas, binary */
1066 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1067 arr[num++] = 0x0; /* reserved */
1068 arr[num++] = 0x4; /* length */
1069 arr[num++] = 0x0; /* reserved */
1070 arr[num++] = 0x0; /* reserved */
1071 arr[num++] = 0x0;
1072 arr[num++] = 0x1; /* relative port A */
1073 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001074 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001075 arr[num++] = 0x61; /* proto=sas, binary */
1076 arr[num++] = 0x93; /* piv=1, target port, naa */
1077 arr[num++] = 0x0;
1078 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001079 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001080 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001081 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001082 arr[num++] = 0x61; /* proto=sas, binary */
1083 arr[num++] = 0x95; /* piv=1, target port group id */
1084 arr[num++] = 0x0;
1085 arr[num++] = 0x4;
1086 arr[num++] = 0;
1087 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001088 put_unaligned_be16(port_group_id, arr + num);
1089 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001090 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091 arr[num++] = 0x61; /* proto=sas, binary */
1092 arr[num++] = 0xa3; /* piv=1, target device, naa */
1093 arr[num++] = 0x0;
1094 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001095 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001096 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001097 /* SCSI name string: Target device identifier */
1098 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1099 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1100 arr[num++] = 0x0;
1101 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001102 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001103 num += 12;
1104 snprintf(b, sizeof(b), "%08X", target_dev_id);
1105 memcpy(arr + num, b, 8);
1106 num += 8;
1107 memset(arr + num, 0, 4);
1108 num += 4;
1109 return num;
1110}
1111
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001112static unsigned char vpd84_data[] = {
1113/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1114 0x22,0x22,0x22,0x0,0xbb,0x1,
1115 0x22,0x22,0x22,0x0,0xbb,0x2,
1116};
1117
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001118/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001119static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001120{
1121 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1122 return sizeof(vpd84_data);
1123}
1124
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001125/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001126static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001127{
1128 int num = 0;
1129 const char * na1 = "https://www.kernel.org/config";
1130 const char * na2 = "http://www.kernel.org/log";
1131 int plen, olen;
1132
1133 arr[num++] = 0x1; /* lu, storage config */
1134 arr[num++] = 0x0; /* reserved */
1135 arr[num++] = 0x0;
1136 olen = strlen(na1);
1137 plen = olen + 1;
1138 if (plen % 4)
1139 plen = ((plen / 4) + 1) * 4;
1140 arr[num++] = plen; /* length, null termianted, padded */
1141 memcpy(arr + num, na1, olen);
1142 memset(arr + num + olen, 0, plen - olen);
1143 num += plen;
1144
1145 arr[num++] = 0x4; /* lu, logging */
1146 arr[num++] = 0x0; /* reserved */
1147 arr[num++] = 0x0;
1148 olen = strlen(na2);
1149 plen = olen + 1;
1150 if (plen % 4)
1151 plen = ((plen / 4) + 1) * 4;
1152 arr[num++] = plen; /* length, null terminated, padded */
1153 memcpy(arr + num, na2, olen);
1154 memset(arr + num + olen, 0, plen - olen);
1155 num += plen;
1156
1157 return num;
1158}
1159
1160/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001161static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001162{
1163 int num = 0;
1164 int port_a, port_b;
1165
1166 port_a = target_dev_id + 1;
1167 port_b = port_a + 1;
1168 arr[num++] = 0x0; /* reserved */
1169 arr[num++] = 0x0; /* reserved */
1170 arr[num++] = 0x0;
1171 arr[num++] = 0x1; /* relative port 1 (primary) */
1172 memset(arr + num, 0, 6);
1173 num += 6;
1174 arr[num++] = 0x0;
1175 arr[num++] = 12; /* length tp descriptor */
1176 /* naa-5 target port identifier (A) */
1177 arr[num++] = 0x61; /* proto=sas, binary */
1178 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1179 arr[num++] = 0x0; /* reserved */
1180 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001181 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001182 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001183 arr[num++] = 0x0; /* reserved */
1184 arr[num++] = 0x0; /* reserved */
1185 arr[num++] = 0x0;
1186 arr[num++] = 0x2; /* relative port 2 (secondary) */
1187 memset(arr + num, 0, 6);
1188 num += 6;
1189 arr[num++] = 0x0;
1190 arr[num++] = 12; /* length tp descriptor */
1191 /* naa-5 target port identifier (B) */
1192 arr[num++] = 0x61; /* proto=sas, binary */
1193 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1194 arr[num++] = 0x0; /* reserved */
1195 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001196 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001197 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001198
1199 return num;
1200}
1201
1202
1203static unsigned char vpd89_data[] = {
1204/* from 4th byte */ 0,0,0,0,
1205'l','i','n','u','x',' ',' ',' ',
1206'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1207'1','2','3','4',
12080x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12090xec,0,0,0,
12100x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12110,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12120x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12130x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12140x53,0x41,
12150x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12160x20,0x20,
12170x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12180x10,0x80,
12190,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12200x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12210x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12220,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12230x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12240x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12250,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12290x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12300,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12310xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12320,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
12330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12370,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12380,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12420,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12440,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1245};
1246
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001247/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001248static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001249{
1250 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1251 return sizeof(vpd89_data);
1252}
1253
1254
1255static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001256 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1257 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1258 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1259 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001260};
1261
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001262/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001263static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001264{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001265 unsigned int gran;
1266
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001267 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001268
1269 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001270 if (sdebug_opt_xferlen_exp != 0 &&
1271 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1272 gran = 1 << sdebug_opt_xferlen_exp;
1273 else
1274 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001275 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001276
1277 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001278 if (sdebug_store_sectors > 0x400)
1279 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001280
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001281 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001282 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001283
Douglas Gilbert773642d2016-04-25 12:16:28 -04001284 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001285 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001286 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001287
1288 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001289 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001290 }
1291
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001292 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001293 if (sdebug_unmap_alignment) {
1294 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001295 arr[28] |= 0x80; /* UGAVALID */
1296 }
1297
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001298 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001299 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001300
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001301 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001302 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001303
1304 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001305
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001306 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307}
1308
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001309/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001310static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001311{
1312 memset(arr, 0, 0x3c);
1313 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001314 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1315 arr[2] = 0;
1316 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001317
1318 return 0x3c;
1319}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001321/* Logical block provisioning VPD page (SBC-4) */
1322static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001323{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001324 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001325 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001326 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001327 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001328 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001329 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001330 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001331 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001332 if (sdebug_lbprz && scsi_debug_lbp())
1333 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1334 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1335 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1336 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001337 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001338}
1339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001341#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001343static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
1345 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001346 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001347 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001348 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001349 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Douglas Gilbert773642d2016-04-25 12:16:28 -04001351 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001352 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1353 if (! arr)
1354 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001355 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001356 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001357 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001358 pq_pdt = TYPE_WLUN; /* present, wlun */
1359 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1360 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001361 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001362 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 arr[0] = pq_pdt;
1364 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001365 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001366 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 return check_condition_result;
1368 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001369 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001370 char lu_id_str[6];
1371 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001373 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1374 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001375 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001376 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001377 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001378 (devip->target * 1000) + devip->lun);
1379 target_dev_id = ((host_no + 1) * 2000) +
1380 (devip->target * 1000) - 3;
1381 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001383 arr[1] = cmd[2]; /*sanity */
1384 n = 4;
1385 arr[n++] = 0x0; /* this page */
1386 arr[n++] = 0x80; /* unit serial number */
1387 arr[n++] = 0x83; /* device identification */
1388 arr[n++] = 0x84; /* software interface ident. */
1389 arr[n++] = 0x85; /* management network addresses */
1390 arr[n++] = 0x86; /* extended inquiry */
1391 arr[n++] = 0x87; /* mode page policy */
1392 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001393 if (is_disk) { /* SBC only */
1394 arr[n++] = 0x89; /* ATA information */
1395 arr[n++] = 0xb0; /* Block limits */
1396 arr[n++] = 0xb1; /* Block characteristics */
1397 arr[n++] = 0xb2; /* Logical Block Prov */
1398 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001399 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001401 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001403 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001405 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001406 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1407 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001408 lu_id_str, len,
1409 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001410 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1411 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001412 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001413 } else if (0x85 == cmd[2]) { /* Management network addresses */
1414 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001415 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001416 } else if (0x86 == cmd[2]) { /* extended inquiry */
1417 arr[1] = cmd[2]; /*sanity */
1418 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001419 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001420 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001421 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001422 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1423 else
1424 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001425 arr[5] = 0x7; /* head of q, ordered + simple q's */
1426 } else if (0x87 == cmd[2]) { /* mode page policy */
1427 arr[1] = cmd[2]; /*sanity */
1428 arr[3] = 0x8; /* number of following entries */
1429 arr[4] = 0x2; /* disconnect-reconnect mp */
1430 arr[6] = 0x80; /* mlus, shared */
1431 arr[8] = 0x18; /* protocol specific lu */
1432 arr[10] = 0x82; /* mlus, per initiator port */
1433 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1434 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001435 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1436 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001437 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001438 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001439 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001440 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001441 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001442 arr[3] = inquiry_vpd_b0(&arr[4]);
1443 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001444 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001445 arr[3] = inquiry_vpd_b1(&arr[4]);
1446 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001447 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001448 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001450 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001451 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 return check_condition_result;
1453 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001454 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001455 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001456 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001457 kfree(arr);
1458 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 }
1460 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001461 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1462 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 arr[3] = 2; /* response_data_format==2 */
1464 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001465 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001466 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001467 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001468 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001470 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001471 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1472 memcpy(&arr[16], sdebug_inq_product_id, 16);
1473 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001474 /* Use Vendor Specific area to place driver date in ASCII hex */
1475 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001477 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1478 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001479 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001480 if (is_disk) { /* SBC-4 no version claimed */
1481 put_unaligned_be16(0x600, arr + n);
1482 n += 2;
1483 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1484 put_unaligned_be16(0x525, arr + n);
1485 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001487 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001488 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001490 kfree(arr);
1491 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492}
1493
Douglas Gilbertfd321192016-04-25 12:16:33 -04001494static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1495 0, 0, 0x0, 0x0};
1496
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497static int resp_requests(struct scsi_cmnd * scp,
1498 struct sdebug_dev_info * devip)
1499{
1500 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001501 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001502 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001503 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 int len = 18;
1505
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001506 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001507 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001508 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001509 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001510 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001511 arr[0] = 0x72;
1512 arr[1] = 0x0; /* NO_SENSE in sense_key */
1513 arr[2] = THRESHOLD_EXCEEDED;
1514 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001515 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001516 } else {
1517 arr[0] = 0x70;
1518 arr[2] = 0x0; /* NO_SENSE in sense_key */
1519 arr[7] = 0xa; /* 18 byte sense buffer */
1520 arr[12] = THRESHOLD_EXCEEDED;
1521 arr[13] = 0xff; /* TEST set and MRIE==6 */
1522 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001523 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001524 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001525 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001526 ; /* have sense and formats match */
1527 else if (arr[0] <= 0x70) {
1528 if (dsense) {
1529 memset(arr, 0, 8);
1530 arr[0] = 0x72;
1531 len = 8;
1532 } else {
1533 memset(arr, 0, 18);
1534 arr[0] = 0x70;
1535 arr[7] = 0xa;
1536 }
1537 } else if (dsense) {
1538 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001539 arr[0] = 0x72;
1540 arr[1] = sbuff[2]; /* sense key */
1541 arr[2] = sbuff[12]; /* asc */
1542 arr[3] = sbuff[13]; /* ascq */
1543 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001544 } else {
1545 memset(arr, 0, 18);
1546 arr[0] = 0x70;
1547 arr[2] = sbuff[1];
1548 arr[7] = 0xa;
1549 arr[12] = sbuff[1];
1550 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001551 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001552
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001553 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001554 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 return fill_from_dev_buffer(scp, arr, len);
1556}
1557
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001558static int resp_start_stop(struct scsi_cmnd * scp,
1559 struct sdebug_dev_info * devip)
1560{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001561 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001562 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001563
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001564 power_cond = (cmd[4] & 0xf0) >> 4;
1565 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001566 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001567 return check_condition_result;
1568 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001569 stop = !(cmd[4] & 1);
1570 atomic_xchg(&devip->stopped, stop);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001571 return 0;
1572}
1573
FUJITA Tomonori28898872008-03-30 00:59:55 +09001574static sector_t get_sdebug_capacity(void)
1575{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001576 static const unsigned int gibibyte = 1073741824;
1577
1578 if (sdebug_virtual_gb > 0)
1579 return (sector_t)sdebug_virtual_gb *
1580 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001581 else
1582 return sdebug_store_sectors;
1583}
1584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585#define SDEBUG_READCAP_ARR_SZ 8
1586static int resp_readcap(struct scsi_cmnd * scp,
1587 struct sdebug_dev_info * devip)
1588{
1589 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001590 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001592 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001593 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001595 if (sdebug_capacity < 0xffffffff) {
1596 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001597 put_unaligned_be32(capac, arr + 0);
1598 } else
1599 put_unaligned_be32(0xffffffff, arr + 0);
1600 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1602}
1603
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001604#define SDEBUG_READCAP16_ARR_SZ 32
1605static int resp_readcap16(struct scsi_cmnd * scp,
1606 struct sdebug_dev_info * devip)
1607{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001608 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001609 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001610 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001611
Douglas Gilbert773642d2016-04-25 12:16:28 -04001612 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001613 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001614 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001615 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001616 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1617 put_unaligned_be32(sdebug_sector_size, arr + 8);
1618 arr[13] = sdebug_physblk_exp & 0xf;
1619 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001620
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001621 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001622 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001623 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1624 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1625 * in the wider field maps to 0 in this field.
1626 */
1627 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1628 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001629 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001630
Douglas Gilbert773642d2016-04-25 12:16:28 -04001631 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001632
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001633 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001634 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001635 arr[12] |= 1; /* PROT_EN */
1636 }
1637
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001638 return fill_from_dev_buffer(scp, arr,
1639 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1640}
1641
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001642#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1643
1644static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1645 struct sdebug_dev_info * devip)
1646{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001647 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001648 unsigned char * arr;
1649 int host_no = devip->sdbg_host->shost->host_no;
1650 int n, ret, alen, rlen;
1651 int port_group_a, port_group_b, port_a, port_b;
1652
Douglas Gilbert773642d2016-04-25 12:16:28 -04001653 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001654 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1655 if (! arr)
1656 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001657 /*
1658 * EVPD page 0x88 states we have two ports, one
1659 * real and a fake port with no device connected.
1660 * So we create two port groups with one port each
1661 * and set the group with port B to unavailable.
1662 */
1663 port_a = 0x1; /* relative port A */
1664 port_b = 0x2; /* relative port B */
1665 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001666 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001667 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001668 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001669
1670 /*
1671 * The asymmetric access state is cycled according to the host_id.
1672 */
1673 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001674 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001675 arr[n++] = host_no % 3; /* Asymm access state */
1676 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001677 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001678 arr[n++] = 0x0; /* Active/Optimized path */
1679 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001680 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001681 put_unaligned_be16(port_group_a, arr + n);
1682 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001683 arr[n++] = 0; /* Reserved */
1684 arr[n++] = 0; /* Status code */
1685 arr[n++] = 0; /* Vendor unique */
1686 arr[n++] = 0x1; /* One port per group */
1687 arr[n++] = 0; /* Reserved */
1688 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001689 put_unaligned_be16(port_a, arr + n);
1690 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001691 arr[n++] = 3; /* Port unavailable */
1692 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001693 put_unaligned_be16(port_group_b, arr + n);
1694 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001695 arr[n++] = 0; /* Reserved */
1696 arr[n++] = 0; /* Status code */
1697 arr[n++] = 0; /* Vendor unique */
1698 arr[n++] = 0x1; /* One port per group */
1699 arr[n++] = 0; /* Reserved */
1700 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001701 put_unaligned_be16(port_b, arr + n);
1702 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001703
1704 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001705 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001706
1707 /*
1708 * Return the smallest value of either
1709 * - The allocated length
1710 * - The constructed command length
1711 * - The maximum array size
1712 */
1713 rlen = min(alen,n);
1714 ret = fill_from_dev_buffer(scp, arr,
1715 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1716 kfree(arr);
1717 return ret;
1718}
1719
Douglas Gilbertfd321192016-04-25 12:16:33 -04001720static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1721 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001722{
1723 bool rctd;
1724 u8 reporting_opts, req_opcode, sdeb_i, supp;
1725 u16 req_sa, u;
1726 u32 alloc_len, a_len;
1727 int k, offset, len, errsts, count, bump, na;
1728 const struct opcode_info_t *oip;
1729 const struct opcode_info_t *r_oip;
1730 u8 *arr;
1731 u8 *cmd = scp->cmnd;
1732
1733 rctd = !!(cmd[2] & 0x80);
1734 reporting_opts = cmd[2] & 0x7;
1735 req_opcode = cmd[3];
1736 req_sa = get_unaligned_be16(cmd + 4);
1737 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001738 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001739 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1740 return check_condition_result;
1741 }
1742 if (alloc_len > 8192)
1743 a_len = 8192;
1744 else
1745 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001746 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001747 if (NULL == arr) {
1748 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1749 INSUFF_RES_ASCQ);
1750 return check_condition_result;
1751 }
1752 switch (reporting_opts) {
1753 case 0: /* all commands */
1754 /* count number of commands */
1755 for (count = 0, oip = opcode_info_arr;
1756 oip->num_attached != 0xff; ++oip) {
1757 if (F_INV_OP & oip->flags)
1758 continue;
1759 count += (oip->num_attached + 1);
1760 }
1761 bump = rctd ? 20 : 8;
1762 put_unaligned_be32(count * bump, arr);
1763 for (offset = 4, oip = opcode_info_arr;
1764 oip->num_attached != 0xff && offset < a_len; ++oip) {
1765 if (F_INV_OP & oip->flags)
1766 continue;
1767 na = oip->num_attached;
1768 arr[offset] = oip->opcode;
1769 put_unaligned_be16(oip->sa, arr + offset + 2);
1770 if (rctd)
1771 arr[offset + 5] |= 0x2;
1772 if (FF_SA & oip->flags)
1773 arr[offset + 5] |= 0x1;
1774 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1775 if (rctd)
1776 put_unaligned_be16(0xa, arr + offset + 8);
1777 r_oip = oip;
1778 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1779 if (F_INV_OP & oip->flags)
1780 continue;
1781 offset += bump;
1782 arr[offset] = oip->opcode;
1783 put_unaligned_be16(oip->sa, arr + offset + 2);
1784 if (rctd)
1785 arr[offset + 5] |= 0x2;
1786 if (FF_SA & oip->flags)
1787 arr[offset + 5] |= 0x1;
1788 put_unaligned_be16(oip->len_mask[0],
1789 arr + offset + 6);
1790 if (rctd)
1791 put_unaligned_be16(0xa,
1792 arr + offset + 8);
1793 }
1794 oip = r_oip;
1795 offset += bump;
1796 }
1797 break;
1798 case 1: /* one command: opcode only */
1799 case 2: /* one command: opcode plus service action */
1800 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1801 sdeb_i = opcode_ind_arr[req_opcode];
1802 oip = &opcode_info_arr[sdeb_i];
1803 if (F_INV_OP & oip->flags) {
1804 supp = 1;
1805 offset = 4;
1806 } else {
1807 if (1 == reporting_opts) {
1808 if (FF_SA & oip->flags) {
1809 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1810 2, 2);
1811 kfree(arr);
1812 return check_condition_result;
1813 }
1814 req_sa = 0;
1815 } else if (2 == reporting_opts &&
1816 0 == (FF_SA & oip->flags)) {
1817 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1818 kfree(arr); /* point at requested sa */
1819 return check_condition_result;
1820 }
1821 if (0 == (FF_SA & oip->flags) &&
1822 req_opcode == oip->opcode)
1823 supp = 3;
1824 else if (0 == (FF_SA & oip->flags)) {
1825 na = oip->num_attached;
1826 for (k = 0, oip = oip->arrp; k < na;
1827 ++k, ++oip) {
1828 if (req_opcode == oip->opcode)
1829 break;
1830 }
1831 supp = (k >= na) ? 1 : 3;
1832 } else if (req_sa != oip->sa) {
1833 na = oip->num_attached;
1834 for (k = 0, oip = oip->arrp; k < na;
1835 ++k, ++oip) {
1836 if (req_sa == oip->sa)
1837 break;
1838 }
1839 supp = (k >= na) ? 1 : 3;
1840 } else
1841 supp = 3;
1842 if (3 == supp) {
1843 u = oip->len_mask[0];
1844 put_unaligned_be16(u, arr + 2);
1845 arr[4] = oip->opcode;
1846 for (k = 1; k < u; ++k)
1847 arr[4 + k] = (k < 16) ?
1848 oip->len_mask[k] : 0xff;
1849 offset = 4 + u;
1850 } else
1851 offset = 4;
1852 }
1853 arr[1] = (rctd ? 0x80 : 0) | supp;
1854 if (rctd) {
1855 put_unaligned_be16(0xa, arr + offset);
1856 offset += 12;
1857 }
1858 break;
1859 default:
1860 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1861 kfree(arr);
1862 return check_condition_result;
1863 }
1864 offset = (offset < a_len) ? offset : a_len;
1865 len = (offset < alloc_len) ? offset : alloc_len;
1866 errsts = fill_from_dev_buffer(scp, arr, len);
1867 kfree(arr);
1868 return errsts;
1869}
1870
Douglas Gilbertfd321192016-04-25 12:16:33 -04001871static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1872 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001873{
1874 bool repd;
1875 u32 alloc_len, len;
1876 u8 arr[16];
1877 u8 *cmd = scp->cmnd;
1878
1879 memset(arr, 0, sizeof(arr));
1880 repd = !!(cmd[2] & 0x80);
1881 alloc_len = get_unaligned_be32(cmd + 6);
1882 if (alloc_len < 4) {
1883 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1884 return check_condition_result;
1885 }
1886 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1887 arr[1] = 0x1; /* ITNRS */
1888 if (repd) {
1889 arr[3] = 0xc;
1890 len = 16;
1891 } else
1892 len = 4;
1893
1894 len = (len < alloc_len) ? len : alloc_len;
1895 return fill_from_dev_buffer(scp, arr, len);
1896}
1897
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898/* <<Following mode page info copied from ST318451LW>> */
1899
1900static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1901{ /* Read-Write Error Recovery page for mode_sense */
1902 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1903 5, 0, 0xff, 0xff};
1904
1905 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1906 if (1 == pcontrol)
1907 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1908 return sizeof(err_recov_pg);
1909}
1910
1911static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1912{ /* Disconnect-Reconnect page for mode_sense */
1913 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1914 0, 0, 0, 0, 0, 0, 0, 0};
1915
1916 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1917 if (1 == pcontrol)
1918 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1919 return sizeof(disconnect_pg);
1920}
1921
1922static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1923{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001924 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1925 0, 0, 0, 0, 0, 0, 0, 0,
1926 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927
Martin K. Petersen597136a2008-06-05 00:12:59 -04001928 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001929 put_unaligned_be16(sdebug_sectors_per, p + 10);
1930 put_unaligned_be16(sdebug_sector_size, p + 12);
1931 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001932 p[20] |= 0x20; /* should agree with INQUIRY */
1933 if (1 == pcontrol)
1934 memset(p + 2, 0, sizeof(format_pg) - 2);
1935 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936}
1937
Douglas Gilbertfd321192016-04-25 12:16:33 -04001938static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1939 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1940 0, 0, 0, 0};
1941
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1943{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001944 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1945 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1946 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1948
Douglas Gilbert773642d2016-04-25 12:16:28 -04001949 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001950 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 memcpy(p, caching_pg, sizeof(caching_pg));
1952 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001953 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1954 else if (2 == pcontrol)
1955 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 return sizeof(caching_pg);
1957}
1958
Douglas Gilbertfd321192016-04-25 12:16:33 -04001959static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1960 0, 0, 0x2, 0x4b};
1961
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1963{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001964 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05001965 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001966 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 0, 0, 0x2, 0x4b};
1968
Douglas Gilbert773642d2016-04-25 12:16:28 -04001969 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001971 else
1972 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001973
Douglas Gilbert773642d2016-04-25 12:16:28 -04001974 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001975 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1976
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1978 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001979 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1980 else if (2 == pcontrol)
1981 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 return sizeof(ctrl_m_pg);
1983}
1984
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001985
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1987{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001988 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1989 0, 0, 0x0, 0x0};
1990 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1991 0, 0, 0x0, 0x0};
1992
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1994 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001995 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1996 else if (2 == pcontrol)
1997 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 return sizeof(iec_m_pg);
1999}
2000
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002001static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
2002{ /* SAS SSP mode page - short format for mode_sense */
2003 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2004 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2005
2006 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2007 if (1 == pcontrol)
2008 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2009 return sizeof(sas_sf_m_pg);
2010}
2011
2012
2013static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
2014 int target_dev_id)
2015{ /* SAS phy control and discover mode page for mode_sense */
2016 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2017 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002018 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2019 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002020 0x2, 0, 0, 0, 0, 0, 0, 0,
2021 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2022 0, 0, 0, 0, 0, 0, 0, 0,
2023 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002024 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2025 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002026 0x3, 0, 0, 0, 0, 0, 0, 0,
2027 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2028 0, 0, 0, 0, 0, 0, 0, 0,
2029 };
2030 int port_a, port_b;
2031
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002032 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2033 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2034 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2035 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002036 port_a = target_dev_id + 1;
2037 port_b = port_a + 1;
2038 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002039 put_unaligned_be32(port_a, p + 20);
2040 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002041 if (1 == pcontrol)
2042 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2043 return sizeof(sas_pcd_m_pg);
2044}
2045
2046static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
2047{ /* SAS SSP shared protocol specific port mode subpage */
2048 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2049 0, 0, 0, 0, 0, 0, 0, 0,
2050 };
2051
2052 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2053 if (1 == pcontrol)
2054 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2055 return sizeof(sas_sha_m_pg);
2056}
2057
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058#define SDEBUG_MAX_MSENSE_SZ 256
2059
Douglas Gilbertfd321192016-04-25 12:16:33 -04002060static int resp_mode_sense(struct scsi_cmnd *scp,
2061 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062{
Douglas Gilbert23183912006-09-16 20:30:47 -04002063 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002065 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002066 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 unsigned char * ap;
2068 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002069 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002070 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002072 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 pcontrol = (cmd[2] & 0xc0) >> 6;
2074 pcode = cmd[2] & 0x3f;
2075 subpcode = cmd[3];
2076 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002077 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2078 is_disk = (sdebug_ptype == TYPE_DISK);
2079 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002080 bd_len = llbaa ? 16 : 8;
2081 else
2082 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002083 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2085 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002086 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 return check_condition_result;
2088 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002089 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2090 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002091 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002092 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002093 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002094 else
2095 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 if (msense_6) {
2097 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002098 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 offset = 4;
2100 } else {
2101 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002102 if (16 == bd_len)
2103 arr[4] = 0x1; /* set LONGLBA bit */
2104 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 offset = 8;
2106 }
2107 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002108 if ((bd_len > 0) && (!sdebug_capacity))
2109 sdebug_capacity = get_sdebug_capacity();
2110
Douglas Gilbert23183912006-09-16 20:30:47 -04002111 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002112 if (sdebug_capacity > 0xfffffffe)
2113 put_unaligned_be32(0xffffffff, ap + 0);
2114 else
2115 put_unaligned_be32(sdebug_capacity, ap + 0);
2116 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002117 offset += bd_len;
2118 ap = arr + offset;
2119 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002120 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2121 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002122 offset += bd_len;
2123 ap = arr + offset;
2124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002126 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2127 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002128 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 return check_condition_result;
2130 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002131 bad_pcode = false;
2132
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 switch (pcode) {
2134 case 0x1: /* Read-Write error recovery page, direct access */
2135 len = resp_err_recov_pg(ap, pcontrol, target);
2136 offset += len;
2137 break;
2138 case 0x2: /* Disconnect-Reconnect page, all devices */
2139 len = resp_disconnect_pg(ap, pcontrol, target);
2140 offset += len;
2141 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002142 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002143 if (is_disk) {
2144 len = resp_format_pg(ap, pcontrol, target);
2145 offset += len;
2146 } else
2147 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002148 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002150 if (is_disk) {
2151 len = resp_caching_pg(ap, pcontrol, target);
2152 offset += len;
2153 } else
2154 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 break;
2156 case 0xa: /* Control Mode page, all devices */
2157 len = resp_ctrl_m_pg(ap, pcontrol, target);
2158 offset += len;
2159 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002160 case 0x19: /* if spc==1 then sas phy, control+discover */
2161 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002162 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002163 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002164 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002165 len = 0;
2166 if ((0x0 == subpcode) || (0xff == subpcode))
2167 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2168 if ((0x1 == subpcode) || (0xff == subpcode))
2169 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2170 target_dev_id);
2171 if ((0x2 == subpcode) || (0xff == subpcode))
2172 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2173 offset += len;
2174 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 case 0x1c: /* Informational Exceptions Mode page, all devices */
2176 len = resp_iec_m_pg(ap, pcontrol, target);
2177 offset += len;
2178 break;
2179 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002180 if ((0 == subpcode) || (0xff == subpcode)) {
2181 len = resp_err_recov_pg(ap, pcontrol, target);
2182 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002183 if (is_disk) {
2184 len += resp_format_pg(ap + len, pcontrol,
2185 target);
2186 len += resp_caching_pg(ap + len, pcontrol,
2187 target);
2188 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002189 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2190 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2191 if (0xff == subpcode) {
2192 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2193 target, target_dev_id);
2194 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2195 }
2196 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002197 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002198 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002199 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002200 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 break;
2203 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002204 bad_pcode = true;
2205 break;
2206 }
2207 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002208 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 return check_condition_result;
2210 }
2211 if (msense_6)
2212 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002213 else
2214 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2216}
2217
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002218#define SDEBUG_MAX_MSELECT_SZ 512
2219
Douglas Gilbertfd321192016-04-25 12:16:33 -04002220static int resp_mode_select(struct scsi_cmnd *scp,
2221 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002222{
2223 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002224 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002225 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002226 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002227 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002228
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002229 memset(arr, 0, sizeof(arr));
2230 pf = cmd[1] & 0x10;
2231 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002232 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002233 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002234 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002235 return check_condition_result;
2236 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002237 res = fetch_to_dev_buffer(scp, arr, param_len);
2238 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002239 return DID_ERROR << 16;
2240 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002241 sdev_printk(KERN_INFO, scp->device,
2242 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2243 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002244 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2245 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002246 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002247 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002248 return check_condition_result;
2249 }
2250 off = bd_len + (mselect6 ? 4 : 8);
2251 mpage = arr[off] & 0x3f;
2252 ps = !!(arr[off] & 0x80);
2253 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002254 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002255 return check_condition_result;
2256 }
2257 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002258 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002259 (arr[off + 1] + 2);
2260 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002261 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 PARAMETER_LIST_LENGTH_ERR, 0);
2263 return check_condition_result;
2264 }
2265 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002266 case 0x8: /* Caching Mode page */
2267 if (caching_pg[1] == arr[off + 1]) {
2268 memcpy(caching_pg + 2, arr + off + 2,
2269 sizeof(caching_pg) - 2);
2270 goto set_mode_changed_ua;
2271 }
2272 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002273 case 0xa: /* Control Mode page */
2274 if (ctrl_m_pg[1] == arr[off + 1]) {
2275 memcpy(ctrl_m_pg + 2, arr + off + 2,
2276 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002277 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002278 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002279 }
2280 break;
2281 case 0x1c: /* Informational Exceptions Mode page */
2282 if (iec_m_pg[1] == arr[off + 1]) {
2283 memcpy(iec_m_pg + 2, arr + off + 2,
2284 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002285 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002286 }
2287 break;
2288 default:
2289 break;
2290 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002291 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002292 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002293set_mode_changed_ua:
2294 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2295 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002296}
2297
2298static int resp_temp_l_pg(unsigned char * arr)
2299{
2300 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2301 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2302 };
2303
Douglas Gilbert9a051012017-12-23 12:48:10 -05002304 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2305 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002306}
2307
2308static int resp_ie_l_pg(unsigned char * arr)
2309{
2310 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2311 };
2312
Douglas Gilbert9a051012017-12-23 12:48:10 -05002313 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002314 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2315 arr[4] = THRESHOLD_EXCEEDED;
2316 arr[5] = 0xff;
2317 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002318 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002319}
2320
2321#define SDEBUG_MAX_LSENSE_SZ 512
2322
Douglas Gilbert9a051012017-12-23 12:48:10 -05002323static int resp_log_sense(struct scsi_cmnd *scp,
2324 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002325{
Bart Van Asscheab172412017-08-25 13:46:42 -07002326 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002327 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002328 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002329
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002330 memset(arr, 0, sizeof(arr));
2331 ppc = cmd[1] & 0x2;
2332 sp = cmd[1] & 0x1;
2333 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002334 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002335 return check_condition_result;
2336 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002337 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002338 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002339 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002340 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002341 if (0 == subpcode) {
2342 switch (pcode) {
2343 case 0x0: /* Supported log pages log page */
2344 n = 4;
2345 arr[n++] = 0x0; /* this page */
2346 arr[n++] = 0xd; /* Temperature */
2347 arr[n++] = 0x2f; /* Informational exceptions */
2348 arr[3] = n - 4;
2349 break;
2350 case 0xd: /* Temperature log page */
2351 arr[3] = resp_temp_l_pg(arr + 4);
2352 break;
2353 case 0x2f: /* Informational exceptions log page */
2354 arr[3] = resp_ie_l_pg(arr + 4);
2355 break;
2356 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002357 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002358 return check_condition_result;
2359 }
2360 } else if (0xff == subpcode) {
2361 arr[0] |= 0x40;
2362 arr[1] = subpcode;
2363 switch (pcode) {
2364 case 0x0: /* Supported log pages and subpages log page */
2365 n = 4;
2366 arr[n++] = 0x0;
2367 arr[n++] = 0x0; /* 0,0 page */
2368 arr[n++] = 0x0;
2369 arr[n++] = 0xff; /* this page */
2370 arr[n++] = 0xd;
2371 arr[n++] = 0x0; /* Temperature */
2372 arr[n++] = 0x2f;
2373 arr[n++] = 0x0; /* Informational exceptions */
2374 arr[3] = n - 4;
2375 break;
2376 case 0xd: /* Temperature subpages */
2377 n = 4;
2378 arr[n++] = 0xd;
2379 arr[n++] = 0x0; /* Temperature */
2380 arr[3] = n - 4;
2381 break;
2382 case 0x2f: /* Informational exceptions subpages */
2383 n = 4;
2384 arr[n++] = 0x2f;
2385 arr[n++] = 0x0; /* Informational exceptions */
2386 arr[3] = n - 4;
2387 break;
2388 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002389 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002390 return check_condition_result;
2391 }
2392 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002393 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002394 return check_condition_result;
2395 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002396 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002397 return fill_from_dev_buffer(scp, arr,
2398 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2399}
2400
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002401static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002402 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002404 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002405 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 return check_condition_result;
2407 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002408 /* transfer length excessive (tie in to block limits VPD page) */
2409 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002410 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002411 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002412 return check_condition_result;
2413 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002414 return 0;
2415}
2416
Akinobu Mitaa4517512013-07-08 16:01:57 -07002417/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002418static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2419 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002420{
2421 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002422 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002423 struct scsi_data_buffer *sdb;
2424 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002425
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002426 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002427 sdb = scsi_out(scmd);
2428 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002429 } else {
2430 sdb = scsi_in(scmd);
2431 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002432 }
2433
2434 if (!sdb->length)
2435 return 0;
2436 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2437 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002438
2439 block = do_div(lba, sdebug_store_sectors);
2440 if (block + num > sdebug_store_sectors)
2441 rest = block + num - sdebug_store_sectors;
2442
Dave Gordon386ecb12015-06-30 14:58:57 -07002443 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002444 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002445 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002446 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002447 return ret;
2448
2449 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002450 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002451 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002452 sg_skip + ((num - rest) * sdebug_sector_size),
2453 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002454 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002455
2456 return ret;
2457}
2458
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002459/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2460 * arr into fake_store(lba,num) and return true. If comparison fails then
2461 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002462static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002463{
2464 bool res;
2465 u64 block, rest = 0;
2466 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002467 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002468
2469 block = do_div(lba, store_blks);
2470 if (block + num > store_blks)
2471 rest = block + num - store_blks;
2472
2473 res = !memcmp(fake_storep + (block * lb_size), arr,
2474 (num - rest) * lb_size);
2475 if (!res)
2476 return res;
2477 if (rest)
2478 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2479 rest * lb_size);
2480 if (!res)
2481 return res;
2482 arr += num * lb_size;
2483 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2484 if (rest)
2485 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2486 rest * lb_size);
2487 return res;
2488}
2489
Akinobu Mita51d648a2013-09-18 21:27:28 +09002490static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002491{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002492 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002493
Douglas Gilbert773642d2016-04-25 12:16:28 -04002494 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002495 csum = (__force __be16)ip_compute_csum(buf, len);
2496 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002497 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002498
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002499 return csum;
2500}
2501
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002502static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002503 sector_t sector, u32 ei_lba)
2504{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002505 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002506
2507 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002508 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002509 (unsigned long)sector,
2510 be16_to_cpu(sdt->guard_tag),
2511 be16_to_cpu(csum));
2512 return 0x01;
2513 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002514 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002515 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002516 pr_err("REF check failed on sector %lu\n",
2517 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002518 return 0x03;
2519 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002520 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002521 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002522 pr_err("REF check failed on sector %lu\n",
2523 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002524 return 0x03;
2525 }
2526 return 0;
2527}
2528
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002529static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002530 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002531{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002532 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002533 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002534 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002535 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002536
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002537 /* Bytes of protection data to copy into sgl */
2538 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002539
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002540 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2541 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2542 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2543
2544 while (sg_miter_next(&miter) && resid > 0) {
2545 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002546 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002547 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002548
2549 if (dif_store_end < start + len)
2550 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002551
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002552 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002553
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002554 if (read)
2555 memcpy(paddr, start, len - rest);
2556 else
2557 memcpy(start, paddr, len - rest);
2558
2559 if (rest) {
2560 if (read)
2561 memcpy(paddr + len - rest, dif_storep, rest);
2562 else
2563 memcpy(dif_storep, paddr + len - rest, rest);
2564 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002565
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002566 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002567 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002568 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002569 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002570}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002571
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002572static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2573 unsigned int sectors, u32 ei_lba)
2574{
2575 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002576 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002577 sector_t sector;
2578
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002579 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002580 int ret;
2581
2582 sector = start_sec + i;
2583 sdt = dif_store(sector);
2584
Akinobu Mita51d648a2013-09-18 21:27:28 +09002585 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002586 continue;
2587
2588 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2589 if (ret) {
2590 dif_errors++;
2591 return ret;
2592 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002593 }
2594
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002595 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002596 dix_reads++;
2597
2598 return 0;
2599}
2600
Douglas Gilbertfd321192016-04-25 12:16:33 -04002601static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002602{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002603 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002604 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002605 u64 lba;
2606 u32 num;
2607 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002608 unsigned long iflags;
2609 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002610 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002611
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002612 switch (cmd[0]) {
2613 case READ_16:
2614 ei_lba = 0;
2615 lba = get_unaligned_be64(cmd + 2);
2616 num = get_unaligned_be32(cmd + 10);
2617 check_prot = true;
2618 break;
2619 case READ_10:
2620 ei_lba = 0;
2621 lba = get_unaligned_be32(cmd + 2);
2622 num = get_unaligned_be16(cmd + 7);
2623 check_prot = true;
2624 break;
2625 case READ_6:
2626 ei_lba = 0;
2627 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2628 (u32)(cmd[1] & 0x1f) << 16;
2629 num = (0 == cmd[4]) ? 256 : cmd[4];
2630 check_prot = true;
2631 break;
2632 case READ_12:
2633 ei_lba = 0;
2634 lba = get_unaligned_be32(cmd + 2);
2635 num = get_unaligned_be32(cmd + 6);
2636 check_prot = true;
2637 break;
2638 case XDWRITEREAD_10:
2639 ei_lba = 0;
2640 lba = get_unaligned_be32(cmd + 2);
2641 num = get_unaligned_be16(cmd + 7);
2642 check_prot = false;
2643 break;
2644 default: /* assume READ(32) */
2645 lba = get_unaligned_be64(cmd + 12);
2646 ei_lba = get_unaligned_be32(cmd + 20);
2647 num = get_unaligned_be32(cmd + 28);
2648 check_prot = false;
2649 break;
2650 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002651 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002652 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002653 (cmd[1] & 0xe0)) {
2654 mk_sense_invalid_opcode(scp);
2655 return check_condition_result;
2656 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002657 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2658 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002659 (cmd[1] & 0xe0) == 0)
2660 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2661 "to DIF device\n");
2662 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002663 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002664 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002665
Douglas Gilbertc4837392016-05-06 00:40:26 -04002666 if (sqcp) {
2667 if (sqcp->inj_short)
2668 num /= 2;
2669 }
2670 } else
2671 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002672
2673 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002674 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002675 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2676 return check_condition_result;
2677 }
2678 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002679 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002680 /* needs work to find which cdb byte 'num' comes from */
2681 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2682 return check_condition_result;
2683 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002684
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002685 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2686 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2687 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002688 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002689 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002690 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002691 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2692 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002693 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2694 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002695 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002696 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002697 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 return check_condition_result;
2699 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002700
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002701 read_lock_irqsave(&atomic_rw, iflags);
2702
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002703 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002704 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002705 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002706
2707 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002708 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002709 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002710 return illegal_condition_result;
2711 }
2712 }
2713
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002714 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002716 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002717 return DID_ERROR << 16;
2718
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002719 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002720
Douglas Gilbertc4837392016-05-06 00:40:26 -04002721 if (unlikely(sqcp)) {
2722 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002723 mk_sense_buffer(scp, RECOVERED_ERROR,
2724 THRESHOLD_EXCEEDED, 0);
2725 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002726 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002727 mk_sense_buffer(scp, ABORTED_COMMAND,
2728 TRANSPORT_PROBLEM, ACK_NAK_TO);
2729 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002730 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002731 /* Logical block guard check failed */
2732 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2733 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002734 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002735 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2736 return illegal_condition_result;
2737 }
2738 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002739 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740}
2741
Tomas Winkler58a86352015-07-28 16:54:23 +03002742static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002743{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002744 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002745
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002746 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002747 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002748 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002749
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002750 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002751 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002752
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002753 if (c >= 0x20 && c < 0x7e)
2754 n += scnprintf(b + n, sizeof(b) - n,
2755 " %c ", buf[i+j]);
2756 else
2757 n += scnprintf(b + n, sizeof(b) - n,
2758 "%02x ", buf[i+j]);
2759 }
2760 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002761 }
2762}
2763
2764static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002765 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002766{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002767 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002768 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002769 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002770 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002771 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002772 int dpage_offset;
2773 struct sg_mapping_iter diter;
2774 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002775
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002776 BUG_ON(scsi_sg_count(SCpnt) == 0);
2777 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2778
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002779 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2780 scsi_prot_sg_count(SCpnt),
2781 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2782 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2783 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002784
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002785 /* For each protection page */
2786 while (sg_miter_next(&piter)) {
2787 dpage_offset = 0;
2788 if (WARN_ON(!sg_miter_next(&diter))) {
2789 ret = 0x01;
2790 goto out;
2791 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002792
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002793 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002794 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002795 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002796 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002797 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002798 if (dpage_offset >= diter.length) {
2799 if (WARN_ON(!sg_miter_next(&diter))) {
2800 ret = 0x01;
2801 goto out;
2802 }
2803 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002804 }
2805
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002806 sdt = piter.addr + ppage_offset;
2807 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002808
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002809 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002810 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002811 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002812 goto out;
2813 }
2814
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002815 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002816 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002817 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002818 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002819 diter.consumed = dpage_offset;
2820 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002821 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002822 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002823
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002824 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002825 dix_writes++;
2826
2827 return 0;
2828
2829out:
2830 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002831 sg_miter_stop(&diter);
2832 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002833 return ret;
2834}
2835
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002836static unsigned long lba_to_map_index(sector_t lba)
2837{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002838 if (sdebug_unmap_alignment)
2839 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2840 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002841 return lba;
2842}
2843
2844static sector_t map_index_to_lba(unsigned long index)
2845{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002846 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002847
Douglas Gilbert773642d2016-04-25 12:16:28 -04002848 if (sdebug_unmap_alignment)
2849 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002850 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002851}
2852
Martin K. Petersen44d92692009-10-15 14:45:27 -04002853static unsigned int map_state(sector_t lba, unsigned int *num)
2854{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002855 sector_t end;
2856 unsigned int mapped;
2857 unsigned long index;
2858 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002859
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002860 index = lba_to_map_index(lba);
2861 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002862
2863 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002864 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002865 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002866 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002867
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002868 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002869 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002870 return mapped;
2871}
2872
2873static void map_region(sector_t lba, unsigned int len)
2874{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002875 sector_t end = lba + len;
2876
Martin K. Petersen44d92692009-10-15 14:45:27 -04002877 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002878 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002879
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002880 if (index < map_size)
2881 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002882
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002883 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002884 }
2885}
2886
2887static void unmap_region(sector_t lba, unsigned int len)
2888{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002889 sector_t end = lba + len;
2890
Martin K. Petersen44d92692009-10-15 14:45:27 -04002891 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002892 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002893
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002894 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002895 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002896 index < map_size) {
2897 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002898 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002899 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002900 lba * sdebug_sector_size,
2901 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002902 sdebug_sector_size *
2903 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002904 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002905 if (dif_storep) {
2906 memset(dif_storep + lba, 0xff,
2907 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002908 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002909 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002910 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002911 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002912 }
2913}
2914
Douglas Gilbertfd321192016-04-25 12:16:33 -04002915static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002917 u8 *cmd = scp->cmnd;
2918 u64 lba;
2919 u32 num;
2920 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002922 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002923 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002925 switch (cmd[0]) {
2926 case WRITE_16:
2927 ei_lba = 0;
2928 lba = get_unaligned_be64(cmd + 2);
2929 num = get_unaligned_be32(cmd + 10);
2930 check_prot = true;
2931 break;
2932 case WRITE_10:
2933 ei_lba = 0;
2934 lba = get_unaligned_be32(cmd + 2);
2935 num = get_unaligned_be16(cmd + 7);
2936 check_prot = true;
2937 break;
2938 case WRITE_6:
2939 ei_lba = 0;
2940 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2941 (u32)(cmd[1] & 0x1f) << 16;
2942 num = (0 == cmd[4]) ? 256 : cmd[4];
2943 check_prot = true;
2944 break;
2945 case WRITE_12:
2946 ei_lba = 0;
2947 lba = get_unaligned_be32(cmd + 2);
2948 num = get_unaligned_be32(cmd + 6);
2949 check_prot = true;
2950 break;
2951 case 0x53: /* XDWRITEREAD(10) */
2952 ei_lba = 0;
2953 lba = get_unaligned_be32(cmd + 2);
2954 num = get_unaligned_be16(cmd + 7);
2955 check_prot = false;
2956 break;
2957 default: /* assume WRITE(32) */
2958 lba = get_unaligned_be64(cmd + 12);
2959 ei_lba = get_unaligned_be32(cmd + 20);
2960 num = get_unaligned_be32(cmd + 28);
2961 check_prot = false;
2962 break;
2963 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002964 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002965 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002966 (cmd[1] & 0xe0)) {
2967 mk_sense_invalid_opcode(scp);
2968 return check_condition_result;
2969 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002970 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2971 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002972 (cmd[1] & 0xe0) == 0)
2973 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2974 "to DIF device\n");
2975 }
2976
2977 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002978 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002979 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2980 return check_condition_result;
2981 }
2982 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002983 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002984 /* needs work to find which cdb byte 'num' comes from */
2985 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2986 return check_condition_result;
2987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002989 write_lock_irqsave(&atomic_rw, iflags);
2990
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002991 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002992 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002993 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002994
2995 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002996 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002997 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002998 return illegal_condition_result;
2999 }
3000 }
3001
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003002 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003003 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003004 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003006 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003007 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003008 else if (unlikely(sdebug_verbose &&
3009 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003010 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003011 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003012 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003013
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003014 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003015 struct sdebug_queued_cmd *sqcp =
3016 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003017
Douglas Gilbertc4837392016-05-06 00:40:26 -04003018 if (sqcp) {
3019 if (sqcp->inj_recovered) {
3020 mk_sense_buffer(scp, RECOVERED_ERROR,
3021 THRESHOLD_EXCEEDED, 0);
3022 return check_condition_result;
3023 } else if (sqcp->inj_dif) {
3024 /* Logical block guard check failed */
3025 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3026 return illegal_condition_result;
3027 } else if (sqcp->inj_dix) {
3028 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3029 return illegal_condition_result;
3030 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003031 }
3032 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 return 0;
3034}
3035
Douglas Gilbertfd321192016-04-25 12:16:33 -04003036static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3037 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003038{
3039 unsigned long iflags;
3040 unsigned long long i;
3041 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003042 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003043
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003044 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003045 if (ret)
3046 return ret;
3047
3048 write_lock_irqsave(&atomic_rw, iflags);
3049
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003050 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003051 unmap_region(lba, num);
3052 goto out;
3053 }
3054
Douglas Gilbert773642d2016-04-25 12:16:28 -04003055 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003056 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3057 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003058 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003059 ret = 0;
3060 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003061 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3062 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003063
3064 if (-1 == ret) {
3065 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003066 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003067 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003068 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003069 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003070 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003071 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003072
3073 /* Copy first sector to remaining blocks */
3074 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003075 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3076 fake_storep + lba_off,
3077 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003078
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003079 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003080 map_region(lba, num);
3081out:
3082 write_unlock_irqrestore(&atomic_rw, iflags);
3083
3084 return 0;
3085}
3086
Douglas Gilbertfd321192016-04-25 12:16:33 -04003087static int resp_write_same_10(struct scsi_cmnd *scp,
3088 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003089{
3090 u8 *cmd = scp->cmnd;
3091 u32 lba;
3092 u16 num;
3093 u32 ei_lba = 0;
3094 bool unmap = false;
3095
3096 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003097 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003098 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3099 return check_condition_result;
3100 } else
3101 unmap = true;
3102 }
3103 lba = get_unaligned_be32(cmd + 2);
3104 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003105 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003106 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3107 return check_condition_result;
3108 }
3109 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3110}
3111
Douglas Gilbertfd321192016-04-25 12:16:33 -04003112static int resp_write_same_16(struct scsi_cmnd *scp,
3113 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003114{
3115 u8 *cmd = scp->cmnd;
3116 u64 lba;
3117 u32 num;
3118 u32 ei_lba = 0;
3119 bool unmap = false;
3120 bool ndob = false;
3121
3122 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003123 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003124 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3125 return check_condition_result;
3126 } else
3127 unmap = true;
3128 }
3129 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3130 ndob = true;
3131 lba = get_unaligned_be64(cmd + 2);
3132 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003133 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003134 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3135 return check_condition_result;
3136 }
3137 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3138}
3139
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003140/* Note the mode field is in the same position as the (lower) service action
3141 * field. For the Report supported operation codes command, SPC-4 suggests
3142 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003143static int resp_write_buffer(struct scsi_cmnd *scp,
3144 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003145{
3146 u8 *cmd = scp->cmnd;
3147 struct scsi_device *sdp = scp->device;
3148 struct sdebug_dev_info *dp;
3149 u8 mode;
3150
3151 mode = cmd[1] & 0x1f;
3152 switch (mode) {
3153 case 0x4: /* download microcode (MC) and activate (ACT) */
3154 /* set UAs on this device only */
3155 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3156 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3157 break;
3158 case 0x5: /* download MC, save and ACT */
3159 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3160 break;
3161 case 0x6: /* download MC with offsets and ACT */
3162 /* set UAs on most devices (LUs) in this target */
3163 list_for_each_entry(dp,
3164 &devip->sdbg_host->dev_info_list,
3165 dev_list)
3166 if (dp->target == sdp->id) {
3167 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3168 if (devip != dp)
3169 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3170 dp->uas_bm);
3171 }
3172 break;
3173 case 0x7: /* download MC with offsets, save, and ACT */
3174 /* set UA on all devices (LUs) in this target */
3175 list_for_each_entry(dp,
3176 &devip->sdbg_host->dev_info_list,
3177 dev_list)
3178 if (dp->target == sdp->id)
3179 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3180 dp->uas_bm);
3181 break;
3182 default:
3183 /* do nothing for this command for other mode values */
3184 break;
3185 }
3186 return 0;
3187}
3188
Douglas Gilbertfd321192016-04-25 12:16:33 -04003189static int resp_comp_write(struct scsi_cmnd *scp,
3190 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003191{
3192 u8 *cmd = scp->cmnd;
3193 u8 *arr;
3194 u8 *fake_storep_hold;
3195 u64 lba;
3196 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003197 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003198 u8 num;
3199 unsigned long iflags;
3200 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003201 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003202
Douglas Gilbertd467d312014-11-26 12:33:48 -05003203 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003204 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3205 if (0 == num)
3206 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003207 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003208 (cmd[1] & 0xe0)) {
3209 mk_sense_invalid_opcode(scp);
3210 return check_condition_result;
3211 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003212 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3213 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003214 (cmd[1] & 0xe0) == 0)
3215 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3216 "to DIF device\n");
3217
3218 /* inline check_device_access_params() */
3219 if (lba + num > sdebug_capacity) {
3220 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3221 return check_condition_result;
3222 }
3223 /* transfer length excessive (tie in to block limits VPD page) */
3224 if (num > sdebug_store_sectors) {
3225 /* needs work to find which cdb byte 'num' comes from */
3226 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3227 return check_condition_result;
3228 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003229 dnum = 2 * num;
3230 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3231 if (NULL == arr) {
3232 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3233 INSUFF_RES_ASCQ);
3234 return check_condition_result;
3235 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003236
3237 write_lock_irqsave(&atomic_rw, iflags);
3238
3239 /* trick do_device_access() to fetch both compare and write buffers
3240 * from data-in into arr. Safe (atomic) since write_lock held. */
3241 fake_storep_hold = fake_storep;
3242 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003243 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003244 fake_storep = fake_storep_hold;
3245 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003246 retval = DID_ERROR << 16;
3247 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003248 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003249 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3250 "indicated=%u, IO sent=%d bytes\n", my_name,
3251 dnum * lb_size, ret);
3252 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003253 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003254 retval = check_condition_result;
3255 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003256 }
3257 if (scsi_debug_lbp())
3258 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003259cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003260 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003261 kfree(arr);
3262 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003263}
3264
Martin K. Petersen44d92692009-10-15 14:45:27 -04003265struct unmap_block_desc {
3266 __be64 lba;
3267 __be32 blocks;
3268 __be32 __reserved;
3269};
3270
Douglas Gilbertfd321192016-04-25 12:16:33 -04003271static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003272{
3273 unsigned char *buf;
3274 struct unmap_block_desc *desc;
3275 unsigned int i, payload_len, descriptors;
3276 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003277 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003278
Martin K. Petersen44d92692009-10-15 14:45:27 -04003279
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003280 if (!scsi_debug_lbp())
3281 return 0; /* fib and say its done */
3282 payload_len = get_unaligned_be16(scp->cmnd + 7);
3283 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003284
3285 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003286 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003287 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003288 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003289 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003290
Douglas Gilbertb333a812016-04-25 12:16:30 -04003291 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003292 if (!buf) {
3293 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3294 INSUFF_RES_ASCQ);
3295 return check_condition_result;
3296 }
3297
3298 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003299
3300 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3301 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3302
3303 desc = (void *)&buf[8];
3304
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003305 write_lock_irqsave(&atomic_rw, iflags);
3306
Martin K. Petersen44d92692009-10-15 14:45:27 -04003307 for (i = 0 ; i < descriptors ; i++) {
3308 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3309 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3310
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003311 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003312 if (ret)
3313 goto out;
3314
3315 unmap_region(lba, num);
3316 }
3317
3318 ret = 0;
3319
3320out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003321 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003322 kfree(buf);
3323
3324 return ret;
3325}
3326
3327#define SDEBUG_GET_LBA_STATUS_LEN 32
3328
Douglas Gilbertfd321192016-04-25 12:16:33 -04003329static int resp_get_lba_status(struct scsi_cmnd *scp,
3330 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003331{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003332 u8 *cmd = scp->cmnd;
3333 u64 lba;
3334 u32 alloc_len, mapped, num;
3335 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003336 int ret;
3337
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003338 lba = get_unaligned_be64(cmd + 2);
3339 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003340
3341 if (alloc_len < 24)
3342 return 0;
3343
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003344 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003345 if (ret)
3346 return ret;
3347
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003348 if (scsi_debug_lbp())
3349 mapped = map_state(lba, &num);
3350 else {
3351 mapped = 1;
3352 /* following just in case virtual_gb changed */
3353 sdebug_capacity = get_sdebug_capacity();
3354 if (sdebug_capacity - lba <= 0xffffffff)
3355 num = sdebug_capacity - lba;
3356 else
3357 num = 0xffffffff;
3358 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003359
3360 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003361 put_unaligned_be32(20, arr); /* Parameter Data Length */
3362 put_unaligned_be64(lba, arr + 8); /* LBA */
3363 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3364 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003365
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003366 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003367}
3368
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003369#define RL_BUCKET_ELEMS 8
3370
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003371/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3372 * (W-LUN), the normal Linux scanning logic does not associate it with a
3373 * device (e.g. /dev/sg7). The following magic will make that association:
3374 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3375 * where <n> is a host number. If there are multiple targets in a host then
3376 * the above will associate a W-LUN to each target. To only get a W-LUN
3377 * for target 2, then use "echo '- 2 49409' > scan" .
3378 */
3379static int resp_report_luns(struct scsi_cmnd *scp,
3380 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003382 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003383 unsigned int alloc_len;
3384 unsigned char select_report;
3385 u64 lun;
3386 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003387 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003388 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3389 unsigned int wlun_cnt; /* report luns W-LUN count */
3390 unsigned int tlun_cnt; /* total LUN count */
3391 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003392 int k, j, n, res;
3393 unsigned int off_rsp = 0;
3394 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003396 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003397
3398 select_report = cmd[2];
3399 alloc_len = get_unaligned_be32(cmd + 6);
3400
3401 if (alloc_len < 4) {
3402 pr_err("alloc len too small %d\n", alloc_len);
3403 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 return check_condition_result;
3405 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003406
3407 switch (select_report) {
3408 case 0: /* all LUNs apart from W-LUNs */
3409 lun_cnt = sdebug_max_luns;
3410 wlun_cnt = 0;
3411 break;
3412 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003413 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003414 wlun_cnt = 1;
3415 break;
3416 case 2: /* all LUNs */
3417 lun_cnt = sdebug_max_luns;
3418 wlun_cnt = 1;
3419 break;
3420 case 0x10: /* only administrative LUs */
3421 case 0x11: /* see SPC-5 */
3422 case 0x12: /* only subsiduary LUs owned by referenced LU */
3423 default:
3424 pr_debug("select report invalid %d\n", select_report);
3425 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3426 return check_condition_result;
3427 }
3428
3429 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003430 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003431
3432 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003433 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3434 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003435 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3436 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3437
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003438 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003439 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003440 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3441 memset(arr, 0, sizeof(arr));
3442 lun_p = (struct scsi_lun *)&arr[0];
3443 if (k == 0) {
3444 put_unaligned_be32(rlen, &arr[0]);
3445 ++lun_p;
3446 j = 1;
3447 }
3448 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3449 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3450 break;
3451 int_to_scsilun(lun++, lun_p);
3452 }
3453 if (j < RL_BUCKET_ELEMS)
3454 break;
3455 n = j * sz_lun;
3456 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3457 if (res)
3458 return res;
3459 off_rsp += n;
3460 }
3461 if (wlun_cnt) {
3462 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3463 ++j;
3464 }
3465 if (j > 0)
3466 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003467 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468}
3469
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003470static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3471 unsigned int num, struct sdebug_dev_info *devip)
3472{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003473 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003474 unsigned char *kaddr, *buf;
3475 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003476 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003477 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003478
3479 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003480 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003481 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003482 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3483 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003484 return check_condition_result;
3485 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003486
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003487 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003488
3489 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003490 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3491 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003492
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003493 while (sg_miter_next(&miter)) {
3494 kaddr = miter.addr;
3495 for (j = 0; j < miter.length; j++)
3496 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003497
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003498 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003499 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003500 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003501 kfree(buf);
3502
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003503 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003504}
3505
Douglas Gilbertfd321192016-04-25 12:16:33 -04003506static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3507 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003508{
3509 u8 *cmd = scp->cmnd;
3510 u64 lba;
3511 u32 num;
3512 int errsts;
3513
3514 if (!scsi_bidi_cmnd(scp)) {
3515 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3516 INSUFF_RES_ASCQ);
3517 return check_condition_result;
3518 }
3519 errsts = resp_read_dt0(scp, devip);
3520 if (errsts)
3521 return errsts;
3522 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3523 errsts = resp_write_dt0(scp, devip);
3524 if (errsts)
3525 return errsts;
3526 }
3527 lba = get_unaligned_be32(cmd + 2);
3528 num = get_unaligned_be16(cmd + 7);
3529 return resp_xdwriteread(scp, lba, num, devip);
3530}
3531
Douglas Gilbertc4837392016-05-06 00:40:26 -04003532static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3533{
3534 struct sdebug_queue *sqp = sdebug_q_arr;
3535
3536 if (sdebug_mq_active) {
3537 u32 tag = blk_mq_unique_tag(cmnd->request);
3538 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3539
3540 if (unlikely(hwq >= submit_queues)) {
3541 pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3542 hwq %= submit_queues;
3543 }
3544 pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3545 return sqp + hwq;
3546 } else
3547 return sqp;
3548}
3549
3550/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003551static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003553 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003554 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003556 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003557 struct sdebug_queued_cmd *sqcp;
3558 struct scsi_cmnd *scp;
3559 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560
Douglas Gilbertc4837392016-05-06 00:40:26 -04003561 qc_idx = sd_dp->qc_idx;
3562 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3563 if (sdebug_statistics) {
3564 atomic_inc(&sdebug_completions);
3565 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3566 atomic_inc(&sdebug_miss_cpus);
3567 }
3568 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3569 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 return;
3571 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003572 spin_lock_irqsave(&sqp->qc_lock, iflags);
3573 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003574 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003575 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003576 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3577 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3578 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 return;
3580 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003581 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003582 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003583 atomic_dec(&devip->num_in_q);
3584 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003585 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003586 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003587 retiring = 1;
3588
3589 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003590 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3591 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003592 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003593 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003595
3596 if (unlikely(retiring)) { /* user has reduced max_queue */
3597 int k, retval;
3598
3599 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003600 if (qc_idx >= retval) {
3601 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003602 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003603 return;
3604 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003605 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003606 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003607 atomic_set(&retired_max_queue, 0);
3608 else
3609 atomic_set(&retired_max_queue, k + 1);
3610 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003611 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003612 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613}
3614
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003615/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003616static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003617{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003618 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3619 hrt);
3620 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003621 return HRTIMER_NORESTART;
3622}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623
Douglas Gilberta10bc122016-04-25 12:16:32 -04003624/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003625static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003626{
3627 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3628 ew.work);
3629 sdebug_q_cmd_complete(sd_dp);
3630}
3631
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003632static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003633static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003634
Douglas Gilbertfd321192016-04-25 12:16:33 -04003635static struct sdebug_dev_info *sdebug_device_create(
3636 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003637{
3638 struct sdebug_dev_info *devip;
3639
3640 devip = kzalloc(sizeof(*devip), flags);
3641 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003642 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003643 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003644 else if (sdebug_uuid_ctl == 2) {
3645 if (got_shared_uuid)
3646 devip->lu_name = shared_uuid;
3647 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003648 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003649 got_shared_uuid = true;
3650 devip->lu_name = shared_uuid;
3651 }
3652 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003653 devip->sdbg_host = sdbg_host;
3654 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3655 }
3656 return devip;
3657}
3658
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003659static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003661 struct sdebug_host_info *sdbg_host;
3662 struct sdebug_dev_info *open_devip = NULL;
3663 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003665 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3666 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003667 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3671 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003672 (devip->target == sdev->id) &&
3673 (devip->lun == sdev->lun))
3674 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 else {
3676 if ((!devip->used) && (!open_devip))
3677 open_devip = devip;
3678 }
3679 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003680 if (!open_devip) { /* try and make a new one */
3681 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3682 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003683 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 return NULL;
3685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003687
3688 open_devip->channel = sdev->channel;
3689 open_devip->target = sdev->id;
3690 open_devip->lun = sdev->lun;
3691 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003692 atomic_set(&open_devip->num_in_q, 0);
3693 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003694 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003695 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696}
3697
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003698static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003700 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003701 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003702 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003703 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003704 return 0;
3705}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003707static int scsi_debug_slave_configure(struct scsi_device *sdp)
3708{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003709 struct sdebug_dev_info *devip =
3710 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003711
Douglas Gilbert773642d2016-04-25 12:16:28 -04003712 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003713 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003714 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003715 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3716 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3717 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003718 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003719 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003720 return 1; /* no resources, will be marked offline */
3721 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003722 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003723 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003724 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003725 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003726 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003727 return 0;
3728}
3729
3730static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3731{
3732 struct sdebug_dev_info *devip =
3733 (struct sdebug_dev_info *)sdp->hostdata;
3734
Douglas Gilbert773642d2016-04-25 12:16:28 -04003735 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003736 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003737 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3738 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003739 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003740 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003741 sdp->hostdata = NULL;
3742 }
3743}
3744
Douglas Gilbertc4837392016-05-06 00:40:26 -04003745static void stop_qc_helper(struct sdebug_defer *sd_dp)
3746{
3747 if (!sd_dp)
3748 return;
3749 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3750 hrtimer_cancel(&sd_dp->hrt);
3751 else if (sdebug_jdelay < 0)
3752 cancel_work_sync(&sd_dp->ew.work);
3753}
3754
Douglas Gilberta10bc122016-04-25 12:16:32 -04003755/* If @cmnd found deletes its timer or work queue and returns true; else
3756 returns false */
3757static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003758{
3759 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003760 int j, k, qmax, r_qmax;
3761 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003762 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003763 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003764 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003765
Douglas Gilbertc4837392016-05-06 00:40:26 -04003766 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3767 spin_lock_irqsave(&sqp->qc_lock, iflags);
3768 qmax = sdebug_max_queue;
3769 r_qmax = atomic_read(&retired_max_queue);
3770 if (r_qmax > qmax)
3771 qmax = r_qmax;
3772 for (k = 0; k < qmax; ++k) {
3773 if (test_bit(k, sqp->in_use_bm)) {
3774 sqcp = &sqp->qc_arr[k];
3775 if (cmnd != sqcp->a_cmnd)
3776 continue;
3777 /* found */
3778 devip = (struct sdebug_dev_info *)
3779 cmnd->device->hostdata;
3780 if (devip)
3781 atomic_dec(&devip->num_in_q);
3782 sqcp->a_cmnd = NULL;
3783 sd_dp = sqcp->sd_dp;
3784 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3785 stop_qc_helper(sd_dp);
3786 clear_bit(k, sqp->in_use_bm);
3787 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003788 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003789 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003790 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003791 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003792 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003793}
3794
Douglas Gilberta10bc122016-04-25 12:16:32 -04003795/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003796static void stop_all_queued(void)
3797{
3798 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003799 int j, k;
3800 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003801 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003802 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003803 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003804
Douglas Gilbertc4837392016-05-06 00:40:26 -04003805 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3806 spin_lock_irqsave(&sqp->qc_lock, iflags);
3807 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3808 if (test_bit(k, sqp->in_use_bm)) {
3809 sqcp = &sqp->qc_arr[k];
3810 if (sqcp->a_cmnd == NULL)
3811 continue;
3812 devip = (struct sdebug_dev_info *)
3813 sqcp->a_cmnd->device->hostdata;
3814 if (devip)
3815 atomic_dec(&devip->num_in_q);
3816 sqcp->a_cmnd = NULL;
3817 sd_dp = sqcp->sd_dp;
3818 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3819 stop_qc_helper(sd_dp);
3820 clear_bit(k, sqp->in_use_bm);
3821 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003822 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003823 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003824 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826}
3827
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003828/* Free queued command memory on heap */
3829static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003831 int j, k;
3832 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003833 struct sdebug_queued_cmd *sqcp;
3834
Douglas Gilbertc4837392016-05-06 00:40:26 -04003835 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3836 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3837 sqcp = &sqp->qc_arr[k];
3838 kfree(sqcp->sd_dp);
3839 sqcp->sd_dp = NULL;
3840 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842}
3843
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003844static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003846 bool ok;
3847
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003848 ++num_aborts;
3849 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003850 ok = stop_queued_cmnd(SCpnt);
3851 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3852 sdev_printk(KERN_INFO, SCpnt->device,
3853 "%s: command%s found\n", __func__,
3854 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003856 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857}
3858
3859static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3860{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003862 if (SCpnt && SCpnt->device) {
3863 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003864 struct sdebug_dev_info *devip =
3865 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003866
Douglas Gilbert773642d2016-04-25 12:16:28 -04003867 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003868 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003870 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 }
3872 return SUCCESS;
3873}
3874
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003875static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3876{
3877 struct sdebug_host_info *sdbg_host;
3878 struct sdebug_dev_info *devip;
3879 struct scsi_device *sdp;
3880 struct Scsi_Host *hp;
3881 int k = 0;
3882
3883 ++num_target_resets;
3884 if (!SCpnt)
3885 goto lie;
3886 sdp = SCpnt->device;
3887 if (!sdp)
3888 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003889 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003890 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3891 hp = sdp->host;
3892 if (!hp)
3893 goto lie;
3894 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3895 if (sdbg_host) {
3896 list_for_each_entry(devip,
3897 &sdbg_host->dev_info_list,
3898 dev_list)
3899 if (devip->target == sdp->id) {
3900 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3901 ++k;
3902 }
3903 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003904 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003905 sdev_printk(KERN_INFO, sdp,
3906 "%s: %d device(s) found in target\n", __func__, k);
3907lie:
3908 return SUCCESS;
3909}
3910
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3912{
3913 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003914 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003915 struct scsi_device *sdp;
3916 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003917 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003920 if (!(SCpnt && SCpnt->device))
3921 goto lie;
3922 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003923 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003924 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3925 hp = sdp->host;
3926 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003927 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003929 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05003930 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003931 dev_list) {
3932 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3933 ++k;
3934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 }
3936 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003937 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003938 sdev_printk(KERN_INFO, sdp,
3939 "%s: %d device(s) found in host\n", __func__, k);
3940lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 return SUCCESS;
3942}
3943
3944static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3945{
3946 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003947 struct sdebug_dev_info *devip;
3948 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003951 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003952 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05003953 spin_lock(&sdebug_host_list_lock);
3954 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003955 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3956 dev_list) {
3957 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3958 ++k;
3959 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05003960 }
3961 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003963 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003964 sdev_printk(KERN_INFO, SCpnt->device,
3965 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 return SUCCESS;
3967}
3968
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003969static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003970 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971{
3972 struct partition * pp;
3973 int starts[SDEBUG_MAX_PARTS + 2];
3974 int sectors_per_part, num_sectors, k;
3975 int heads_by_sects, start_sec, end_sec;
3976
3977 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003978 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003980 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3981 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003982 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003984 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003986 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003988 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003989 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3991 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003992 starts[sdebug_num_parts] = num_sectors;
3993 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994
3995 ramp[510] = 0x55; /* magic partition markings */
3996 ramp[511] = 0xAA;
3997 pp = (struct partition *)(ramp + 0x1be);
3998 for (k = 0; starts[k + 1]; ++k, ++pp) {
3999 start_sec = starts[k];
4000 end_sec = starts[k + 1] - 1;
4001 pp->boot_ind = 0;
4002
4003 pp->cyl = start_sec / heads_by_sects;
4004 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4005 / sdebug_sectors_per;
4006 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4007
4008 pp->end_cyl = end_sec / heads_by_sects;
4009 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4010 / sdebug_sectors_per;
4011 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4012
Akinobu Mita150c3542013-08-26 22:08:40 +09004013 pp->start_sect = cpu_to_le32(start_sec);
4014 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 pp->sys_ind = 0x83; /* plain Linux partition */
4016 }
4017}
4018
Douglas Gilbertc4837392016-05-06 00:40:26 -04004019static void block_unblock_all_queues(bool block)
4020{
4021 int j;
4022 struct sdebug_queue *sqp;
4023
4024 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4025 atomic_set(&sqp->blocked, (int)block);
4026}
4027
4028/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4029 * commands will be processed normally before triggers occur.
4030 */
4031static void tweak_cmnd_count(void)
4032{
4033 int count, modulo;
4034
4035 modulo = abs(sdebug_every_nth);
4036 if (modulo < 2)
4037 return;
4038 block_unblock_all_queues(true);
4039 count = atomic_read(&sdebug_cmnd_count);
4040 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4041 block_unblock_all_queues(false);
4042}
4043
4044static void clear_queue_stats(void)
4045{
4046 atomic_set(&sdebug_cmnd_count, 0);
4047 atomic_set(&sdebug_completions, 0);
4048 atomic_set(&sdebug_miss_cpus, 0);
4049 atomic_set(&sdebug_a_tsf, 0);
4050}
4051
4052static void setup_inject(struct sdebug_queue *sqp,
4053 struct sdebug_queued_cmd *sqcp)
4054{
4055 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
4056 return;
4057 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4058 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4059 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4060 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4061 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004062 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004063}
4064
4065/* Complete the processing of the thread that queued a SCSI command to this
4066 * driver. It either completes the command by calling cmnd_done() or
4067 * schedules a hr timer or work queue then returns 0. Returns
4068 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4069 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004070static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
4071 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004073 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004074 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004075 struct sdebug_queue *sqp;
4076 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004077 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004078 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004080 if (unlikely(devip == NULL)) {
4081 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004082 scsi_result = DID_NO_CONNECT << 16;
4083 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004085 sdp = cmnd->device;
4086
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004087 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004088 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4089 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004090 if (delta_jiff == 0)
4091 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004093 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004094 sqp = get_queue(cmnd);
4095 spin_lock_irqsave(&sqp->qc_lock, iflags);
4096 if (unlikely(atomic_read(&sqp->blocked))) {
4097 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4098 return SCSI_MLQUEUE_HOST_BUSY;
4099 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004100 num_in_q = atomic_read(&devip->num_in_q);
4101 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004102 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004103 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004104 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004105 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004106 goto respond_in_thread;
4107 } else
4108 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004109 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004110 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4111 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004112 if ((num_in_q == (qdepth - 1)) &&
4113 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004114 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004115 atomic_set(&sdebug_a_tsf, 0);
4116 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004117 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004119 }
4120
Douglas Gilbertc4837392016-05-06 00:40:26 -04004121 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004122 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004123 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004124 if (scsi_result)
4125 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004126 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004127 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004128 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004129 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004130 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004131 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004132 (scsi_result ? "status: TASK SET FULL" :
4133 "report: host busy"));
4134 if (scsi_result)
4135 goto respond_in_thread;
4136 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004137 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004139 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004140 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004141 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004142 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004143 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004144 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004145 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004146 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4147 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4148 setup_inject(sqp, sqcp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004149 if (delta_jiff > 0 || sdebug_ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004150 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004151
Douglas Gilbertb333a812016-04-25 12:16:30 -04004152 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004153 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004154 } else
Thomas Gleixner8b0e1952016-12-25 12:30:41 +01004155 kt = sdebug_ndelay;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004156 if (NULL == sd_dp) {
4157 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4158 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004159 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004160 sqcp->sd_dp = sd_dp;
4161 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004162 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004163 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004164 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4165 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004166 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004167 if (sdebug_statistics)
4168 sd_dp->issuing_cpu = raw_smp_processor_id();
4169 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4170 } else { /* jdelay < 0, use work queue */
Douglas Gilberta10bc122016-04-25 12:16:32 -04004171 if (NULL == sd_dp) {
4172 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4173 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004174 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004175 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004176 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4177 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004178 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004179 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004180 if (sdebug_statistics)
4181 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilberta10bc122016-04-25 12:16:32 -04004182 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004183 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004184 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4185 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004186 sdev_printk(KERN_INFO, sdp,
4187 "%s: num_in_q=%d +1, %s%s\n", __func__,
4188 num_in_q, (inject ? "<inject> " : ""),
4189 "status: TASK SET FULL");
4190 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004191
4192respond_in_thread: /* call back to mid-layer using invocation thread */
4193 cmnd->result = scsi_result;
4194 cmnd->scsi_done(cmnd);
4195 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004197
Douglas Gilbert23183912006-09-16 20:30:47 -04004198/* Note: The following macros create attribute files in the
4199 /sys/module/scsi_debug/parameters directory. Unfortunately this
4200 driver is unaware of a change and cannot trigger auxiliary actions
4201 as it can when the corresponding attribute in the
4202 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4203 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004204module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4205module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004206module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004207module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004208module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004209module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4210module_param_named(dif, sdebug_dif, int, S_IRUGO);
4211module_param_named(dix, sdebug_dix, int, S_IRUGO);
4212module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4213module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4214module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4215module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4216module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004217module_param_string(inq_vendor, sdebug_inq_vendor_id,
4218 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4219module_param_string(inq_product, sdebug_inq_product_id,
4220 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4221module_param_string(inq_rev, sdebug_inq_product_rev,
4222 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004223module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4224module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4225module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4226module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4227module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4228module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4229module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4230module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4231module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4232module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4233module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4234module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4235module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4236module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4237module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004238module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004239module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4240module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4241module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4242module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004243module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004244module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004245module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004246module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4247module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4248module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4249module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4250module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004251module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004252module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004253 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004254module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004255 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256
4257MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4258MODULE_DESCRIPTION("SCSI debug adapter driver");
4259MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004260MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261
4262MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004263MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004264MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004265MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004266MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004267MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004268MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4269MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004270MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004271MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004272MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004273MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004274MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004275MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4276MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004277MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4278 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004279MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4280MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4281MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004282MODULE_PARM_DESC(lbprz,
4283 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004284MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004285MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004286MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4287MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004288MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004289MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004291MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004292MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004293MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004294MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004295MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004297MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004298MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004299MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004300MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004301MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004302MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004303MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4304MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004305MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4306MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004307MODULE_PARM_DESC(uuid_ctl,
4308 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004309MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004310MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4311MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004313#define SDEBUG_INFO_LEN 256
4314static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315
4316static const char * scsi_debug_info(struct Scsi_Host * shp)
4317{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004318 int k;
4319
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004320 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4321 my_name, SDEBUG_VERSION, sdebug_version_date);
4322 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004323 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004324 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4325 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4326 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4327 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 return sdebug_info;
4329}
4330
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004331/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004332static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4333 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334{
Al Viroc8ed5552013-03-31 01:46:06 -04004335 char arr[16];
4336 int opts;
4337 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
Al Viroc8ed5552013-03-31 01:46:06 -04004339 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4340 return -EACCES;
4341 memcpy(arr, buffer, minLen);
4342 arr[minLen] = '\0';
4343 if (1 != sscanf(arr, "%d", &opts))
4344 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004345 sdebug_opts = opts;
4346 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4347 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4348 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004349 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004350 return length;
4351}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004353/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4354 * same for each scsi_debug host (if more than one). Some of the counters
4355 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004356static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4357{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004358 int f, j, l;
4359 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004360
Douglas Gilbertc4837392016-05-06 00:40:26 -04004361 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4362 SDEBUG_VERSION, sdebug_version_date);
4363 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4364 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4365 sdebug_opts, sdebug_every_nth);
4366 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4367 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4368 sdebug_sector_size, "bytes");
4369 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4370 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4371 num_aborts);
4372 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4373 num_dev_resets, num_target_resets, num_bus_resets,
4374 num_host_resets);
4375 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4376 dix_reads, dix_writes, dif_errors);
4377 seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4378 TICK_NSEC / 1000, "statistics", sdebug_statistics,
4379 sdebug_mq_active);
4380 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4381 atomic_read(&sdebug_cmnd_count),
4382 atomic_read(&sdebug_completions),
4383 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4384 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004385
Douglas Gilbertc4837392016-05-06 00:40:26 -04004386 seq_printf(m, "submit_queues=%d\n", submit_queues);
4387 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4388 seq_printf(m, " queue %d:\n", j);
4389 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4390 if (f != sdebug_max_queue) {
4391 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4392 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4393 "first,last bits", f, l);
4394 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004395 }
Al Viroc8ed5552013-03-31 01:46:06 -04004396 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397}
4398
Akinobu Mita82069372013-10-14 22:48:04 +09004399static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004401 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004403/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4404 * of delay is jiffies.
4405 */
Akinobu Mita82069372013-10-14 22:48:04 +09004406static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4407 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004409 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004411 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004412 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004413 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004414 int j, k;
4415 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004416
Douglas Gilbertc4837392016-05-06 00:40:26 -04004417 block_unblock_all_queues(true);
4418 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4419 ++j, ++sqp) {
4420 k = find_first_bit(sqp->in_use_bm,
4421 sdebug_max_queue);
4422 if (k != sdebug_max_queue) {
4423 res = -EBUSY; /* queued commands */
4424 break;
4425 }
4426 }
4427 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004428 /* make sure sdebug_defer instances get
4429 * re-allocated for new delay variant */
4430 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004431 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004432 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004433 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004434 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004436 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 }
4438 return -EINVAL;
4439}
Akinobu Mita82069372013-10-14 22:48:04 +09004440static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004442static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4443{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004444 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004445}
4446/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004447/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004448static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004449 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004450{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004451 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004452
4453 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004454 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004455 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004456 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004457 int j, k;
4458 struct sdebug_queue *sqp;
4459
4460 block_unblock_all_queues(true);
4461 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4462 ++j, ++sqp) {
4463 k = find_first_bit(sqp->in_use_bm,
4464 sdebug_max_queue);
4465 if (k != sdebug_max_queue) {
4466 res = -EBUSY; /* queued commands */
4467 break;
4468 }
4469 }
4470 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004471 /* make sure sdebug_defer instances get
4472 * re-allocated for new delay variant */
4473 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004474 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004475 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4476 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004477 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004478 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004479 }
4480 return res;
4481 }
4482 return -EINVAL;
4483}
4484static DRIVER_ATTR_RW(ndelay);
4485
Akinobu Mita82069372013-10-14 22:48:04 +09004486static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004488 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489}
4490
Akinobu Mita82069372013-10-14 22:48:04 +09004491static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4492 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004494 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 char work[20];
4496
Douglas Gilbert9a051012017-12-23 12:48:10 -05004497 if (sscanf(buf, "%10s", work) == 1) {
4498 if (strncasecmp(work, "0x", 2) == 0) {
4499 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 goto opts_done;
4501 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004502 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 goto opts_done;
4504 }
4505 }
4506 return -EINVAL;
4507opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004508 sdebug_opts = opts;
4509 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4510 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004511 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 return count;
4513}
Akinobu Mita82069372013-10-14 22:48:04 +09004514static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515
Akinobu Mita82069372013-10-14 22:48:04 +09004516static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004518 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519}
Akinobu Mita82069372013-10-14 22:48:04 +09004520static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4521 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004523 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524
4525 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004526 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 return count;
4528 }
4529 return -EINVAL;
4530}
Akinobu Mita82069372013-10-14 22:48:04 +09004531static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
Akinobu Mita82069372013-10-14 22:48:04 +09004533static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004535 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536}
Akinobu Mita82069372013-10-14 22:48:04 +09004537static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4538 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004540 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541
4542 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004543 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 return count;
4545 }
4546 return -EINVAL;
4547}
Akinobu Mita82069372013-10-14 22:48:04 +09004548static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549
Akinobu Mita82069372013-10-14 22:48:04 +09004550static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004551{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004552 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004553}
Akinobu Mita82069372013-10-14 22:48:04 +09004554static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4555 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004556{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004557 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004558
4559 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004560 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004561 sdebug_fake_rw = (sdebug_fake_rw > 0);
4562 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004563 if ((0 == n) && (NULL == fake_storep)) {
4564 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004565 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004566 1048576;
4567
4568 fake_storep = vmalloc(sz);
4569 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004570 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004571 return -ENOMEM;
4572 }
4573 memset(fake_storep, 0, sz);
4574 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004575 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004576 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004577 return count;
4578 }
4579 return -EINVAL;
4580}
Akinobu Mita82069372013-10-14 22:48:04 +09004581static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004582
Akinobu Mita82069372013-10-14 22:48:04 +09004583static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004584{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004585 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004586}
Akinobu Mita82069372013-10-14 22:48:04 +09004587static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4588 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004589{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004590 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004591
4592 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004593 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004594 return count;
4595 }
4596 return -EINVAL;
4597}
Akinobu Mita82069372013-10-14 22:48:04 +09004598static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004599
Akinobu Mita82069372013-10-14 22:48:04 +09004600static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004602 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603}
Akinobu Mita82069372013-10-14 22:48:04 +09004604static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4605 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004607 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608
4609 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004610 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 sdebug_max_tgts_luns();
4612 return count;
4613 }
4614 return -EINVAL;
4615}
Akinobu Mita82069372013-10-14 22:48:04 +09004616static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617
Akinobu Mita82069372013-10-14 22:48:04 +09004618static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004620 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621}
Akinobu Mita82069372013-10-14 22:48:04 +09004622static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623
Akinobu Mita82069372013-10-14 22:48:04 +09004624static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004626 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627}
Akinobu Mita82069372013-10-14 22:48:04 +09004628static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629
Akinobu Mita82069372013-10-14 22:48:04 +09004630static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004632 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633}
Akinobu Mita82069372013-10-14 22:48:04 +09004634static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4635 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004637 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638
4639 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004640 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004641 if (nth && !sdebug_statistics) {
4642 pr_info("every_nth needs statistics=1, set it\n");
4643 sdebug_statistics = true;
4644 }
4645 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 return count;
4647 }
4648 return -EINVAL;
4649}
Akinobu Mita82069372013-10-14 22:48:04 +09004650static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
Akinobu Mita82069372013-10-14 22:48:04 +09004652static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004654 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655}
Akinobu Mita82069372013-10-14 22:48:04 +09004656static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4657 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004659 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004660 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661
4662 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004663 if (n > 256) {
4664 pr_warn("max_luns can be no more than 256\n");
4665 return -EINVAL;
4666 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004667 changed = (sdebug_max_luns != n);
4668 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004670 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004671 struct sdebug_host_info *sdhp;
4672 struct sdebug_dev_info *dp;
4673
4674 spin_lock(&sdebug_host_list_lock);
4675 list_for_each_entry(sdhp, &sdebug_host_list,
4676 host_list) {
4677 list_for_each_entry(dp, &sdhp->dev_info_list,
4678 dev_list) {
4679 set_bit(SDEBUG_UA_LUNS_CHANGED,
4680 dp->uas_bm);
4681 }
4682 }
4683 spin_unlock(&sdebug_host_list_lock);
4684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 return count;
4686 }
4687 return -EINVAL;
4688}
Akinobu Mita82069372013-10-14 22:48:04 +09004689static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
Akinobu Mita82069372013-10-14 22:48:04 +09004691static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004692{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004693 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004694}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004695/* N.B. max_queue can be changed while there are queued commands. In flight
4696 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004697static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4698 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004699{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004700 int j, n, k, a;
4701 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004702
4703 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004704 (n <= SDEBUG_CANQUEUE)) {
4705 block_unblock_all_queues(true);
4706 k = 0;
4707 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4708 ++j, ++sqp) {
4709 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4710 if (a > k)
4711 k = a;
4712 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004713 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004714 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004715 atomic_set(&retired_max_queue, 0);
4716 else if (k >= n)
4717 atomic_set(&retired_max_queue, k + 1);
4718 else
4719 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004720 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004721 return count;
4722 }
4723 return -EINVAL;
4724}
Akinobu Mita82069372013-10-14 22:48:04 +09004725static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004726
Akinobu Mita82069372013-10-14 22:48:04 +09004727static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004728{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004729 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004730}
Akinobu Mita82069372013-10-14 22:48:04 +09004731static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004732
Akinobu Mita82069372013-10-14 22:48:04 +09004733static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004735 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736}
Akinobu Mita82069372013-10-14 22:48:04 +09004737static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738
Akinobu Mita82069372013-10-14 22:48:04 +09004739static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004740{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004741 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004742}
Akinobu Mita82069372013-10-14 22:48:04 +09004743static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4744 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004745{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004746 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004747 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004748
4749 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004750 changed = (sdebug_virtual_gb != n);
4751 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004752 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004753 if (changed) {
4754 struct sdebug_host_info *sdhp;
4755 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004756
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004757 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004758 list_for_each_entry(sdhp, &sdebug_host_list,
4759 host_list) {
4760 list_for_each_entry(dp, &sdhp->dev_info_list,
4761 dev_list) {
4762 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4763 dp->uas_bm);
4764 }
4765 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004766 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004767 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004768 return count;
4769 }
4770 return -EINVAL;
4771}
Akinobu Mita82069372013-10-14 22:48:04 +09004772static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004773
Akinobu Mita82069372013-10-14 22:48:04 +09004774static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004776 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777}
4778
Douglas Gilbertfd321192016-04-25 12:16:33 -04004779static int sdebug_add_adapter(void);
4780static void sdebug_remove_adapter(void);
4781
Akinobu Mita82069372013-10-14 22:48:04 +09004782static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4783 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004785 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004787 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 if (delta_hosts > 0) {
4790 do {
4791 sdebug_add_adapter();
4792 } while (--delta_hosts);
4793 } else if (delta_hosts < 0) {
4794 do {
4795 sdebug_remove_adapter();
4796 } while (++delta_hosts);
4797 }
4798 return count;
4799}
Akinobu Mita82069372013-10-14 22:48:04 +09004800static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801
Akinobu Mita82069372013-10-14 22:48:04 +09004802static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004803{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004804 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004805}
Akinobu Mita82069372013-10-14 22:48:04 +09004806static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4807 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004808{
4809 int n;
4810
4811 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004812 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004813 return count;
4814 }
4815 return -EINVAL;
4816}
Akinobu Mita82069372013-10-14 22:48:04 +09004817static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004818
Douglas Gilbertc4837392016-05-06 00:40:26 -04004819static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4820{
4821 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4822}
4823static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4824 size_t count)
4825{
4826 int n;
4827
4828 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4829 if (n > 0)
4830 sdebug_statistics = true;
4831 else {
4832 clear_queue_stats();
4833 sdebug_statistics = false;
4834 }
4835 return count;
4836 }
4837 return -EINVAL;
4838}
4839static DRIVER_ATTR_RW(statistics);
4840
Akinobu Mita82069372013-10-14 22:48:04 +09004841static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004842{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004843 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004844}
Akinobu Mita82069372013-10-14 22:48:04 +09004845static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004846
Douglas Gilbertc4837392016-05-06 00:40:26 -04004847static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4848{
4849 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4850}
4851static DRIVER_ATTR_RO(submit_queues);
4852
Akinobu Mita82069372013-10-14 22:48:04 +09004853static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004854{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004855 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004856}
Akinobu Mita82069372013-10-14 22:48:04 +09004857static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004858
Akinobu Mita82069372013-10-14 22:48:04 +09004859static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004860{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004861 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004862}
Akinobu Mita82069372013-10-14 22:48:04 +09004863static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004864
Akinobu Mita82069372013-10-14 22:48:04 +09004865static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004866{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004867 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004868}
Akinobu Mita82069372013-10-14 22:48:04 +09004869static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004870
Akinobu Mita82069372013-10-14 22:48:04 +09004871static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004872{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004873 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004874}
Akinobu Mita82069372013-10-14 22:48:04 +09004875static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004876
Akinobu Mita82069372013-10-14 22:48:04 +09004877static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004878{
4879 ssize_t count;
4880
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004881 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004882 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4883 sdebug_store_sectors);
4884
Tejun Heoc7badc92015-02-13 14:37:51 -08004885 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4886 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004887 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004888 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004889
4890 return count;
4891}
Akinobu Mita82069372013-10-14 22:48:04 +09004892static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004893
Akinobu Mita82069372013-10-14 22:48:04 +09004894static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004895{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004896 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004897}
Akinobu Mita82069372013-10-14 22:48:04 +09004898static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4899 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004900{
4901 int n;
4902
4903 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004904 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004905 return count;
4906 }
4907 return -EINVAL;
4908}
Akinobu Mita82069372013-10-14 22:48:04 +09004909static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004910
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004911static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4912{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004913 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004914}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004915/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004916static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4917 size_t count)
4918{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004919 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004920
4921 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004922 sdebug_host_lock = (n > 0);
4923 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004924 }
4925 return -EINVAL;
4926}
4927static DRIVER_ATTR_RW(host_lock);
4928
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004929static ssize_t strict_show(struct device_driver *ddp, char *buf)
4930{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004931 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004932}
4933static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4934 size_t count)
4935{
4936 int n;
4937
4938 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004939 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004940 return count;
4941 }
4942 return -EINVAL;
4943}
4944static DRIVER_ATTR_RW(strict);
4945
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004946static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
4947{
4948 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
4949}
4950static DRIVER_ATTR_RO(uuid_ctl);
4951
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004952static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
4953{
4954 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
4955}
4956static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
4957 size_t count)
4958{
4959 int ret, n;
4960
4961 ret = kstrtoint(buf, 0, &n);
4962 if (ret)
4963 return ret;
4964 sdebug_cdb_len = n;
4965 all_config_cdb_len();
4966 return count;
4967}
4968static DRIVER_ATTR_RW(cdb_len);
4969
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004970
Akinobu Mita82069372013-10-14 22:48:04 +09004971/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004972 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4973 files (over those found in the /sys/module/scsi_debug/parameters
4974 directory) is that auxiliary actions can be triggered when an attribute
4975 is changed. For example see: sdebug_add_host_store() above.
4976 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004977
Akinobu Mita82069372013-10-14 22:48:04 +09004978static struct attribute *sdebug_drv_attrs[] = {
4979 &driver_attr_delay.attr,
4980 &driver_attr_opts.attr,
4981 &driver_attr_ptype.attr,
4982 &driver_attr_dsense.attr,
4983 &driver_attr_fake_rw.attr,
4984 &driver_attr_no_lun_0.attr,
4985 &driver_attr_num_tgts.attr,
4986 &driver_attr_dev_size_mb.attr,
4987 &driver_attr_num_parts.attr,
4988 &driver_attr_every_nth.attr,
4989 &driver_attr_max_luns.attr,
4990 &driver_attr_max_queue.attr,
4991 &driver_attr_no_uld.attr,
4992 &driver_attr_scsi_level.attr,
4993 &driver_attr_virtual_gb.attr,
4994 &driver_attr_add_host.attr,
4995 &driver_attr_vpd_use_hostno.attr,
4996 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004997 &driver_attr_statistics.attr,
4998 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004999 &driver_attr_dix.attr,
5000 &driver_attr_dif.attr,
5001 &driver_attr_guard.attr,
5002 &driver_attr_ato.attr,
5003 &driver_attr_map.attr,
5004 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005005 &driver_attr_host_lock.attr,
5006 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005007 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005008 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005009 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005010 NULL,
5011};
5012ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005014static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005015
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016static int __init scsi_debug_init(void)
5017{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005018 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 int host_to_add;
5020 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005021 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005023 atomic_set(&retired_max_queue, 0);
5024
Douglas Gilbert773642d2016-04-25 12:16:28 -04005025 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005026 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005027 sdebug_ndelay = 0;
5028 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005029 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005030
Douglas Gilbert773642d2016-04-25 12:16:28 -04005031 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04005032 case 512:
5033 case 1024:
5034 case 2048:
5035 case 4096:
5036 break;
5037 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005038 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04005039 return -EINVAL;
5040 }
5041
Douglas Gilbert773642d2016-04-25 12:16:28 -04005042 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005043 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005044 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005045 case T10_PI_TYPE1_PROTECTION:
5046 case T10_PI_TYPE2_PROTECTION:
5047 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005048 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005049 break;
5050
5051 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005052 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005053 return -EINVAL;
5054 }
5055
Douglas Gilbert773642d2016-04-25 12:16:28 -04005056 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005057 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005058 return -EINVAL;
5059 }
5060
Douglas Gilbert773642d2016-04-25 12:16:28 -04005061 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005062 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005063 return -EINVAL;
5064 }
5065
Douglas Gilbert773642d2016-04-25 12:16:28 -04005066 if (sdebug_physblk_exp > 15) {
5067 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005068 return -EINVAL;
5069 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005070 if (sdebug_max_luns > 256) {
5071 pr_warn("max_luns can be no more than 256, use default\n");
5072 sdebug_max_luns = DEF_MAX_LUNS;
5073 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005074
Douglas Gilbert773642d2016-04-25 12:16:28 -04005075 if (sdebug_lowest_aligned > 0x3fff) {
5076 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005077 return -EINVAL;
5078 }
5079
Douglas Gilbertc4837392016-05-06 00:40:26 -04005080 if (submit_queues < 1) {
5081 pr_err("submit_queues must be 1 or more\n");
5082 return -EINVAL;
5083 }
5084 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5085 GFP_KERNEL);
5086 if (sdebug_q_arr == NULL)
5087 return -ENOMEM;
5088 for (k = 0; k < submit_queues; ++k)
5089 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5090
Douglas Gilbert773642d2016-04-25 12:16:28 -04005091 if (sdebug_dev_size_mb < 1)
5092 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5093 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5094 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005095 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096
5097 /* play around with geometry, don't waste too much on track 0 */
5098 sdebug_heads = 8;
5099 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005100 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005102 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005103 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5105 (sdebug_sectors_per * sdebug_heads);
5106 if (sdebug_cylinders_per >= 1024) {
5107 /* other LLDs do this; implies >= 1GB ram disk ... */
5108 sdebug_heads = 255;
5109 sdebug_sectors_per = 63;
5110 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5111 (sdebug_sectors_per * sdebug_heads);
5112 }
5113
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005114 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005115 fake_storep = vmalloc(sz);
5116 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005117 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005118 ret = -ENOMEM;
5119 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005120 }
5121 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005122 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005123 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125
Douglas Gilbert773642d2016-04-25 12:16:28 -04005126 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005127 int dif_size;
5128
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005129 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005130 dif_storep = vmalloc(dif_size);
5131
Tomas Winklerc12879702015-07-28 16:54:20 +03005132 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005133
5134 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005135 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005136 ret = -ENOMEM;
5137 goto free_vm;
5138 }
5139
5140 memset(dif_storep, 0xff, dif_size);
5141 }
5142
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005143 /* Logical Block Provisioning */
5144 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005145 sdebug_unmap_max_blocks =
5146 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005147
Douglas Gilbert773642d2016-04-25 12:16:28 -04005148 sdebug_unmap_max_desc =
5149 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005150
Douglas Gilbert773642d2016-04-25 12:16:28 -04005151 sdebug_unmap_granularity =
5152 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005153
Douglas Gilbert773642d2016-04-25 12:16:28 -04005154 if (sdebug_unmap_alignment &&
5155 sdebug_unmap_granularity <=
5156 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005157 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005158 ret = -EINVAL;
5159 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005160 }
5161
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005162 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
5163 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005164
Tomas Winklerc12879702015-07-28 16:54:20 +03005165 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005166
5167 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005168 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005169 ret = -ENOMEM;
5170 goto free_vm;
5171 }
5172
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005173 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005174
5175 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005176 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005177 map_region(0, 2);
5178 }
5179
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005180 pseudo_primary = root_device_register("pseudo_0");
5181 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005182 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005183 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005184 goto free_vm;
5185 }
5186 ret = bus_register(&pseudo_lld_bus);
5187 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005188 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005189 goto dev_unreg;
5190 }
5191 ret = driver_register(&sdebug_driverfs_driver);
5192 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005193 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005194 goto bus_unreg;
5195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196
Douglas Gilbert773642d2016-04-25 12:16:28 -04005197 host_to_add = sdebug_add_host;
5198 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199
Douglas Gilbert9a051012017-12-23 12:48:10 -05005200 for (k = 0; k < host_to_add; k++) {
5201 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005202 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005203 break;
5204 }
5205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005206
Douglas Gilbert773642d2016-04-25 12:16:28 -04005207 if (sdebug_verbose)
5208 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005209
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005211
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005212bus_unreg:
5213 bus_unregister(&pseudo_lld_bus);
5214dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005215 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005216free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005217 vfree(map_storep);
5218 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005219 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005220free_q_arr:
5221 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005222 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223}
5224
5225static void __exit scsi_debug_exit(void)
5226{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005227 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228
5229 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005230 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 for (; k; k--)
5232 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 driver_unregister(&sdebug_driverfs_driver);
5234 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005235 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005237 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005238 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005240 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241}
5242
5243device_initcall(scsi_debug_init);
5244module_exit(scsi_debug_exit);
5245
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246static void sdebug_release_adapter(struct device * dev)
5247{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005248 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249
5250 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005251 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252}
5253
5254static int sdebug_add_adapter(void)
5255{
5256 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005257 int error = 0;
5258 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005259 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
Douglas Gilbert9a051012017-12-23 12:48:10 -05005261 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5262 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005263 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005264 return -ENOMEM;
5265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266
Douglas Gilbert9a051012017-12-23 12:48:10 -05005267 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
Douglas Gilbert773642d2016-04-25 12:16:28 -04005269 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005270 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005271 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5272 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005273 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005274 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005276 }
5277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278
Douglas Gilbert9a051012017-12-23 12:48:10 -05005279 spin_lock(&sdebug_host_list_lock);
5280 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5281 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282
Douglas Gilbert9a051012017-12-23 12:48:10 -05005283 sdbg_host->dev.bus = &pseudo_lld_bus;
5284 sdbg_host->dev.parent = pseudo_primary;
5285 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005286 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287
Douglas Gilbert9a051012017-12-23 12:48:10 -05005288 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289
Douglas Gilbert9a051012017-12-23 12:48:10 -05005290 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 goto clean;
5292
Douglas Gilbert773642d2016-04-25 12:16:28 -04005293 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005294 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295
5296clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005297 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5298 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 list_del(&sdbg_devinfo->dev_list);
5300 kfree(sdbg_devinfo);
5301 }
5302
5303 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005304 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305}
5306
5307static void sdebug_remove_adapter(void)
5308{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005309 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310
Douglas Gilbert9a051012017-12-23 12:48:10 -05005311 spin_lock(&sdebug_host_list_lock);
5312 if (!list_empty(&sdebug_host_list)) {
5313 sdbg_host = list_entry(sdebug_host_list.prev,
5314 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 list_del(&sdbg_host->host_list);
5316 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005317 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318
5319 if (!sdbg_host)
5320 return;
5321
Douglas Gilbert773642d2016-04-25 12:16:28 -04005322 device_unregister(&sdbg_host->dev);
5323 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324}
5325
Douglas Gilbertfd321192016-04-25 12:16:33 -04005326static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005327{
5328 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005329 struct sdebug_dev_info *devip;
5330
Douglas Gilbertc4837392016-05-06 00:40:26 -04005331 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005332 devip = (struct sdebug_dev_info *)sdev->hostdata;
5333 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005334 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005335 return -ENODEV;
5336 }
5337 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005338
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005339 if (qdepth < 1)
5340 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005341 /* allow to exceed max host qc_arr elements for testing */
5342 if (qdepth > SDEBUG_CANQUEUE + 10)
5343 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005344 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005345
Douglas Gilbert773642d2016-04-25 12:16:28 -04005346 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005347 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005348 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005349 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005350 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005351 return sdev->queue_depth;
5352}
5353
Douglas Gilbertc4837392016-05-06 00:40:26 -04005354static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005355{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005356 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005357 if (sdebug_every_nth < -1)
5358 sdebug_every_nth = -1;
5359 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005360 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005361 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005362 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005363 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005364 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005365 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005366}
5367
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005368static bool fake_host_busy(struct scsi_cmnd *scp)
5369{
5370 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5371 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5372}
5373
Douglas Gilbertfd321192016-04-25 12:16:33 -04005374static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5375 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005376{
5377 u8 sdeb_i;
5378 struct scsi_device *sdp = scp->device;
5379 const struct opcode_info_t *oip;
5380 const struct opcode_info_t *r_oip;
5381 struct sdebug_dev_info *devip;
5382 u8 *cmd = scp->cmnd;
5383 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5384 int k, na;
5385 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005386 u32 flags;
5387 u16 sa;
5388 u8 opcode = cmd[0];
5389 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005390
5391 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005392 if (sdebug_statistics)
5393 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005394 if (unlikely(sdebug_verbose &&
5395 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005396 char b[120];
5397 int n, len, sb;
5398
5399 len = scp->cmd_len;
5400 sb = (int)sizeof(b);
5401 if (len > 32)
5402 strcpy(b, "too long, over 32 bytes");
5403 else {
5404 for (k = 0, n = 0; k < len && n < sb; ++k)
5405 n += scnprintf(b + n, sb - n, "%02x ",
5406 (u32)cmd[k]);
5407 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005408 if (sdebug_mq_active)
5409 sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5410 my_name, blk_mq_unique_tag(scp->request),
5411 b);
5412 else
5413 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5414 b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005415 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005416 if (fake_host_busy(scp))
5417 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005418 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005419 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5420 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005421
5422 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5423 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5424 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005425 if (unlikely(!devip)) {
5426 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005427 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005428 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005429 }
5430 na = oip->num_attached;
5431 r_pfp = oip->pfp;
5432 if (na) { /* multiple commands with this opcode */
5433 r_oip = oip;
5434 if (FF_SA & r_oip->flags) {
5435 if (F_SA_LOW & oip->flags)
5436 sa = 0x1f & cmd[1];
5437 else
5438 sa = get_unaligned_be16(cmd + 8);
5439 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5440 if (opcode == oip->opcode && sa == oip->sa)
5441 break;
5442 }
5443 } else { /* since no service action only check opcode */
5444 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5445 if (opcode == oip->opcode)
5446 break;
5447 }
5448 }
5449 if (k > na) {
5450 if (F_SA_LOW & r_oip->flags)
5451 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5452 else if (F_SA_HIGH & r_oip->flags)
5453 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5454 else
5455 mk_sense_invalid_opcode(scp);
5456 goto check_cond;
5457 }
5458 } /* else (when na==0) we assume the oip is a match */
5459 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005460 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005461 mk_sense_invalid_opcode(scp);
5462 goto check_cond;
5463 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005464 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005465 if (sdebug_verbose)
5466 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5467 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005468 mk_sense_invalid_opcode(scp);
5469 goto check_cond;
5470 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005471 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005472 u8 rem;
5473 int j;
5474
5475 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5476 rem = ~oip->len_mask[k] & cmd[k];
5477 if (rem) {
5478 for (j = 7; j >= 0; --j, rem <<= 1) {
5479 if (0x80 & rem)
5480 break;
5481 }
5482 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5483 goto check_cond;
5484 }
5485 }
5486 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005487 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005488 find_first_bit(devip->uas_bm,
5489 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005490 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005491 if (errsts)
5492 goto check_cond;
5493 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005494 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005495 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005496 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005497 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5498 "%s\n", my_name, "initializing command "
5499 "required");
5500 errsts = check_condition_result;
5501 goto fini;
5502 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005503 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005504 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005505 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005506 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005507 return 0; /* ignore command: make trouble */
5508 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005509 if (likely(oip->pfp))
5510 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005511 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5512 errsts = r_pfp(scp, devip);
5513
5514fini:
5515 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005516 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005517check_cond:
5518 return schedule_resp(scp, devip, check_condition_result, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005519err_out:
5520 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005521}
5522
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005523static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005524 .show_info = scsi_debug_show_info,
5525 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005526 .proc_name = sdebug_proc_name,
5527 .name = "SCSI DEBUG",
5528 .info = scsi_debug_info,
5529 .slave_alloc = scsi_debug_slave_alloc,
5530 .slave_configure = scsi_debug_slave_configure,
5531 .slave_destroy = scsi_debug_slave_destroy,
5532 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005533 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005534 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005535 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005536 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005537 .eh_target_reset_handler = scsi_debug_target_reset,
5538 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005539 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005540 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005541 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005542 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005543 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005544 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005545 .use_clustering = DISABLE_CLUSTERING,
5546 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005547 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005548};
5549
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550static int sdebug_driver_probe(struct device * dev)
5551{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005552 int error = 0;
5553 struct sdebug_host_info *sdbg_host;
5554 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005555 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556
5557 sdbg_host = to_sdebug_host(dev);
5558
Douglas Gilbert773642d2016-04-25 12:16:28 -04005559 sdebug_driver_template.can_queue = sdebug_max_queue;
5560 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005561 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005562 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5563 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005564 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005565 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005567 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005568 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005569 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005570 my_name, submit_queues, nr_cpu_ids);
5571 submit_queues = nr_cpu_ids;
5572 }
5573 /* Decide whether to tell scsi subsystem that we want mq */
5574 /* Following should give the same answer for each host */
5575 sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5576 if (sdebug_mq_active)
5577 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578
Douglas Gilbert9a051012017-12-23 12:48:10 -05005579 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005581 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5582 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005584 hpnt->max_id = sdebug_num_tgts;
5585 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005586 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005587
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005588 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005589
Douglas Gilbert773642d2016-04-25 12:16:28 -04005590 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005591
Christoph Hellwig8475c812016-09-11 19:35:41 +02005592 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005593 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005594 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005595 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005596 break;
5597
Christoph Hellwig8475c812016-09-11 19:35:41 +02005598 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005599 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005600 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005601 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005602 break;
5603
Christoph Hellwig8475c812016-09-11 19:35:41 +02005604 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005605 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005606 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005607 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005608 break;
5609
5610 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005611 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005612 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005613 break;
5614 }
5615
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005616 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005617
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005618 if (have_dif_prot || sdebug_dix)
5619 pr_info("host protection%s%s%s%s%s%s%s\n",
5620 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5621 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5622 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5623 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5624 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5625 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5626 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005627
Douglas Gilbert773642d2016-04-25 12:16:28 -04005628 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005629 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5630 else
5631 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5632
Douglas Gilbert773642d2016-04-25 12:16:28 -04005633 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5634 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005635 if (sdebug_every_nth) /* need stats counters for every_nth */
5636 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005637 error = scsi_add_host(hpnt, &sdbg_host->dev);
5638 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005639 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005640 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005642 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 scsi_scan_host(hpnt);
5644
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005645 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646}
5647
5648static int sdebug_driver_remove(struct device * dev)
5649{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005650 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005651 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652
5653 sdbg_host = to_sdebug_host(dev);
5654
5655 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005656 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 return -ENODEV;
5658 }
5659
Douglas Gilbert9a051012017-12-23 12:48:10 -05005660 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005662 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5663 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005664 list_del(&sdbg_devinfo->dev_list);
5665 kfree(sdbg_devinfo);
5666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667
Douglas Gilbert9a051012017-12-23 12:48:10 -05005668 scsi_host_put(sdbg_host->shost);
5669 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670}
5671
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005672static int pseudo_lld_bus_match(struct device *dev,
5673 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005675 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005677
5678static struct bus_type pseudo_lld_bus = {
5679 .name = "pseudo",
5680 .match = pseudo_lld_bus_match,
5681 .probe = sdebug_driver_probe,
5682 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005683 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005684};