blob: afbbfaa20a3427e5301ae56e40088e15bb564004 [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 Gilbert773642d2016-04-25 12:16:28 -04009 * Copyright (C) 2001 - 2016 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>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050044
45#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090046
Martin K. Petersen44d92692009-10-15 14:45:27 -040047#include <asm/unaligned.h>
48
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090049#include <scsi/scsi.h>
50#include <scsi/scsi_cmnd.h>
51#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <scsi/scsi_host.h>
53#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090054#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040055#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040056#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Martin K. Petersenc6a44282009-01-04 03:08:19 -050058#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Douglas Gilbert773642d2016-04-25 12:16:28 -040061/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -040062#define SDEBUG_VERSION "1.86"
63static const char *sdebug_version_date = "20160430";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040064
65#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050067/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define NO_ADDITIONAL_SENSE 0x0
69#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050070#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040072#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050074#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040076#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040077#define UA_RESET_ASC 0x29
78#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050079#define TARGET_CHANGED_ASC 0x3f
80#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050081#define INSUFF_RES_ASC 0x55
82#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040083#define POWER_ON_RESET_ASCQ 0x0
84#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
85#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050086#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050088#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040089#define THRESHOLD_EXCEEDED 0x5d
90#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050091#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050092#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
93#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050095/* Additional Sense Code Qualifier (ASCQ) */
96#define ACK_NAK_TO 0x3
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098/* Default values for driver parameters */
99#define DEF_NUM_HOST 1
100#define DEF_NUM_TGTS 1
101#define DEF_MAX_LUNS 1
102/* With these defaults, this driver will make 1 host with 1 target
103 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
104 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500105#define DEF_ATO 1
Douglas Gilbertc2206092016-04-25 12:16:31 -0400106#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500108#define DEF_DIF 0
109#define DEF_DIX 0
110#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500112#define DEF_FAKE_RW 0
113#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400114#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500115#define DEF_LBPU 0
116#define DEF_LBPWS 0
117#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600118#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400120#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500121#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#define DEF_NUM_PARTS 0
123#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500124#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500125#define DEF_PHYSBLK_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400126#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200127#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400128#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500129#define DEF_SECTOR_SIZE 512
130#define DEF_UNMAP_ALIGNMENT 0
131#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400132#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
133#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500134#define DEF_VIRTUAL_GB 0
135#define DEF_VPD_USE_HOSTNO 1
136#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500137#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400138#define DEF_STATISTICS false
139#define DEF_SUBMIT_QUEUES 1
Douglas Gilbertc2206092016-04-25 12:16:31 -0400140#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400142#define SDEBUG_LUN_0_VAL 0
143
Douglas Gilbert773642d2016-04-25 12:16:28 -0400144/* bit mask values for sdebug_opts */
145#define SDEBUG_OPT_NOISE 1
146#define SDEBUG_OPT_MEDIUM_ERR 2
147#define SDEBUG_OPT_TIMEOUT 4
148#define SDEBUG_OPT_RECOVERED_ERR 8
149#define SDEBUG_OPT_TRANSPORT_ERR 16
150#define SDEBUG_OPT_DIF_ERR 32
151#define SDEBUG_OPT_DIX_ERR 64
152#define SDEBUG_OPT_MAC_TIMEOUT 128
153#define SDEBUG_OPT_SHORT_TRANSFER 0x100
154#define SDEBUG_OPT_Q_NOISE 0x200
155#define SDEBUG_OPT_ALL_TSF 0x400
156#define SDEBUG_OPT_RARE_TSF 0x800
157#define SDEBUG_OPT_N_WCE 0x1000
158#define SDEBUG_OPT_RESET_NOISE 0x2000
159#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
160#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
161 SDEBUG_OPT_RESET_NOISE)
162#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
163 SDEBUG_OPT_TRANSPORT_ERR | \
164 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
165 SDEBUG_OPT_SHORT_TRANSFER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400167 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400169 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500170 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400171 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 *
173 * When "every_nth" < 0 then after "- 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 _DEBUG_OPT_TRANSPORT_ERR is set.
179 * This will continue on every subsequent command until some other action
180 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
181 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 */
183
Douglas Gilbertfd321192016-04-25 12:16:33 -0400184/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400185 * priority order. In the subset implemented here lower numbers have higher
186 * priority. The UA numbers should be a sequence starting from 0 with
187 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
188#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
189#define SDEBUG_UA_BUS_RESET 1
190#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500191#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500192#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500193#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
194#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
195#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400196
Douglas Gilbert773642d2016-04-25 12:16:28 -0400197/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 * sector on read commands: */
199#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500200#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
203 * or "peripheral device" addressing (value 0) */
204#define SAM2_LUN_ADDRESS_METHOD 0
205
Douglas Gilbertc4837392016-05-06 00:40:26 -0400206/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
207 * (for response) per submit queue at one time. Can be reduced by max_queue
208 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
209 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
210 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
211 * but cannot exceed SDEBUG_CANQUEUE .
212 */
213#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
214#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400215#define DEF_CMD_PER_LUN 255
216
Douglas Gilbertfd321192016-04-25 12:16:33 -0400217#define F_D_IN 1
218#define F_D_OUT 2
219#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
220#define F_D_UNKN 8
221#define F_RL_WLUN_OK 0x10
222#define F_SKIP_UA 0x20
223#define F_DELAY_OVERR 0x40
224#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
225#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
226#define F_INV_OP 0x200
227#define F_FAKE_RW 0x400
228#define F_M_ACCESS 0x800 /* media access */
229
230#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
231#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
232#define FF_SA (F_SA_HIGH | F_SA_LOW)
233
234#define SDEBUG_MAX_PARTS 4
235
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400236#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400237
238
239struct sdebug_dev_info {
240 struct list_head dev_list;
241 unsigned int channel;
242 unsigned int target;
243 u64 lun;
244 struct sdebug_host_info *sdbg_host;
245 unsigned long uas_bm[1];
246 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400247 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400248 bool used;
249};
250
251struct sdebug_host_info {
252 struct list_head host_list;
253 struct Scsi_Host *shost;
254 struct device dev;
255 struct list_head dev_info_list;
256};
257
258#define to_sdebug_host(d) \
259 container_of(d, struct sdebug_host_info, dev)
260
261struct sdebug_defer {
262 struct hrtimer hrt;
263 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400264 int sqa_idx; /* index of sdebug_queue array */
265 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
266 int issuing_cpu;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400267};
268
269struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400270 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
271 * instance indicates this slot is in use.
272 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400273 struct sdebug_defer *sd_dp;
274 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400275 unsigned int inj_recovered:1;
276 unsigned int inj_transport:1;
277 unsigned int inj_dif:1;
278 unsigned int inj_dix:1;
279 unsigned int inj_short:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400280};
281
Douglas Gilbertc4837392016-05-06 00:40:26 -0400282struct sdebug_queue {
283 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
284 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
285 spinlock_t qc_lock;
286 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400287};
288
Douglas Gilbertc4837392016-05-06 00:40:26 -0400289static atomic_t sdebug_cmnd_count; /* number of incoming commands */
290static atomic_t sdebug_completions; /* count of deferred completions */
291static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
292static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
293
Douglas Gilbertfd321192016-04-25 12:16:33 -0400294struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400295 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
296 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400297 u8 opcode; /* if num_attached > 0, preferred */
298 u16 sa; /* service action */
299 u32 flags; /* OR-ed set of SDEB_F_* */
300 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
301 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
302 u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
303 /* ignore cdb bytes after position 15 */
304};
305
306/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500307enum sdeb_opcode_index {
308 SDEB_I_INVALID_OPCODE = 0,
309 SDEB_I_INQUIRY = 1,
310 SDEB_I_REPORT_LUNS = 2,
311 SDEB_I_REQUEST_SENSE = 3,
312 SDEB_I_TEST_UNIT_READY = 4,
313 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
314 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
315 SDEB_I_LOG_SENSE = 7,
316 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
317 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
318 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
319 SDEB_I_START_STOP = 11,
320 SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
321 SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
322 SDEB_I_MAINT_IN = 14,
323 SDEB_I_MAINT_OUT = 15,
324 SDEB_I_VERIFY = 16, /* 10 only */
325 SDEB_I_VARIABLE_LEN = 17,
326 SDEB_I_RESERVE = 18, /* 6, 10 */
327 SDEB_I_RELEASE = 19, /* 6, 10 */
328 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
329 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
330 SDEB_I_ATA_PT = 22, /* 12, 16 */
331 SDEB_I_SEND_DIAG = 23,
332 SDEB_I_UNMAP = 24,
333 SDEB_I_XDWRITEREAD = 25, /* 10 only */
334 SDEB_I_WRITE_BUFFER = 26,
335 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
336 SDEB_I_SYNC_CACHE = 28, /* 10 only */
337 SDEB_I_COMP_WRITE = 29,
338 SDEB_I_LAST_ELEMENT = 30, /* keep this last */
339};
340
Douglas Gilbertc4837392016-05-06 00:40:26 -0400341
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500342static const unsigned char opcode_ind_arr[256] = {
343/* 0x0; 0x0->0x1f: 6 byte cdbs */
344 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
345 0, 0, 0, 0,
346 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
347 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
348 SDEB_I_RELEASE,
349 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
350 SDEB_I_ALLOW_REMOVAL, 0,
351/* 0x20; 0x20->0x3f: 10 byte cdbs */
352 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
353 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
354 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
355 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
356/* 0x40; 0x40->0x5f: 10 byte cdbs */
357 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
358 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
359 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
360 SDEB_I_RELEASE,
361 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400362/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365 0, SDEB_I_VARIABLE_LEN,
366/* 0x80; 0x80->0x9f: 16 byte cdbs */
367 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
368 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
369 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
370 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
371/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
372 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
373 SDEB_I_MAINT_OUT, 0, 0, 0,
374 SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
375 0, 0, 0, 0,
376 0, 0, 0, 0, 0, 0, 0, 0,
377 0, 0, 0, 0, 0, 0, 0, 0,
378/* 0xc0; 0xc0->0xff: vendor specific */
379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
383};
384
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500385static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
386static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
387static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
388static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
389static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
390static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
391static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
392static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
393static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
394static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
395static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
396static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
397static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
398static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500399static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
400static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500401static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
402static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
403static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500404static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500405static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500406
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500407static const struct opcode_info_t msense_iarr[1] = {
408 {0, 0x1a, 0, F_D_IN, NULL, NULL,
409 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
410};
411
412static const struct opcode_info_t mselect_iarr[1] = {
413 {0, 0x15, 0, F_D_OUT, NULL, NULL,
414 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
415};
416
417static const struct opcode_info_t read_iarr[3] = {
418 {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
419 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
420 0, 0, 0, 0} },
421 {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
422 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
423 {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
424 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
425 0xc7, 0, 0, 0, 0} },
426};
427
428static const struct opcode_info_t write_iarr[3] = {
429 {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
430 {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
431 0, 0, 0, 0} },
432 {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
433 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
434 {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
435 {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
436 0xc7, 0, 0, 0, 0} },
437};
438
439static const struct opcode_info_t sa_in_iarr[1] = {
440 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
441 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
442 0xff, 0xff, 0xff, 0, 0xc7} },
443};
444
445static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
446 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
447 NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
448 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
449};
450
451static const struct opcode_info_t maint_in_iarr[2] = {
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500452 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500453 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
454 0xc7, 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500455 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500456 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
457 0, 0} },
458};
459
460static const struct opcode_info_t write_same_iarr[1] = {
461 {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
462 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
463 0xff, 0xff, 0xff, 0x1f, 0xc7} },
464};
465
466static const struct opcode_info_t reserve_iarr[1] = {
467 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
468 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
469};
470
471static const struct opcode_info_t release_iarr[1] = {
472 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
473 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
474};
475
476
477/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
478 * plus the terminating elements for logic that scans this table such as
479 * REPORT SUPPORTED OPERATION CODES. */
480static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
481/* 0 */
482 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
483 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
484 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
485 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
486 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
487 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
488 0, 0} },
489 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
490 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
491 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
492 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
493 {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
494 {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
495 0} },
496 {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
497 {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
498 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
499 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
500 0, 0, 0} },
501 {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
502 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
503 0, 0} },
504 {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
505 {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
506 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */
507/* 10 */
508 {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
509 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
510 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */
511 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
512 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
513 {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
514 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
515 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
516 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
517 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
518 {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
519 {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
520 0} },
521 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
522 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500523 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
524 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
525 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500526 {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
527 vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
528 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
529 {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
530 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
531 0} },
532 {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
533 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
534 0} },
535/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500536 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
537 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500538 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
539 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
540 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
541 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
542 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
543 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
544 {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
545 {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
546 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
547 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
548 0, 0, 0, 0, 0, 0} },
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500549 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
550 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
551 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500552 {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
553 write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
554 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
555 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
556 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
557 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500558 {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500559 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
560 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
561
562/* 30 */
563 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
564 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
565};
566
Douglas Gilbert773642d2016-04-25 12:16:28 -0400567static int sdebug_add_host = DEF_NUM_HOST;
568static int sdebug_ato = DEF_ATO;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400569static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400570static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
571static int sdebug_dif = DEF_DIF;
572static int sdebug_dix = DEF_DIX;
573static int sdebug_dsense = DEF_D_SENSE;
574static int sdebug_every_nth = DEF_EVERY_NTH;
575static int sdebug_fake_rw = DEF_FAKE_RW;
576static unsigned int sdebug_guard = DEF_GUARD;
577static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
578static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400579static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400580static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400581static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400582static int sdebug_no_lun_0 = DEF_NO_LUN_0;
583static int sdebug_no_uld;
584static int sdebug_num_parts = DEF_NUM_PARTS;
585static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
586static int sdebug_opt_blks = DEF_OPT_BLKS;
587static int sdebug_opts = DEF_OPTS;
588static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400589static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400590static int sdebug_scsi_level = DEF_SCSI_LEVEL;
591static int sdebug_sector_size = DEF_SECTOR_SIZE;
592static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
593static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
594static unsigned int sdebug_lbpu = DEF_LBPU;
595static unsigned int sdebug_lbpws = DEF_LBPWS;
596static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
597static unsigned int sdebug_lbprz = DEF_LBPRZ;
598static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
599static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
600static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
601static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
602static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
603static bool sdebug_removable = DEF_REMOVABLE;
604static bool sdebug_clustering;
605static bool sdebug_host_lock = DEF_HOST_LOCK;
606static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500607static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400608static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400609static bool have_dif_prot;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400610static bool sdebug_statistics = DEF_STATISTICS;
611static bool sdebug_mq_active;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400613static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614static sector_t sdebug_capacity; /* in sectors */
615
616/* old BIOS stuff, kernel may get rid of them but some mode sense pages
617 may still need them */
618static int sdebug_heads; /* heads per disk */
619static int sdebug_cylinders_per; /* cylinders per surface */
620static int sdebug_sectors_per; /* sectors per cylinder */
621
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622static LIST_HEAD(sdebug_host_list);
623static DEFINE_SPINLOCK(sdebug_host_list_lock);
624
Douglas Gilbertfd321192016-04-25 12:16:33 -0400625static unsigned char *fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900626static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400627static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Martin K. Petersen44d92692009-10-15 14:45:27 -0400629static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400630static int num_aborts;
631static int num_dev_resets;
632static int num_target_resets;
633static int num_bus_resets;
634static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500635static int dix_writes;
636static int dix_reads;
637static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Douglas Gilbertc4837392016-05-06 00:40:26 -0400639static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
640static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642static DEFINE_RWLOCK(atomic_rw);
643
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400644static char sdebug_proc_name[] = MY_NAME;
645static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647static struct bus_type pseudo_lld_bus;
648
649static struct device_driver sdebug_driverfs_driver = {
650 .name = sdebug_proc_name,
651 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652};
653
654static const int check_condition_result =
655 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
656
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500657static const int illegal_condition_result =
658 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
659
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400660static const int device_qfull_result =
661 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
662
Douglas Gilbertfd321192016-04-25 12:16:33 -0400663
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400664/* Only do the extra work involved in logical block provisioning if one or
665 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
666 * real reads and writes (i.e. not skipping them for speed).
667 */
668static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400669{
670 return 0 == sdebug_fake_rw &&
671 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
672}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400673
Akinobu Mita14faa942013-09-18 21:27:24 +0900674static void *fake_store(unsigned long long lba)
675{
676 lba = do_div(lba, sdebug_store_sectors);
677
Douglas Gilbert773642d2016-04-25 12:16:28 -0400678 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900679}
680
681static struct sd_dif_tuple *dif_store(sector_t sector)
682{
Arnd Bergmann49413112015-11-20 17:38:28 +0100683 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900684
685 return dif_storep + sector;
686}
687
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900688static void sdebug_max_tgts_luns(void)
689{
690 struct sdebug_host_info *sdbg_host;
691 struct Scsi_Host *hpnt;
692
693 spin_lock(&sdebug_host_list_lock);
694 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
695 hpnt = sdbg_host->shost;
696 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400697 (sdebug_num_tgts > hpnt->this_id))
698 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900699 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400700 hpnt->max_id = sdebug_num_tgts;
701 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300702 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900703 }
704 spin_unlock(&sdebug_host_list_lock);
705}
706
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500707enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
708
709/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400710static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
711 enum sdeb_cmd_data c_d,
712 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500713{
714 unsigned char *sbuff;
715 u8 sks[4];
716 int sl, asc;
717
718 sbuff = scp->sense_buffer;
719 if (!sbuff) {
720 sdev_printk(KERN_ERR, scp->device,
721 "%s: sense_buffer is NULL\n", __func__);
722 return;
723 }
724 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
725 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400726 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500727 memset(sks, 0, sizeof(sks));
728 sks[0] = 0x80;
729 if (c_d)
730 sks[0] |= 0x40;
731 if (in_bit >= 0) {
732 sks[0] |= 0x8;
733 sks[0] |= 0x7 & in_bit;
734 }
735 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400736 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500737 sl = sbuff[7] + 8;
738 sbuff[7] = sl;
739 sbuff[sl] = 0x2;
740 sbuff[sl + 1] = 0x6;
741 memcpy(sbuff + sl + 4, sks, 3);
742 } else
743 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400744 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500745 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
746 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
747 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
748}
749
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400750static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900751{
752 unsigned char *sbuff;
753
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400754 sbuff = scp->sense_buffer;
755 if (!sbuff) {
756 sdev_printk(KERN_ERR, scp->device,
757 "%s: sense_buffer is NULL\n", __func__);
758 return;
759 }
760 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900761
Douglas Gilbert773642d2016-04-25 12:16:28 -0400762 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900763
Douglas Gilbert773642d2016-04-25 12:16:28 -0400764 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400765 sdev_printk(KERN_INFO, scp->device,
766 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
767 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900768}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Douglas Gilbertfd321192016-04-25 12:16:33 -0400770static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500771{
772 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
773}
774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
776{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400777 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400778 if (0x1261 == cmd)
779 sdev_printk(KERN_INFO, dev,
780 "%s: BLKFLSBUF [0x1261]\n", __func__);
781 else if (0x5331 == cmd)
782 sdev_printk(KERN_INFO, dev,
783 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
784 __func__);
785 else
786 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
787 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 }
789 return -EINVAL;
790 /* return -ENOTTY; // correct return but upsets fdisk */
791}
792
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500793static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
794{
795 struct sdebug_host_info *sdhp;
796 struct sdebug_dev_info *dp;
797
798 spin_lock(&sdebug_host_list_lock);
799 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
800 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
801 if ((devip->sdbg_host == dp->sdbg_host) &&
802 (devip->target == dp->target))
803 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
804 }
805 }
806 spin_unlock(&sdebug_host_list_lock);
807}
808
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400809static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400811 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400812
813 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
814 if (k != SDEBUG_NUM_UAS) {
815 const char *cp = NULL;
816
817 switch (k) {
818 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400819 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
820 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400821 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400822 cp = "power on reset";
823 break;
824 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400825 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
826 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400827 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400828 cp = "bus reset";
829 break;
830 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400831 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
832 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400833 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400834 cp = "mode parameters changed";
835 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500836 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400837 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
838 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400839 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500840 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500841 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500842 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400843 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400844 TARGET_CHANGED_ASC,
845 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400846 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500847 cp = "microcode has been changed";
848 break;
849 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400850 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500851 TARGET_CHANGED_ASC,
852 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400853 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500854 cp = "microcode has been changed without reset";
855 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500856 case SDEBUG_UA_LUNS_CHANGED:
857 /*
858 * SPC-3 behavior is to report a UNIT ATTENTION with
859 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
860 * on the target, until a REPORT LUNS command is
861 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400862 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500863 * values as struct scsi_device->scsi_level.
864 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400865 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500866 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400867 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500868 TARGET_CHANGED_ASC,
869 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400870 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500871 cp = "reported luns data has changed";
872 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400873 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400874 pr_warn("unexpected unit attention code=%d\n", k);
875 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400876 cp = "unknown";
877 break;
878 }
879 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400880 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400881 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400882 "%s reports: Unit attention: %s\n",
883 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 return check_condition_result;
885 }
886 return 0;
887}
888
889/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900890static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 int arr_len)
892{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900893 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900894 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900896 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900898 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400899 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900900
901 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
902 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700903 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 return 0;
906}
907
908/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900909static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
910 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900912 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900914 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900916
917 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918}
919
920
921static const char * inq_vendor_id = "Linux ";
922static const char * inq_product_id = "scsi_debug ";
Douglas Gilbert773642d2016-04-25 12:16:28 -0400923static const char *inq_product_rev = "0186"; /* version less '.' */
924static const u64 naa5_comp_a = 0x5222222000000000ULL;
925static const u64 naa5_comp_b = 0x5333333000000000ULL;
926static const u64 naa5_comp_c = 0x5111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400928/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400929static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
930 int target_dev_id, int dev_id_num,
931 const char *dev_id_str,
932 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400934 int num, port_a;
935 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400937 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 /* T10 vendor identifier field format (faked) */
939 arr[0] = 0x2; /* ASCII */
940 arr[1] = 0x1;
941 arr[2] = 0x0;
942 memcpy(&arr[4], inq_vendor_id, 8);
943 memcpy(&arr[12], inq_product_id, 16);
944 memcpy(&arr[28], dev_id_str, dev_id_str_len);
945 num = 8 + 16 + dev_id_str_len;
946 arr[3] = num;
947 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400948 if (dev_id_num >= 0) {
949 /* NAA-5, Logical unit identifier (binary) */
950 arr[num++] = 0x1; /* binary (not necessarily sas) */
951 arr[num++] = 0x3; /* PIV=0, lu, naa */
952 arr[num++] = 0x0;
953 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400954 put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
955 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400956 /* Target relative port number */
957 arr[num++] = 0x61; /* proto=sas, binary */
958 arr[num++] = 0x94; /* PIV=1, target port, rel port */
959 arr[num++] = 0x0; /* reserved */
960 arr[num++] = 0x4; /* length */
961 arr[num++] = 0x0; /* reserved */
962 arr[num++] = 0x0; /* reserved */
963 arr[num++] = 0x0;
964 arr[num++] = 0x1; /* relative port A */
965 }
966 /* NAA-5, Target port identifier */
967 arr[num++] = 0x61; /* proto=sas, binary */
968 arr[num++] = 0x93; /* piv=1, target port, naa */
969 arr[num++] = 0x0;
970 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400971 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
972 num += 8;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200973 /* NAA-5, Target port group identifier */
974 arr[num++] = 0x61; /* proto=sas, binary */
975 arr[num++] = 0x95; /* piv=1, target port group id */
976 arr[num++] = 0x0;
977 arr[num++] = 0x4;
978 arr[num++] = 0;
979 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400980 put_unaligned_be16(port_group_id, arr + num);
981 num += 2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400982 /* NAA-5, Target device identifier */
983 arr[num++] = 0x61; /* proto=sas, binary */
984 arr[num++] = 0xa3; /* piv=1, target device, naa */
985 arr[num++] = 0x0;
986 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400987 put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
988 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400989 /* SCSI name string: Target device identifier */
990 arr[num++] = 0x63; /* proto=sas, UTF-8 */
991 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
992 arr[num++] = 0x0;
993 arr[num++] = 24;
994 memcpy(arr + num, "naa.52222220", 12);
995 num += 12;
996 snprintf(b, sizeof(b), "%08X", target_dev_id);
997 memcpy(arr + num, b, 8);
998 num += 8;
999 memset(arr + num, 0, 4);
1000 num += 4;
1001 return num;
1002}
1003
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001004static unsigned char vpd84_data[] = {
1005/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1006 0x22,0x22,0x22,0x0,0xbb,0x1,
1007 0x22,0x22,0x22,0x0,0xbb,0x2,
1008};
1009
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001010/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001011static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001012{
1013 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1014 return sizeof(vpd84_data);
1015}
1016
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001017/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001018static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001019{
1020 int num = 0;
1021 const char * na1 = "https://www.kernel.org/config";
1022 const char * na2 = "http://www.kernel.org/log";
1023 int plen, olen;
1024
1025 arr[num++] = 0x1; /* lu, storage config */
1026 arr[num++] = 0x0; /* reserved */
1027 arr[num++] = 0x0;
1028 olen = strlen(na1);
1029 plen = olen + 1;
1030 if (plen % 4)
1031 plen = ((plen / 4) + 1) * 4;
1032 arr[num++] = plen; /* length, null termianted, padded */
1033 memcpy(arr + num, na1, olen);
1034 memset(arr + num + olen, 0, plen - olen);
1035 num += plen;
1036
1037 arr[num++] = 0x4; /* lu, logging */
1038 arr[num++] = 0x0; /* reserved */
1039 arr[num++] = 0x0;
1040 olen = strlen(na2);
1041 plen = olen + 1;
1042 if (plen % 4)
1043 plen = ((plen / 4) + 1) * 4;
1044 arr[num++] = plen; /* length, null terminated, padded */
1045 memcpy(arr + num, na2, olen);
1046 memset(arr + num + olen, 0, plen - olen);
1047 num += plen;
1048
1049 return num;
1050}
1051
1052/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001053static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001054{
1055 int num = 0;
1056 int port_a, port_b;
1057
1058 port_a = target_dev_id + 1;
1059 port_b = port_a + 1;
1060 arr[num++] = 0x0; /* reserved */
1061 arr[num++] = 0x0; /* reserved */
1062 arr[num++] = 0x0;
1063 arr[num++] = 0x1; /* relative port 1 (primary) */
1064 memset(arr + num, 0, 6);
1065 num += 6;
1066 arr[num++] = 0x0;
1067 arr[num++] = 12; /* length tp descriptor */
1068 /* naa-5 target port identifier (A) */
1069 arr[num++] = 0x61; /* proto=sas, binary */
1070 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1071 arr[num++] = 0x0; /* reserved */
1072 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001073 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1074 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001075 arr[num++] = 0x0; /* reserved */
1076 arr[num++] = 0x0; /* reserved */
1077 arr[num++] = 0x0;
1078 arr[num++] = 0x2; /* relative port 2 (secondary) */
1079 memset(arr + num, 0, 6);
1080 num += 6;
1081 arr[num++] = 0x0;
1082 arr[num++] = 12; /* length tp descriptor */
1083 /* naa-5 target port identifier (B) */
1084 arr[num++] = 0x61; /* proto=sas, binary */
1085 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1086 arr[num++] = 0x0; /* reserved */
1087 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001088 put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1089 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001090
1091 return num;
1092}
1093
1094
1095static unsigned char vpd89_data[] = {
1096/* from 4th byte */ 0,0,0,0,
1097'l','i','n','u','x',' ',' ',' ',
1098'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1099'1','2','3','4',
11000x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
11010xec,0,0,0,
11020x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
11030,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
11040x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
11050x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
11060x53,0x41,
11070x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11080x20,0x20,
11090x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11100x10,0x80,
11110,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
11120x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
11130x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
11140,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
11150x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
11160x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11170,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
11180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11210x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11220,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11230xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11240,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
11250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11360,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1137};
1138
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001139/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001140static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001141{
1142 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1143 return sizeof(vpd89_data);
1144}
1145
1146
1147static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001148 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1149 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1150 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1151 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001152};
1153
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001154/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001155static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001156{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001157 unsigned int gran;
1158
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001159 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001160
1161 /* Optimal transfer length granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001162 gran = 1 << sdebug_physblk_exp;
1163 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001164
1165 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001166 if (sdebug_store_sectors > 0x400)
1167 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001168
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001169 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001170 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001171
Douglas Gilbert773642d2016-04-25 12:16:28 -04001172 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001173 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001174 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001175
1176 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001177 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001178 }
1179
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001180 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001181 if (sdebug_unmap_alignment) {
1182 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001183 arr[28] |= 0x80; /* UGAVALID */
1184 }
1185
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001186 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001187 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001188
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001189 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001190 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001191
1192 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001193
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001194 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195}
1196
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001197/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001198static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001199{
1200 memset(arr, 0, 0x3c);
1201 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001202 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1203 arr[2] = 0;
1204 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001205
1206 return 0x3c;
1207}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001209/* Logical block provisioning VPD page (SBC-4) */
1210static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001211{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001212 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001213 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001214 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001215 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001216 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001217 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001218 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001219 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001220 if (sdebug_lbprz && scsi_debug_lbp())
1221 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1222 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1223 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1224 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001225 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001226}
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001229#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001231static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232{
1233 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001234 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001235 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001236 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001237 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Douglas Gilbert773642d2016-04-25 12:16:28 -04001239 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001240 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1241 if (! arr)
1242 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001243 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001244 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001245 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001246 pq_pdt = TYPE_WLUN; /* present, wlun */
1247 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1248 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001249 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001250 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 arr[0] = pq_pdt;
1252 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001253 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001254 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 return check_condition_result;
1256 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001257 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001258 char lu_id_str[6];
1259 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001261 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1262 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001263 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001264 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001265 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001266 (devip->target * 1000) + devip->lun);
1267 target_dev_id = ((host_no + 1) * 2000) +
1268 (devip->target * 1000) - 3;
1269 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001271 arr[1] = cmd[2]; /*sanity */
1272 n = 4;
1273 arr[n++] = 0x0; /* this page */
1274 arr[n++] = 0x80; /* unit serial number */
1275 arr[n++] = 0x83; /* device identification */
1276 arr[n++] = 0x84; /* software interface ident. */
1277 arr[n++] = 0x85; /* management network addresses */
1278 arr[n++] = 0x86; /* extended inquiry */
1279 arr[n++] = 0x87; /* mode page policy */
1280 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001281 if (is_disk) { /* SBC only */
1282 arr[n++] = 0x89; /* ATA information */
1283 arr[n++] = 0xb0; /* Block limits */
1284 arr[n++] = 0xb1; /* Block characteristics */
1285 arr[n++] = 0xb2; /* Logical Block Prov */
1286 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001287 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001289 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001291 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001293 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001294 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1295 target_dev_id, lu_id_num,
1296 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001297 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1298 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001299 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001300 } else if (0x85 == cmd[2]) { /* Management network addresses */
1301 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001302 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001303 } else if (0x86 == cmd[2]) { /* extended inquiry */
1304 arr[1] = cmd[2]; /*sanity */
1305 arr[3] = 0x3c; /* number of following entries */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001306 if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001307 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001308 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001309 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1310 else
1311 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001312 arr[5] = 0x7; /* head of q, ordered + simple q's */
1313 } else if (0x87 == cmd[2]) { /* mode page policy */
1314 arr[1] = cmd[2]; /*sanity */
1315 arr[3] = 0x8; /* number of following entries */
1316 arr[4] = 0x2; /* disconnect-reconnect mp */
1317 arr[6] = 0x80; /* mlus, shared */
1318 arr[8] = 0x18; /* protocol specific lu */
1319 arr[10] = 0x82; /* mlus, per initiator port */
1320 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1321 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001322 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1323 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001324 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001325 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001326 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001327 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001328 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001329 arr[3] = inquiry_vpd_b0(&arr[4]);
1330 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001331 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001332 arr[3] = inquiry_vpd_b1(&arr[4]);
1333 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001334 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001335 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001337 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001338 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 return check_condition_result;
1340 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001341 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001342 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001343 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001344 kfree(arr);
1345 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 }
1347 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001348 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1349 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 arr[3] = 2; /* response_data_format==2 */
1351 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001352 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001353 if (sdebug_vpd_use_hostno == 0)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001354 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001355 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001357 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 memcpy(&arr[8], inq_vendor_id, 8);
1359 memcpy(&arr[16], inq_product_id, 16);
1360 memcpy(&arr[32], inq_product_rev, 4);
1361 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001362 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1363 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001364 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001365 if (is_disk) { /* SBC-4 no version claimed */
1366 put_unaligned_be16(0x600, arr + n);
1367 n += 2;
1368 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1369 put_unaligned_be16(0x525, arr + n);
1370 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001372 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001373 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001375 kfree(arr);
1376 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377}
1378
Douglas Gilbertfd321192016-04-25 12:16:33 -04001379static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1380 0, 0, 0x0, 0x0};
1381
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382static int resp_requests(struct scsi_cmnd * scp,
1383 struct sdebug_dev_info * devip)
1384{
1385 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001386 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001387 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001388 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 int len = 18;
1390
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001391 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001392 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001393 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001394 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001395 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001396 arr[0] = 0x72;
1397 arr[1] = 0x0; /* NO_SENSE in sense_key */
1398 arr[2] = THRESHOLD_EXCEEDED;
1399 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001400 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001401 } else {
1402 arr[0] = 0x70;
1403 arr[2] = 0x0; /* NO_SENSE in sense_key */
1404 arr[7] = 0xa; /* 18 byte sense buffer */
1405 arr[12] = THRESHOLD_EXCEEDED;
1406 arr[13] = 0xff; /* TEST set and MRIE==6 */
1407 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001408 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001409 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001410 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001411 ; /* have sense and formats match */
1412 else if (arr[0] <= 0x70) {
1413 if (dsense) {
1414 memset(arr, 0, 8);
1415 arr[0] = 0x72;
1416 len = 8;
1417 } else {
1418 memset(arr, 0, 18);
1419 arr[0] = 0x70;
1420 arr[7] = 0xa;
1421 }
1422 } else if (dsense) {
1423 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001424 arr[0] = 0x72;
1425 arr[1] = sbuff[2]; /* sense key */
1426 arr[2] = sbuff[12]; /* asc */
1427 arr[3] = sbuff[13]; /* ascq */
1428 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001429 } else {
1430 memset(arr, 0, 18);
1431 arr[0] = 0x70;
1432 arr[2] = sbuff[1];
1433 arr[7] = 0xa;
1434 arr[12] = sbuff[1];
1435 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001436 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001437
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001438 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001439 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 return fill_from_dev_buffer(scp, arr, len);
1441}
1442
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001443static int resp_start_stop(struct scsi_cmnd * scp,
1444 struct sdebug_dev_info * devip)
1445{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001446 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001447 int power_cond, stop;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001448
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001449 power_cond = (cmd[4] & 0xf0) >> 4;
1450 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001451 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001452 return check_condition_result;
1453 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001454 stop = !(cmd[4] & 1);
1455 atomic_xchg(&devip->stopped, stop);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001456 return 0;
1457}
1458
FUJITA Tomonori28898872008-03-30 00:59:55 +09001459static sector_t get_sdebug_capacity(void)
1460{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001461 static const unsigned int gibibyte = 1073741824;
1462
1463 if (sdebug_virtual_gb > 0)
1464 return (sector_t)sdebug_virtual_gb *
1465 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001466 else
1467 return sdebug_store_sectors;
1468}
1469
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470#define SDEBUG_READCAP_ARR_SZ 8
1471static int resp_readcap(struct scsi_cmnd * scp,
1472 struct sdebug_dev_info * devip)
1473{
1474 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001475 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001477 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001478 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001480 if (sdebug_capacity < 0xffffffff) {
1481 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001482 put_unaligned_be32(capac, arr + 0);
1483 } else
1484 put_unaligned_be32(0xffffffff, arr + 0);
1485 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1487}
1488
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001489#define SDEBUG_READCAP16_ARR_SZ 32
1490static int resp_readcap16(struct scsi_cmnd * scp,
1491 struct sdebug_dev_info * devip)
1492{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001493 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001494 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001495 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496
Douglas Gilbert773642d2016-04-25 12:16:28 -04001497 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001498 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001499 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001500 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001501 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1502 put_unaligned_be32(sdebug_sector_size, arr + 8);
1503 arr[13] = sdebug_physblk_exp & 0xf;
1504 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001505
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001506 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001507 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001508 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1509 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1510 * in the wider field maps to 0 in this field.
1511 */
1512 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1513 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001514 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001515
Douglas Gilbert773642d2016-04-25 12:16:28 -04001516 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001517
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001518 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001519 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001520 arr[12] |= 1; /* PROT_EN */
1521 }
1522
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001523 return fill_from_dev_buffer(scp, arr,
1524 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1525}
1526
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001527#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1528
1529static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1530 struct sdebug_dev_info * devip)
1531{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001532 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001533 unsigned char * arr;
1534 int host_no = devip->sdbg_host->shost->host_no;
1535 int n, ret, alen, rlen;
1536 int port_group_a, port_group_b, port_a, port_b;
1537
Douglas Gilbert773642d2016-04-25 12:16:28 -04001538 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001539 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1540 if (! arr)
1541 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001542 /*
1543 * EVPD page 0x88 states we have two ports, one
1544 * real and a fake port with no device connected.
1545 * So we create two port groups with one port each
1546 * and set the group with port B to unavailable.
1547 */
1548 port_a = 0x1; /* relative port A */
1549 port_b = 0x2; /* relative port B */
1550 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001551 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001552 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001553 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001554
1555 /*
1556 * The asymmetric access state is cycled according to the host_id.
1557 */
1558 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001559 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001560 arr[n++] = host_no % 3; /* Asymm access state */
1561 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001562 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001563 arr[n++] = 0x0; /* Active/Optimized path */
1564 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001565 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001566 put_unaligned_be16(port_group_a, arr + n);
1567 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001568 arr[n++] = 0; /* Reserved */
1569 arr[n++] = 0; /* Status code */
1570 arr[n++] = 0; /* Vendor unique */
1571 arr[n++] = 0x1; /* One port per group */
1572 arr[n++] = 0; /* Reserved */
1573 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001574 put_unaligned_be16(port_a, arr + n);
1575 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001576 arr[n++] = 3; /* Port unavailable */
1577 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001578 put_unaligned_be16(port_group_b, arr + n);
1579 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001580 arr[n++] = 0; /* Reserved */
1581 arr[n++] = 0; /* Status code */
1582 arr[n++] = 0; /* Vendor unique */
1583 arr[n++] = 0x1; /* One port per group */
1584 arr[n++] = 0; /* Reserved */
1585 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001586 put_unaligned_be16(port_b, arr + n);
1587 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001588
1589 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001590 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001591
1592 /*
1593 * Return the smallest value of either
1594 * - The allocated length
1595 * - The constructed command length
1596 * - The maximum array size
1597 */
1598 rlen = min(alen,n);
1599 ret = fill_from_dev_buffer(scp, arr,
1600 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1601 kfree(arr);
1602 return ret;
1603}
1604
Douglas Gilbertfd321192016-04-25 12:16:33 -04001605static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1606 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001607{
1608 bool rctd;
1609 u8 reporting_opts, req_opcode, sdeb_i, supp;
1610 u16 req_sa, u;
1611 u32 alloc_len, a_len;
1612 int k, offset, len, errsts, count, bump, na;
1613 const struct opcode_info_t *oip;
1614 const struct opcode_info_t *r_oip;
1615 u8 *arr;
1616 u8 *cmd = scp->cmnd;
1617
1618 rctd = !!(cmd[2] & 0x80);
1619 reporting_opts = cmd[2] & 0x7;
1620 req_opcode = cmd[3];
1621 req_sa = get_unaligned_be16(cmd + 4);
1622 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001623 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001624 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1625 return check_condition_result;
1626 }
1627 if (alloc_len > 8192)
1628 a_len = 8192;
1629 else
1630 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001631 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001632 if (NULL == arr) {
1633 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1634 INSUFF_RES_ASCQ);
1635 return check_condition_result;
1636 }
1637 switch (reporting_opts) {
1638 case 0: /* all commands */
1639 /* count number of commands */
1640 for (count = 0, oip = opcode_info_arr;
1641 oip->num_attached != 0xff; ++oip) {
1642 if (F_INV_OP & oip->flags)
1643 continue;
1644 count += (oip->num_attached + 1);
1645 }
1646 bump = rctd ? 20 : 8;
1647 put_unaligned_be32(count * bump, arr);
1648 for (offset = 4, oip = opcode_info_arr;
1649 oip->num_attached != 0xff && offset < a_len; ++oip) {
1650 if (F_INV_OP & oip->flags)
1651 continue;
1652 na = oip->num_attached;
1653 arr[offset] = oip->opcode;
1654 put_unaligned_be16(oip->sa, arr + offset + 2);
1655 if (rctd)
1656 arr[offset + 5] |= 0x2;
1657 if (FF_SA & oip->flags)
1658 arr[offset + 5] |= 0x1;
1659 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1660 if (rctd)
1661 put_unaligned_be16(0xa, arr + offset + 8);
1662 r_oip = oip;
1663 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1664 if (F_INV_OP & oip->flags)
1665 continue;
1666 offset += bump;
1667 arr[offset] = oip->opcode;
1668 put_unaligned_be16(oip->sa, arr + offset + 2);
1669 if (rctd)
1670 arr[offset + 5] |= 0x2;
1671 if (FF_SA & oip->flags)
1672 arr[offset + 5] |= 0x1;
1673 put_unaligned_be16(oip->len_mask[0],
1674 arr + offset + 6);
1675 if (rctd)
1676 put_unaligned_be16(0xa,
1677 arr + offset + 8);
1678 }
1679 oip = r_oip;
1680 offset += bump;
1681 }
1682 break;
1683 case 1: /* one command: opcode only */
1684 case 2: /* one command: opcode plus service action */
1685 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1686 sdeb_i = opcode_ind_arr[req_opcode];
1687 oip = &opcode_info_arr[sdeb_i];
1688 if (F_INV_OP & oip->flags) {
1689 supp = 1;
1690 offset = 4;
1691 } else {
1692 if (1 == reporting_opts) {
1693 if (FF_SA & oip->flags) {
1694 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1695 2, 2);
1696 kfree(arr);
1697 return check_condition_result;
1698 }
1699 req_sa = 0;
1700 } else if (2 == reporting_opts &&
1701 0 == (FF_SA & oip->flags)) {
1702 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1703 kfree(arr); /* point at requested sa */
1704 return check_condition_result;
1705 }
1706 if (0 == (FF_SA & oip->flags) &&
1707 req_opcode == oip->opcode)
1708 supp = 3;
1709 else if (0 == (FF_SA & oip->flags)) {
1710 na = oip->num_attached;
1711 for (k = 0, oip = oip->arrp; k < na;
1712 ++k, ++oip) {
1713 if (req_opcode == oip->opcode)
1714 break;
1715 }
1716 supp = (k >= na) ? 1 : 3;
1717 } else if (req_sa != oip->sa) {
1718 na = oip->num_attached;
1719 for (k = 0, oip = oip->arrp; k < na;
1720 ++k, ++oip) {
1721 if (req_sa == oip->sa)
1722 break;
1723 }
1724 supp = (k >= na) ? 1 : 3;
1725 } else
1726 supp = 3;
1727 if (3 == supp) {
1728 u = oip->len_mask[0];
1729 put_unaligned_be16(u, arr + 2);
1730 arr[4] = oip->opcode;
1731 for (k = 1; k < u; ++k)
1732 arr[4 + k] = (k < 16) ?
1733 oip->len_mask[k] : 0xff;
1734 offset = 4 + u;
1735 } else
1736 offset = 4;
1737 }
1738 arr[1] = (rctd ? 0x80 : 0) | supp;
1739 if (rctd) {
1740 put_unaligned_be16(0xa, arr + offset);
1741 offset += 12;
1742 }
1743 break;
1744 default:
1745 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1746 kfree(arr);
1747 return check_condition_result;
1748 }
1749 offset = (offset < a_len) ? offset : a_len;
1750 len = (offset < alloc_len) ? offset : alloc_len;
1751 errsts = fill_from_dev_buffer(scp, arr, len);
1752 kfree(arr);
1753 return errsts;
1754}
1755
Douglas Gilbertfd321192016-04-25 12:16:33 -04001756static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1757 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001758{
1759 bool repd;
1760 u32 alloc_len, len;
1761 u8 arr[16];
1762 u8 *cmd = scp->cmnd;
1763
1764 memset(arr, 0, sizeof(arr));
1765 repd = !!(cmd[2] & 0x80);
1766 alloc_len = get_unaligned_be32(cmd + 6);
1767 if (alloc_len < 4) {
1768 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1769 return check_condition_result;
1770 }
1771 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1772 arr[1] = 0x1; /* ITNRS */
1773 if (repd) {
1774 arr[3] = 0xc;
1775 len = 16;
1776 } else
1777 len = 4;
1778
1779 len = (len < alloc_len) ? len : alloc_len;
1780 return fill_from_dev_buffer(scp, arr, len);
1781}
1782
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783/* <<Following mode page info copied from ST318451LW>> */
1784
1785static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1786{ /* Read-Write Error Recovery page for mode_sense */
1787 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1788 5, 0, 0xff, 0xff};
1789
1790 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1791 if (1 == pcontrol)
1792 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1793 return sizeof(err_recov_pg);
1794}
1795
1796static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1797{ /* Disconnect-Reconnect page for mode_sense */
1798 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1799 0, 0, 0, 0, 0, 0, 0, 0};
1800
1801 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1802 if (1 == pcontrol)
1803 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1804 return sizeof(disconnect_pg);
1805}
1806
1807static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1808{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001809 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1810 0, 0, 0, 0, 0, 0, 0, 0,
1811 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Martin K. Petersen597136a2008-06-05 00:12:59 -04001813 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001814 put_unaligned_be16(sdebug_sectors_per, p + 10);
1815 put_unaligned_be16(sdebug_sector_size, p + 12);
1816 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001817 p[20] |= 0x20; /* should agree with INQUIRY */
1818 if (1 == pcontrol)
1819 memset(p + 2, 0, sizeof(format_pg) - 2);
1820 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821}
1822
Douglas Gilbertfd321192016-04-25 12:16:33 -04001823static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1824 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1825 0, 0, 0, 0};
1826
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1828{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001829 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1830 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1831 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1833
Douglas Gilbert773642d2016-04-25 12:16:28 -04001834 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001835 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 memcpy(p, caching_pg, sizeof(caching_pg));
1837 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001838 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1839 else if (2 == pcontrol)
1840 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 return sizeof(caching_pg);
1842}
1843
Douglas Gilbertfd321192016-04-25 12:16:33 -04001844static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1845 0, 0, 0x2, 0x4b};
1846
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1848{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001849 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1850 0, 0, 0, 0};
1851 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 0, 0, 0x2, 0x4b};
1853
Douglas Gilbert773642d2016-04-25 12:16:28 -04001854 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001856 else
1857 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001858
Douglas Gilbert773642d2016-04-25 12:16:28 -04001859 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001860 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1863 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001864 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1865 else if (2 == pcontrol)
1866 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 return sizeof(ctrl_m_pg);
1868}
1869
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001870
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1872{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001873 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1874 0, 0, 0x0, 0x0};
1875 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1876 0, 0, 0x0, 0x0};
1877
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1879 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001880 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1881 else if (2 == pcontrol)
1882 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 return sizeof(iec_m_pg);
1884}
1885
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001886static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1887{ /* SAS SSP mode page - short format for mode_sense */
1888 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1889 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1890
1891 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1892 if (1 == pcontrol)
1893 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1894 return sizeof(sas_sf_m_pg);
1895}
1896
1897
1898static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1899 int target_dev_id)
1900{ /* SAS phy control and discover mode page for mode_sense */
1901 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1902 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001903 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1904 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001905 0x2, 0, 0, 0, 0, 0, 0, 0,
1906 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1907 0, 0, 0, 0, 0, 0, 0, 0,
1908 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001909 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1910 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001911 0x3, 0, 0, 0, 0, 0, 0, 0,
1912 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1913 0, 0, 0, 0, 0, 0, 0, 0,
1914 };
1915 int port_a, port_b;
1916
Douglas Gilbert773642d2016-04-25 12:16:28 -04001917 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1918 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1919 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1920 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001921 port_a = target_dev_id + 1;
1922 port_b = port_a + 1;
1923 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001924 put_unaligned_be32(port_a, p + 20);
1925 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001926 if (1 == pcontrol)
1927 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1928 return sizeof(sas_pcd_m_pg);
1929}
1930
1931static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1932{ /* SAS SSP shared protocol specific port mode subpage */
1933 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1934 0, 0, 0, 0, 0, 0, 0, 0,
1935 };
1936
1937 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1938 if (1 == pcontrol)
1939 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1940 return sizeof(sas_sha_m_pg);
1941}
1942
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943#define SDEBUG_MAX_MSENSE_SZ 256
1944
Douglas Gilbertfd321192016-04-25 12:16:33 -04001945static int resp_mode_sense(struct scsi_cmnd *scp,
1946 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947{
Douglas Gilbert23183912006-09-16 20:30:47 -04001948 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001950 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001951 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 unsigned char * ap;
1953 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001954 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001955 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001957 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 pcontrol = (cmd[2] & 0xc0) >> 6;
1959 pcode = cmd[2] & 0x3f;
1960 subpcode = cmd[3];
1961 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001962 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
1963 is_disk = (sdebug_ptype == TYPE_DISK);
1964 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04001965 bd_len = llbaa ? 16 : 8;
1966 else
1967 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001968 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1970 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001971 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 return check_condition_result;
1973 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001974 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1975 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001976 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001977 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001978 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04001979 else
1980 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 if (msense_6) {
1982 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001983 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 offset = 4;
1985 } else {
1986 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001987 if (16 == bd_len)
1988 arr[4] = 0x1; /* set LONGLBA bit */
1989 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 offset = 8;
1991 }
1992 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001993 if ((bd_len > 0) && (!sdebug_capacity))
1994 sdebug_capacity = get_sdebug_capacity();
1995
Douglas Gilbert23183912006-09-16 20:30:47 -04001996 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001997 if (sdebug_capacity > 0xfffffffe)
1998 put_unaligned_be32(0xffffffff, ap + 0);
1999 else
2000 put_unaligned_be32(sdebug_capacity, ap + 0);
2001 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002002 offset += bd_len;
2003 ap = arr + offset;
2004 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002005 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2006 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002007 offset += bd_len;
2008 ap = arr + offset;
2009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002011 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2012 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002013 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 return check_condition_result;
2015 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002016 bad_pcode = false;
2017
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 switch (pcode) {
2019 case 0x1: /* Read-Write error recovery page, direct access */
2020 len = resp_err_recov_pg(ap, pcontrol, target);
2021 offset += len;
2022 break;
2023 case 0x2: /* Disconnect-Reconnect page, all devices */
2024 len = resp_disconnect_pg(ap, pcontrol, target);
2025 offset += len;
2026 break;
2027 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002028 if (is_disk) {
2029 len = resp_format_pg(ap, pcontrol, target);
2030 offset += len;
2031 } else
2032 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 break;
2034 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002035 if (is_disk) {
2036 len = resp_caching_pg(ap, pcontrol, target);
2037 offset += len;
2038 } else
2039 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 break;
2041 case 0xa: /* Control Mode page, all devices */
2042 len = resp_ctrl_m_pg(ap, pcontrol, target);
2043 offset += len;
2044 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002045 case 0x19: /* if spc==1 then sas phy, control+discover */
2046 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002047 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002048 return check_condition_result;
2049 }
2050 len = 0;
2051 if ((0x0 == subpcode) || (0xff == subpcode))
2052 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2053 if ((0x1 == subpcode) || (0xff == subpcode))
2054 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2055 target_dev_id);
2056 if ((0x2 == subpcode) || (0xff == subpcode))
2057 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2058 offset += len;
2059 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 case 0x1c: /* Informational Exceptions Mode page, all devices */
2061 len = resp_iec_m_pg(ap, pcontrol, target);
2062 offset += len;
2063 break;
2064 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002065 if ((0 == subpcode) || (0xff == subpcode)) {
2066 len = resp_err_recov_pg(ap, pcontrol, target);
2067 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002068 if (is_disk) {
2069 len += resp_format_pg(ap + len, pcontrol,
2070 target);
2071 len += resp_caching_pg(ap + len, pcontrol,
2072 target);
2073 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002074 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2075 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2076 if (0xff == subpcode) {
2077 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2078 target, target_dev_id);
2079 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2080 }
2081 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002082 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002083 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002084 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002085 return check_condition_result;
2086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 break;
2088 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002089 bad_pcode = true;
2090 break;
2091 }
2092 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002093 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 return check_condition_result;
2095 }
2096 if (msense_6)
2097 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002098 else
2099 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2101}
2102
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002103#define SDEBUG_MAX_MSELECT_SZ 512
2104
Douglas Gilbertfd321192016-04-25 12:16:33 -04002105static int resp_mode_select(struct scsi_cmnd *scp,
2106 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002107{
2108 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002109 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002110 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002111 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002112 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002113
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002114 memset(arr, 0, sizeof(arr));
2115 pf = cmd[1] & 0x10;
2116 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002117 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002118 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002119 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002120 return check_condition_result;
2121 }
2122 res = fetch_to_dev_buffer(scp, arr, param_len);
2123 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002124 return DID_ERROR << 16;
2125 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002126 sdev_printk(KERN_INFO, scp->device,
2127 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2128 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002129 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2130 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002131 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002132 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002133 return check_condition_result;
2134 }
2135 off = bd_len + (mselect6 ? 4 : 8);
2136 mpage = arr[off] & 0x3f;
2137 ps = !!(arr[off] & 0x80);
2138 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002139 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002140 return check_condition_result;
2141 }
2142 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002143 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002144 (arr[off + 1] + 2);
2145 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002146 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002147 PARAMETER_LIST_LENGTH_ERR, 0);
2148 return check_condition_result;
2149 }
2150 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002151 case 0x8: /* Caching Mode page */
2152 if (caching_pg[1] == arr[off + 1]) {
2153 memcpy(caching_pg + 2, arr + off + 2,
2154 sizeof(caching_pg) - 2);
2155 goto set_mode_changed_ua;
2156 }
2157 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002158 case 0xa: /* Control Mode page */
2159 if (ctrl_m_pg[1] == arr[off + 1]) {
2160 memcpy(ctrl_m_pg + 2, arr + off + 2,
2161 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002162 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002163 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002164 }
2165 break;
2166 case 0x1c: /* Informational Exceptions Mode page */
2167 if (iec_m_pg[1] == arr[off + 1]) {
2168 memcpy(iec_m_pg + 2, arr + off + 2,
2169 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002170 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002171 }
2172 break;
2173 default:
2174 break;
2175 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002176 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002177 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002178set_mode_changed_ua:
2179 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2180 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002181}
2182
2183static int resp_temp_l_pg(unsigned char * arr)
2184{
2185 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2186 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2187 };
2188
2189 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2190 return sizeof(temp_l_pg);
2191}
2192
2193static int resp_ie_l_pg(unsigned char * arr)
2194{
2195 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2196 };
2197
2198 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2199 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2200 arr[4] = THRESHOLD_EXCEEDED;
2201 arr[5] = 0xff;
2202 }
2203 return sizeof(ie_l_pg);
2204}
2205
2206#define SDEBUG_MAX_LSENSE_SZ 512
2207
2208static int resp_log_sense(struct scsi_cmnd * scp,
2209 struct sdebug_dev_info * devip)
2210{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002211 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002212 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002213 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002214
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002215 memset(arr, 0, sizeof(arr));
2216 ppc = cmd[1] & 0x2;
2217 sp = cmd[1] & 0x1;
2218 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002219 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002220 return check_condition_result;
2221 }
2222 pcontrol = (cmd[2] & 0xc0) >> 6;
2223 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002224 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002225 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002226 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002227 if (0 == subpcode) {
2228 switch (pcode) {
2229 case 0x0: /* Supported log pages log page */
2230 n = 4;
2231 arr[n++] = 0x0; /* this page */
2232 arr[n++] = 0xd; /* Temperature */
2233 arr[n++] = 0x2f; /* Informational exceptions */
2234 arr[3] = n - 4;
2235 break;
2236 case 0xd: /* Temperature log page */
2237 arr[3] = resp_temp_l_pg(arr + 4);
2238 break;
2239 case 0x2f: /* Informational exceptions log page */
2240 arr[3] = resp_ie_l_pg(arr + 4);
2241 break;
2242 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002243 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002244 return check_condition_result;
2245 }
2246 } else if (0xff == subpcode) {
2247 arr[0] |= 0x40;
2248 arr[1] = subpcode;
2249 switch (pcode) {
2250 case 0x0: /* Supported log pages and subpages log page */
2251 n = 4;
2252 arr[n++] = 0x0;
2253 arr[n++] = 0x0; /* 0,0 page */
2254 arr[n++] = 0x0;
2255 arr[n++] = 0xff; /* this page */
2256 arr[n++] = 0xd;
2257 arr[n++] = 0x0; /* Temperature */
2258 arr[n++] = 0x2f;
2259 arr[n++] = 0x0; /* Informational exceptions */
2260 arr[3] = n - 4;
2261 break;
2262 case 0xd: /* Temperature subpages */
2263 n = 4;
2264 arr[n++] = 0xd;
2265 arr[n++] = 0x0; /* Temperature */
2266 arr[3] = n - 4;
2267 break;
2268 case 0x2f: /* Informational exceptions subpages */
2269 n = 4;
2270 arr[n++] = 0x2f;
2271 arr[n++] = 0x0; /* Informational exceptions */
2272 arr[3] = n - 4;
2273 break;
2274 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002275 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002276 return check_condition_result;
2277 }
2278 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002279 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002280 return check_condition_result;
2281 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002282 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002283 return fill_from_dev_buffer(scp, arr,
2284 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2285}
2286
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002287static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002288 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002290 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002291 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 return check_condition_result;
2293 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002294 /* transfer length excessive (tie in to block limits VPD page) */
2295 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002296 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002297 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002298 return check_condition_result;
2299 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002300 return 0;
2301}
2302
Akinobu Mitaa4517512013-07-08 16:01:57 -07002303/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002304static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2305 bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002306{
2307 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002308 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002309 struct scsi_data_buffer *sdb;
2310 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002311
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002312 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002313 sdb = scsi_out(scmd);
2314 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002315 } else {
2316 sdb = scsi_in(scmd);
2317 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002318 }
2319
2320 if (!sdb->length)
2321 return 0;
2322 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2323 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002324
2325 block = do_div(lba, sdebug_store_sectors);
2326 if (block + num > sdebug_store_sectors)
2327 rest = block + num - sdebug_store_sectors;
2328
Dave Gordon386ecb12015-06-30 14:58:57 -07002329 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002330 fake_storep + (block * sdebug_sector_size),
2331 (num - rest) * sdebug_sector_size, 0, do_write);
2332 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002333 return ret;
2334
2335 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002336 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002337 fake_storep, rest * sdebug_sector_size,
2338 (num - rest) * sdebug_sector_size, do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002339 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002340
2341 return ret;
2342}
2343
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002344/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2345 * arr into fake_store(lba,num) and return true. If comparison fails then
2346 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002347static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002348{
2349 bool res;
2350 u64 block, rest = 0;
2351 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002352 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002353
2354 block = do_div(lba, store_blks);
2355 if (block + num > store_blks)
2356 rest = block + num - store_blks;
2357
2358 res = !memcmp(fake_storep + (block * lb_size), arr,
2359 (num - rest) * lb_size);
2360 if (!res)
2361 return res;
2362 if (rest)
2363 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2364 rest * lb_size);
2365 if (!res)
2366 return res;
2367 arr += num * lb_size;
2368 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2369 if (rest)
2370 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2371 rest * lb_size);
2372 return res;
2373}
2374
Akinobu Mita51d648a2013-09-18 21:27:28 +09002375static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002376{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002377 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002378
Douglas Gilbert773642d2016-04-25 12:16:28 -04002379 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002380 csum = (__force __be16)ip_compute_csum(buf, len);
2381 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002382 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002383
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002384 return csum;
2385}
2386
2387static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2388 sector_t sector, u32 ei_lba)
2389{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002390 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002391
2392 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002393 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002394 (unsigned long)sector,
2395 be16_to_cpu(sdt->guard_tag),
2396 be16_to_cpu(csum));
2397 return 0x01;
2398 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002399 if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002400 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002401 pr_err("REF check failed on sector %lu\n",
2402 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002403 return 0x03;
2404 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002405 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002406 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002407 pr_err("REF check failed on sector %lu\n",
2408 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002409 return 0x03;
2410 }
2411 return 0;
2412}
2413
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002414static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002415 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002416{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002417 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002418 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002419 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002420 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002421
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002422 /* Bytes of protection data to copy into sgl */
2423 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002424
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002425 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2426 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2427 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2428
2429 while (sg_miter_next(&miter) && resid > 0) {
2430 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002431 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002432 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002433
2434 if (dif_store_end < start + len)
2435 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002436
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002437 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002438
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002439 if (read)
2440 memcpy(paddr, start, len - rest);
2441 else
2442 memcpy(start, paddr, len - rest);
2443
2444 if (rest) {
2445 if (read)
2446 memcpy(paddr + len - rest, dif_storep, rest);
2447 else
2448 memcpy(dif_storep, paddr + len - rest, rest);
2449 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002450
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002451 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002452 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002453 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002454 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002455}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002456
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002457static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2458 unsigned int sectors, u32 ei_lba)
2459{
2460 unsigned int i;
2461 struct sd_dif_tuple *sdt;
2462 sector_t sector;
2463
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002464 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002465 int ret;
2466
2467 sector = start_sec + i;
2468 sdt = dif_store(sector);
2469
Akinobu Mita51d648a2013-09-18 21:27:28 +09002470 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002471 continue;
2472
2473 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2474 if (ret) {
2475 dif_errors++;
2476 return ret;
2477 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002478 }
2479
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002480 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002481 dix_reads++;
2482
2483 return 0;
2484}
2485
Douglas Gilbertfd321192016-04-25 12:16:33 -04002486static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002487{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002488 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002489 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002490 u64 lba;
2491 u32 num;
2492 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002493 unsigned long iflags;
2494 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002495 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002496
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002497 switch (cmd[0]) {
2498 case READ_16:
2499 ei_lba = 0;
2500 lba = get_unaligned_be64(cmd + 2);
2501 num = get_unaligned_be32(cmd + 10);
2502 check_prot = true;
2503 break;
2504 case READ_10:
2505 ei_lba = 0;
2506 lba = get_unaligned_be32(cmd + 2);
2507 num = get_unaligned_be16(cmd + 7);
2508 check_prot = true;
2509 break;
2510 case READ_6:
2511 ei_lba = 0;
2512 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2513 (u32)(cmd[1] & 0x1f) << 16;
2514 num = (0 == cmd[4]) ? 256 : cmd[4];
2515 check_prot = true;
2516 break;
2517 case READ_12:
2518 ei_lba = 0;
2519 lba = get_unaligned_be32(cmd + 2);
2520 num = get_unaligned_be32(cmd + 6);
2521 check_prot = true;
2522 break;
2523 case XDWRITEREAD_10:
2524 ei_lba = 0;
2525 lba = get_unaligned_be32(cmd + 2);
2526 num = get_unaligned_be16(cmd + 7);
2527 check_prot = false;
2528 break;
2529 default: /* assume READ(32) */
2530 lba = get_unaligned_be64(cmd + 12);
2531 ei_lba = get_unaligned_be32(cmd + 20);
2532 num = get_unaligned_be32(cmd + 28);
2533 check_prot = false;
2534 break;
2535 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002536 if (unlikely(have_dif_prot && check_prot)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002537 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002538 (cmd[1] & 0xe0)) {
2539 mk_sense_invalid_opcode(scp);
2540 return check_condition_result;
2541 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002542 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2543 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002544 (cmd[1] & 0xe0) == 0)
2545 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2546 "to DIF device\n");
2547 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002548 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002549 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002550
Douglas Gilbertc4837392016-05-06 00:40:26 -04002551 if (sqcp) {
2552 if (sqcp->inj_short)
2553 num /= 2;
2554 }
2555 } else
2556 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002557
2558 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002559 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002560 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2561 return check_condition_result;
2562 }
2563 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002564 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002565 /* needs work to find which cdb byte 'num' comes from */
2566 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2567 return check_condition_result;
2568 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002569
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002570 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2571 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2572 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002573 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002574 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002575 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002576 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2577 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002578 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2579 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002580 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002581 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002582 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 return check_condition_result;
2584 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002585
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002586 read_lock_irqsave(&atomic_rw, iflags);
2587
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002588 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002589 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002590 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002591
2592 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002593 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002594 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002595 return illegal_condition_result;
2596 }
2597 }
2598
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002599 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002601 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002602 return DID_ERROR << 16;
2603
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002604 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002605
Douglas Gilbertc4837392016-05-06 00:40:26 -04002606 if (unlikely(sqcp)) {
2607 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002608 mk_sense_buffer(scp, RECOVERED_ERROR,
2609 THRESHOLD_EXCEEDED, 0);
2610 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002611 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002612 mk_sense_buffer(scp, ABORTED_COMMAND,
2613 TRANSPORT_PROBLEM, ACK_NAK_TO);
2614 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002615 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002616 /* Logical block guard check failed */
2617 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2618 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002619 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002620 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2621 return illegal_condition_result;
2622 }
2623 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002624 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625}
2626
Tomas Winkler58a86352015-07-28 16:54:23 +03002627static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002628{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002629 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002630
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002631 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002632 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002633 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002634
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002635 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002636 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002637
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002638 if (c >= 0x20 && c < 0x7e)
2639 n += scnprintf(b + n, sizeof(b) - n,
2640 " %c ", buf[i+j]);
2641 else
2642 n += scnprintf(b + n, sizeof(b) - n,
2643 "%02x ", buf[i+j]);
2644 }
2645 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002646 }
2647}
2648
2649static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002650 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002651{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002652 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002653 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002654 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002655 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002656 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002657 int dpage_offset;
2658 struct sg_mapping_iter diter;
2659 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002660
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002661 BUG_ON(scsi_sg_count(SCpnt) == 0);
2662 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2663
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002664 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2665 scsi_prot_sg_count(SCpnt),
2666 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2667 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2668 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002669
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002670 /* For each protection page */
2671 while (sg_miter_next(&piter)) {
2672 dpage_offset = 0;
2673 if (WARN_ON(!sg_miter_next(&diter))) {
2674 ret = 0x01;
2675 goto out;
2676 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002677
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002678 for (ppage_offset = 0; ppage_offset < piter.length;
2679 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002680 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002681 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002682 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002683 if (dpage_offset >= diter.length) {
2684 if (WARN_ON(!sg_miter_next(&diter))) {
2685 ret = 0x01;
2686 goto out;
2687 }
2688 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002689 }
2690
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002691 sdt = piter.addr + ppage_offset;
2692 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002693
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002694 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002695 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002696 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002697 goto out;
2698 }
2699
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002700 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002701 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002702 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002703 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002704 diter.consumed = dpage_offset;
2705 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002706 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002707 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002708
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002709 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002710 dix_writes++;
2711
2712 return 0;
2713
2714out:
2715 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002716 sg_miter_stop(&diter);
2717 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002718 return ret;
2719}
2720
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002721static unsigned long lba_to_map_index(sector_t lba)
2722{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002723 if (sdebug_unmap_alignment)
2724 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2725 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002726 return lba;
2727}
2728
2729static sector_t map_index_to_lba(unsigned long index)
2730{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002731 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002732
Douglas Gilbert773642d2016-04-25 12:16:28 -04002733 if (sdebug_unmap_alignment)
2734 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002735 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002736}
2737
Martin K. Petersen44d92692009-10-15 14:45:27 -04002738static unsigned int map_state(sector_t lba, unsigned int *num)
2739{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002740 sector_t end;
2741 unsigned int mapped;
2742 unsigned long index;
2743 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002744
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002745 index = lba_to_map_index(lba);
2746 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002747
2748 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002749 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002750 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002751 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002752
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002753 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002754 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002755 return mapped;
2756}
2757
2758static void map_region(sector_t lba, unsigned int len)
2759{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002760 sector_t end = lba + len;
2761
Martin K. Petersen44d92692009-10-15 14:45:27 -04002762 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002763 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002764
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002765 if (index < map_size)
2766 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002767
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002768 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002769 }
2770}
2771
2772static void unmap_region(sector_t lba, unsigned int len)
2773{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002774 sector_t end = lba + len;
2775
Martin K. Petersen44d92692009-10-15 14:45:27 -04002776 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002777 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002778
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002779 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002780 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002781 index < map_size) {
2782 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002783 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002784 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002785 lba * sdebug_sector_size,
2786 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002787 sdebug_sector_size *
2788 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002789 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002790 if (dif_storep) {
2791 memset(dif_storep + lba, 0xff,
2792 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002793 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002794 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002795 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002796 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002797 }
2798}
2799
Douglas Gilbertfd321192016-04-25 12:16:33 -04002800static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002802 u8 *cmd = scp->cmnd;
2803 u64 lba;
2804 u32 num;
2805 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002807 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002808 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002810 switch (cmd[0]) {
2811 case WRITE_16:
2812 ei_lba = 0;
2813 lba = get_unaligned_be64(cmd + 2);
2814 num = get_unaligned_be32(cmd + 10);
2815 check_prot = true;
2816 break;
2817 case WRITE_10:
2818 ei_lba = 0;
2819 lba = get_unaligned_be32(cmd + 2);
2820 num = get_unaligned_be16(cmd + 7);
2821 check_prot = true;
2822 break;
2823 case WRITE_6:
2824 ei_lba = 0;
2825 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2826 (u32)(cmd[1] & 0x1f) << 16;
2827 num = (0 == cmd[4]) ? 256 : cmd[4];
2828 check_prot = true;
2829 break;
2830 case WRITE_12:
2831 ei_lba = 0;
2832 lba = get_unaligned_be32(cmd + 2);
2833 num = get_unaligned_be32(cmd + 6);
2834 check_prot = true;
2835 break;
2836 case 0x53: /* XDWRITEREAD(10) */
2837 ei_lba = 0;
2838 lba = get_unaligned_be32(cmd + 2);
2839 num = get_unaligned_be16(cmd + 7);
2840 check_prot = false;
2841 break;
2842 default: /* assume WRITE(32) */
2843 lba = get_unaligned_be64(cmd + 12);
2844 ei_lba = get_unaligned_be32(cmd + 20);
2845 num = get_unaligned_be32(cmd + 28);
2846 check_prot = false;
2847 break;
2848 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002849 if (unlikely(have_dif_prot && check_prot)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002850 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002851 (cmd[1] & 0xe0)) {
2852 mk_sense_invalid_opcode(scp);
2853 return check_condition_result;
2854 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002855 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2856 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002857 (cmd[1] & 0xe0) == 0)
2858 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2859 "to DIF device\n");
2860 }
2861
2862 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002863 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002864 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2865 return check_condition_result;
2866 }
2867 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002868 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002869 /* needs work to find which cdb byte 'num' comes from */
2870 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2871 return check_condition_result;
2872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002874 write_lock_irqsave(&atomic_rw, iflags);
2875
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002876 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002877 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002878 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002879
2880 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002881 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002882 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002883 return illegal_condition_result;
2884 }
2885 }
2886
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002887 ret = do_device_access(scp, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002888 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04002889 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002891 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04002892 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002893 else if (unlikely(sdebug_verbose &&
2894 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002895 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002896 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002897 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002898
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002899 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002900 struct sdebug_queued_cmd *sqcp =
2901 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002902
Douglas Gilbertc4837392016-05-06 00:40:26 -04002903 if (sqcp) {
2904 if (sqcp->inj_recovered) {
2905 mk_sense_buffer(scp, RECOVERED_ERROR,
2906 THRESHOLD_EXCEEDED, 0);
2907 return check_condition_result;
2908 } else if (sqcp->inj_dif) {
2909 /* Logical block guard check failed */
2910 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2911 return illegal_condition_result;
2912 } else if (sqcp->inj_dix) {
2913 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2914 return illegal_condition_result;
2915 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002916 }
2917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 return 0;
2919}
2920
Douglas Gilbertfd321192016-04-25 12:16:33 -04002921static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2922 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002923{
2924 unsigned long iflags;
2925 unsigned long long i;
2926 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002927 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002928
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002929 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002930 if (ret)
2931 return ret;
2932
2933 write_lock_irqsave(&atomic_rw, iflags);
2934
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002935 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002936 unmap_region(lba, num);
2937 goto out;
2938 }
2939
Douglas Gilbert773642d2016-04-25 12:16:28 -04002940 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002941 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2942 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002943 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002944 ret = 0;
2945 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04002946 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2947 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002948
2949 if (-1 == ret) {
2950 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002951 return DID_ERROR << 16;
2952 } else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002953 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002954 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2955 my_name, "write same",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002956 num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002957
2958 /* Copy first sector to remaining blocks */
2959 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002960 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2961 fake_storep + lba_off,
2962 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002963
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002964 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002965 map_region(lba, num);
2966out:
2967 write_unlock_irqrestore(&atomic_rw, iflags);
2968
2969 return 0;
2970}
2971
Douglas Gilbertfd321192016-04-25 12:16:33 -04002972static int resp_write_same_10(struct scsi_cmnd *scp,
2973 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002974{
2975 u8 *cmd = scp->cmnd;
2976 u32 lba;
2977 u16 num;
2978 u32 ei_lba = 0;
2979 bool unmap = false;
2980
2981 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002982 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002983 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2984 return check_condition_result;
2985 } else
2986 unmap = true;
2987 }
2988 lba = get_unaligned_be32(cmd + 2);
2989 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002990 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002991 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2992 return check_condition_result;
2993 }
2994 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2995}
2996
Douglas Gilbertfd321192016-04-25 12:16:33 -04002997static int resp_write_same_16(struct scsi_cmnd *scp,
2998 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002999{
3000 u8 *cmd = scp->cmnd;
3001 u64 lba;
3002 u32 num;
3003 u32 ei_lba = 0;
3004 bool unmap = false;
3005 bool ndob = false;
3006
3007 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003008 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003009 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3010 return check_condition_result;
3011 } else
3012 unmap = true;
3013 }
3014 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3015 ndob = true;
3016 lba = get_unaligned_be64(cmd + 2);
3017 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003018 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003019 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3020 return check_condition_result;
3021 }
3022 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3023}
3024
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003025/* Note the mode field is in the same position as the (lower) service action
3026 * field. For the Report supported operation codes command, SPC-4 suggests
3027 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003028static int resp_write_buffer(struct scsi_cmnd *scp,
3029 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003030{
3031 u8 *cmd = scp->cmnd;
3032 struct scsi_device *sdp = scp->device;
3033 struct sdebug_dev_info *dp;
3034 u8 mode;
3035
3036 mode = cmd[1] & 0x1f;
3037 switch (mode) {
3038 case 0x4: /* download microcode (MC) and activate (ACT) */
3039 /* set UAs on this device only */
3040 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3041 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3042 break;
3043 case 0x5: /* download MC, save and ACT */
3044 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3045 break;
3046 case 0x6: /* download MC with offsets and ACT */
3047 /* set UAs on most devices (LUs) in this target */
3048 list_for_each_entry(dp,
3049 &devip->sdbg_host->dev_info_list,
3050 dev_list)
3051 if (dp->target == sdp->id) {
3052 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3053 if (devip != dp)
3054 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3055 dp->uas_bm);
3056 }
3057 break;
3058 case 0x7: /* download MC with offsets, save, and ACT */
3059 /* set UA on all devices (LUs) in this target */
3060 list_for_each_entry(dp,
3061 &devip->sdbg_host->dev_info_list,
3062 dev_list)
3063 if (dp->target == sdp->id)
3064 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3065 dp->uas_bm);
3066 break;
3067 default:
3068 /* do nothing for this command for other mode values */
3069 break;
3070 }
3071 return 0;
3072}
3073
Douglas Gilbertfd321192016-04-25 12:16:33 -04003074static int resp_comp_write(struct scsi_cmnd *scp,
3075 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003076{
3077 u8 *cmd = scp->cmnd;
3078 u8 *arr;
3079 u8 *fake_storep_hold;
3080 u64 lba;
3081 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003082 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003083 u8 num;
3084 unsigned long iflags;
3085 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003086 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003087
Douglas Gilbertd467d312014-11-26 12:33:48 -05003088 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003089 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3090 if (0 == num)
3091 return 0; /* degenerate case, not an error */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003092 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003093 (cmd[1] & 0xe0)) {
3094 mk_sense_invalid_opcode(scp);
3095 return check_condition_result;
3096 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003097 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3098 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003099 (cmd[1] & 0xe0) == 0)
3100 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3101 "to DIF device\n");
3102
3103 /* inline check_device_access_params() */
3104 if (lba + num > sdebug_capacity) {
3105 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3106 return check_condition_result;
3107 }
3108 /* transfer length excessive (tie in to block limits VPD page) */
3109 if (num > sdebug_store_sectors) {
3110 /* needs work to find which cdb byte 'num' comes from */
3111 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3112 return check_condition_result;
3113 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003114 dnum = 2 * num;
3115 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3116 if (NULL == arr) {
3117 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3118 INSUFF_RES_ASCQ);
3119 return check_condition_result;
3120 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003121
3122 write_lock_irqsave(&atomic_rw, iflags);
3123
3124 /* trick do_device_access() to fetch both compare and write buffers
3125 * from data-in into arr. Safe (atomic) since write_lock held. */
3126 fake_storep_hold = fake_storep;
3127 fake_storep = arr;
3128 ret = do_device_access(scp, 0, dnum, true);
3129 fake_storep = fake_storep_hold;
3130 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003131 retval = DID_ERROR << 16;
3132 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003133 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003134 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3135 "indicated=%u, IO sent=%d bytes\n", my_name,
3136 dnum * lb_size, ret);
3137 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003138 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003139 retval = check_condition_result;
3140 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003141 }
3142 if (scsi_debug_lbp())
3143 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003144cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003145 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003146 kfree(arr);
3147 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003148}
3149
Martin K. Petersen44d92692009-10-15 14:45:27 -04003150struct unmap_block_desc {
3151 __be64 lba;
3152 __be32 blocks;
3153 __be32 __reserved;
3154};
3155
Douglas Gilbertfd321192016-04-25 12:16:33 -04003156static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003157{
3158 unsigned char *buf;
3159 struct unmap_block_desc *desc;
3160 unsigned int i, payload_len, descriptors;
3161 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003162 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003163
Martin K. Petersen44d92692009-10-15 14:45:27 -04003164
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003165 if (!scsi_debug_lbp())
3166 return 0; /* fib and say its done */
3167 payload_len = get_unaligned_be16(scp->cmnd + 7);
3168 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003169
3170 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003171 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003172 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003173 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003174 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003175
Douglas Gilbertb333a812016-04-25 12:16:30 -04003176 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003177 if (!buf) {
3178 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3179 INSUFF_RES_ASCQ);
3180 return check_condition_result;
3181 }
3182
3183 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003184
3185 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3186 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3187
3188 desc = (void *)&buf[8];
3189
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003190 write_lock_irqsave(&atomic_rw, iflags);
3191
Martin K. Petersen44d92692009-10-15 14:45:27 -04003192 for (i = 0 ; i < descriptors ; i++) {
3193 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3194 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3195
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003196 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003197 if (ret)
3198 goto out;
3199
3200 unmap_region(lba, num);
3201 }
3202
3203 ret = 0;
3204
3205out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003206 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003207 kfree(buf);
3208
3209 return ret;
3210}
3211
3212#define SDEBUG_GET_LBA_STATUS_LEN 32
3213
Douglas Gilbertfd321192016-04-25 12:16:33 -04003214static int resp_get_lba_status(struct scsi_cmnd *scp,
3215 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003216{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003217 u8 *cmd = scp->cmnd;
3218 u64 lba;
3219 u32 alloc_len, mapped, num;
3220 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003221 int ret;
3222
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003223 lba = get_unaligned_be64(cmd + 2);
3224 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003225
3226 if (alloc_len < 24)
3227 return 0;
3228
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003229 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003230 if (ret)
3231 return ret;
3232
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003233 if (scsi_debug_lbp())
3234 mapped = map_state(lba, &num);
3235 else {
3236 mapped = 1;
3237 /* following just in case virtual_gb changed */
3238 sdebug_capacity = get_sdebug_capacity();
3239 if (sdebug_capacity - lba <= 0xffffffff)
3240 num = sdebug_capacity - lba;
3241 else
3242 num = 0xffffffff;
3243 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003244
3245 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003246 put_unaligned_be32(20, arr); /* Parameter Data Length */
3247 put_unaligned_be64(lba, arr + 8); /* LBA */
3248 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3249 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003250
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003251 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003252}
3253
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003254/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3255 * (W-LUN), the normal Linux scanning logic does not associate it with a
3256 * device (e.g. /dev/sg7). The following magic will make that association:
3257 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3258 * where <n> is a host number. If there are multiple targets in a host then
3259 * the above will associate a W-LUN to each target. To only get a W-LUN
3260 * for target 2, then use "echo '- 2 49409' > scan" .
3261 */
3262static int resp_report_luns(struct scsi_cmnd *scp,
3263 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003265 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003266 unsigned int alloc_len;
3267 unsigned char select_report;
3268 u64 lun;
3269 struct scsi_lun *lun_p;
3270 u8 *arr;
3271 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3272 unsigned int wlun_cnt; /* report luns W-LUN count */
3273 unsigned int tlun_cnt; /* total LUN count */
3274 unsigned int rlen; /* response length (in bytes) */
3275 int i, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003277 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003278
3279 select_report = cmd[2];
3280 alloc_len = get_unaligned_be32(cmd + 6);
3281
3282 if (alloc_len < 4) {
3283 pr_err("alloc len too small %d\n", alloc_len);
3284 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 return check_condition_result;
3286 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003287
3288 switch (select_report) {
3289 case 0: /* all LUNs apart from W-LUNs */
3290 lun_cnt = sdebug_max_luns;
3291 wlun_cnt = 0;
3292 break;
3293 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003294 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003295 wlun_cnt = 1;
3296 break;
3297 case 2: /* all LUNs */
3298 lun_cnt = sdebug_max_luns;
3299 wlun_cnt = 1;
3300 break;
3301 case 0x10: /* only administrative LUs */
3302 case 0x11: /* see SPC-5 */
3303 case 0x12: /* only subsiduary LUs owned by referenced LU */
3304 default:
3305 pr_debug("select report invalid %d\n", select_report);
3306 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3307 return check_condition_result;
3308 }
3309
3310 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003311 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003312
3313 tlun_cnt = lun_cnt + wlun_cnt;
3314
3315 rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8;
3316 arr = vmalloc(rlen);
3317 if (!arr) {
3318 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3319 INSUFF_RES_ASCQ);
3320 return check_condition_result;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003321 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003322 memset(arr, 0, rlen);
3323 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3324 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3325
3326 /* luns start at byte 8 in response following the header */
3327 lun_p = (struct scsi_lun *)&arr[8];
3328
3329 /* LUNs use single level peripheral device addressing method */
3330 lun = sdebug_no_lun_0 ? 1 : 0;
3331 for (i = 0; i < lun_cnt; i++)
3332 int_to_scsilun(lun++, lun_p++);
3333
3334 if (wlun_cnt)
3335 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++);
3336
3337 put_unaligned_be32(rlen - 8, &arr[0]);
3338
3339 res = fill_from_dev_buffer(scp, arr, rlen);
3340 vfree(arr);
3341 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342}
3343
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003344static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3345 unsigned int num, struct sdebug_dev_info *devip)
3346{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003347 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003348 unsigned char *kaddr, *buf;
3349 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003350 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003351 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003352
3353 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003354 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003355 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003356 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3357 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003358 return check_condition_result;
3359 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003360
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003361 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003362
3363 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003364 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3365 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003366
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003367 while (sg_miter_next(&miter)) {
3368 kaddr = miter.addr;
3369 for (j = 0; j < miter.length; j++)
3370 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003371
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003372 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003373 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003374 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003375 kfree(buf);
3376
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003377 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003378}
3379
Douglas Gilbertfd321192016-04-25 12:16:33 -04003380static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3381 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003382{
3383 u8 *cmd = scp->cmnd;
3384 u64 lba;
3385 u32 num;
3386 int errsts;
3387
3388 if (!scsi_bidi_cmnd(scp)) {
3389 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3390 INSUFF_RES_ASCQ);
3391 return check_condition_result;
3392 }
3393 errsts = resp_read_dt0(scp, devip);
3394 if (errsts)
3395 return errsts;
3396 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3397 errsts = resp_write_dt0(scp, devip);
3398 if (errsts)
3399 return errsts;
3400 }
3401 lba = get_unaligned_be32(cmd + 2);
3402 num = get_unaligned_be16(cmd + 7);
3403 return resp_xdwriteread(scp, lba, num, devip);
3404}
3405
Douglas Gilbertc4837392016-05-06 00:40:26 -04003406static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3407{
3408 struct sdebug_queue *sqp = sdebug_q_arr;
3409
3410 if (sdebug_mq_active) {
3411 u32 tag = blk_mq_unique_tag(cmnd->request);
3412 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
3413
3414 if (unlikely(hwq >= submit_queues)) {
3415 pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
3416 hwq %= submit_queues;
3417 }
3418 pr_debug("tag=%u, hwq=%d\n", tag, hwq);
3419 return sqp + hwq;
3420 } else
3421 return sqp;
3422}
3423
3424/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003425static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003427 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003428 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003430 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003431 struct sdebug_queued_cmd *sqcp;
3432 struct scsi_cmnd *scp;
3433 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434
Douglas Gilbertc4837392016-05-06 00:40:26 -04003435 qc_idx = sd_dp->qc_idx;
3436 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3437 if (sdebug_statistics) {
3438 atomic_inc(&sdebug_completions);
3439 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3440 atomic_inc(&sdebug_miss_cpus);
3441 }
3442 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3443 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 return;
3445 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003446 spin_lock_irqsave(&sqp->qc_lock, iflags);
3447 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003448 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003449 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003450 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3451 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3452 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 return;
3454 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003455 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003456 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003457 atomic_dec(&devip->num_in_q);
3458 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003459 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003460 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003461 retiring = 1;
3462
3463 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003464 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3465 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003466 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003467 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003469
3470 if (unlikely(retiring)) { /* user has reduced max_queue */
3471 int k, retval;
3472
3473 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003474 if (qc_idx >= retval) {
3475 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003476 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003477 return;
3478 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003479 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003480 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003481 atomic_set(&retired_max_queue, 0);
3482 else
3483 atomic_set(&retired_max_queue, k + 1);
3484 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003485 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003486 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487}
3488
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003489/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003490static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003491{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003492 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3493 hrt);
3494 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003495 return HRTIMER_NORESTART;
3496}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497
Douglas Gilberta10bc122016-04-25 12:16:32 -04003498/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003499static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003500{
3501 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3502 ew.work);
3503 sdebug_q_cmd_complete(sd_dp);
3504}
3505
Douglas Gilbertfd321192016-04-25 12:16:33 -04003506static struct sdebug_dev_info *sdebug_device_create(
3507 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003508{
3509 struct sdebug_dev_info *devip;
3510
3511 devip = kzalloc(sizeof(*devip), flags);
3512 if (devip) {
3513 devip->sdbg_host = sdbg_host;
3514 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3515 }
3516 return devip;
3517}
3518
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003519static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003521 struct sdebug_host_info *sdbg_host;
3522 struct sdebug_dev_info *open_devip = NULL;
3523 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003525 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3526 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003527 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 return NULL;
3529 }
3530 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3531 if ((devip->used) && (devip->channel == sdev->channel) &&
3532 (devip->target == sdev->id) &&
3533 (devip->lun == sdev->lun))
3534 return devip;
3535 else {
3536 if ((!devip->used) && (!open_devip))
3537 open_devip = devip;
3538 }
3539 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003540 if (!open_devip) { /* try and make a new one */
3541 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3542 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003543 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 return NULL;
3545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003547
3548 open_devip->channel = sdev->channel;
3549 open_devip->target = sdev->id;
3550 open_devip->lun = sdev->lun;
3551 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003552 atomic_set(&open_devip->num_in_q, 0);
3553 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003554 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003555 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556}
3557
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003558static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003560 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003561 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003562 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003563 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003564 return 0;
3565}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003567static int scsi_debug_slave_configure(struct scsi_device *sdp)
3568{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003569 struct sdebug_dev_info *devip =
3570 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003571
Douglas Gilbert773642d2016-04-25 12:16:28 -04003572 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003573 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003574 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003575 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3576 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3577 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003578 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003579 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003580 return 1; /* no resources, will be marked offline */
3581 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003582 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003583 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003584 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003585 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003586 return 0;
3587}
3588
3589static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3590{
3591 struct sdebug_dev_info *devip =
3592 (struct sdebug_dev_info *)sdp->hostdata;
3593
Douglas Gilbert773642d2016-04-25 12:16:28 -04003594 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003595 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003596 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3597 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003598 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003599 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003600 sdp->hostdata = NULL;
3601 }
3602}
3603
Douglas Gilbertc4837392016-05-06 00:40:26 -04003604static void stop_qc_helper(struct sdebug_defer *sd_dp)
3605{
3606 if (!sd_dp)
3607 return;
3608 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0))
3609 hrtimer_cancel(&sd_dp->hrt);
3610 else if (sdebug_jdelay < 0)
3611 cancel_work_sync(&sd_dp->ew.work);
3612}
3613
Douglas Gilberta10bc122016-04-25 12:16:32 -04003614/* If @cmnd found deletes its timer or work queue and returns true; else
3615 returns false */
3616static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003617{
3618 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003619 int j, k, qmax, r_qmax;
3620 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003621 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003622 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003623 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003624
Douglas Gilbertc4837392016-05-06 00:40:26 -04003625 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3626 spin_lock_irqsave(&sqp->qc_lock, iflags);
3627 qmax = sdebug_max_queue;
3628 r_qmax = atomic_read(&retired_max_queue);
3629 if (r_qmax > qmax)
3630 qmax = r_qmax;
3631 for (k = 0; k < qmax; ++k) {
3632 if (test_bit(k, sqp->in_use_bm)) {
3633 sqcp = &sqp->qc_arr[k];
3634 if (cmnd != sqcp->a_cmnd)
3635 continue;
3636 /* found */
3637 devip = (struct sdebug_dev_info *)
3638 cmnd->device->hostdata;
3639 if (devip)
3640 atomic_dec(&devip->num_in_q);
3641 sqcp->a_cmnd = NULL;
3642 sd_dp = sqcp->sd_dp;
3643 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3644 stop_qc_helper(sd_dp);
3645 clear_bit(k, sqp->in_use_bm);
3646 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003647 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003648 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003649 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003650 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003651 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003652}
3653
Douglas Gilberta10bc122016-04-25 12:16:32 -04003654/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003655static void stop_all_queued(void)
3656{
3657 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003658 int j, k;
3659 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003660 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003661 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003662 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003663
Douglas Gilbertc4837392016-05-06 00:40:26 -04003664 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3665 spin_lock_irqsave(&sqp->qc_lock, iflags);
3666 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3667 if (test_bit(k, sqp->in_use_bm)) {
3668 sqcp = &sqp->qc_arr[k];
3669 if (sqcp->a_cmnd == NULL)
3670 continue;
3671 devip = (struct sdebug_dev_info *)
3672 sqcp->a_cmnd->device->hostdata;
3673 if (devip)
3674 atomic_dec(&devip->num_in_q);
3675 sqcp->a_cmnd = NULL;
3676 sd_dp = sqcp->sd_dp;
3677 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3678 stop_qc_helper(sd_dp);
3679 clear_bit(k, sqp->in_use_bm);
3680 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003681 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003682 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003683 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685}
3686
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003687/* Free queued command memory on heap */
3688static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689{
Douglas Gilbertc4837392016-05-06 00:40:26 -04003690 int j, k;
3691 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003692 struct sdebug_queued_cmd *sqcp;
3693
Douglas Gilbertc4837392016-05-06 00:40:26 -04003694 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3695 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3696 sqcp = &sqp->qc_arr[k];
3697 kfree(sqcp->sd_dp);
3698 sqcp->sd_dp = NULL;
3699 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701}
3702
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003703static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003705 bool ok;
3706
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003707 ++num_aborts;
3708 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003709 ok = stop_queued_cmnd(SCpnt);
3710 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3711 sdev_printk(KERN_INFO, SCpnt->device,
3712 "%s: command%s found\n", __func__,
3713 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003715 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716}
3717
3718static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3719{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003721 if (SCpnt && SCpnt->device) {
3722 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003723 struct sdebug_dev_info *devip =
3724 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003725
Douglas Gilbert773642d2016-04-25 12:16:28 -04003726 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003727 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003729 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 }
3731 return SUCCESS;
3732}
3733
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003734static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3735{
3736 struct sdebug_host_info *sdbg_host;
3737 struct sdebug_dev_info *devip;
3738 struct scsi_device *sdp;
3739 struct Scsi_Host *hp;
3740 int k = 0;
3741
3742 ++num_target_resets;
3743 if (!SCpnt)
3744 goto lie;
3745 sdp = SCpnt->device;
3746 if (!sdp)
3747 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003748 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003749 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3750 hp = sdp->host;
3751 if (!hp)
3752 goto lie;
3753 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3754 if (sdbg_host) {
3755 list_for_each_entry(devip,
3756 &sdbg_host->dev_info_list,
3757 dev_list)
3758 if (devip->target == sdp->id) {
3759 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3760 ++k;
3761 }
3762 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003763 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003764 sdev_printk(KERN_INFO, sdp,
3765 "%s: %d device(s) found in target\n", __func__, k);
3766lie:
3767 return SUCCESS;
3768}
3769
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3771{
3772 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003773 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 struct scsi_device * sdp;
3775 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003776 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003779 if (!(SCpnt && SCpnt->device))
3780 goto lie;
3781 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003782 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003783 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3784 hp = sdp->host;
3785 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003786 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003788 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003790 dev_list) {
3791 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3792 ++k;
3793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 }
3795 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003796 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003797 sdev_printk(KERN_INFO, sdp,
3798 "%s: %d device(s) found in host\n", __func__, k);
3799lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 return SUCCESS;
3801}
3802
3803static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3804{
3805 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003806 struct sdebug_dev_info *devip;
3807 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003810 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003811 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 spin_lock(&sdebug_host_list_lock);
3813 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003814 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3815 dev_list) {
3816 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3817 ++k;
3818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 }
3820 spin_unlock(&sdebug_host_list_lock);
3821 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003822 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003823 sdev_printk(KERN_INFO, SCpnt->device,
3824 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 return SUCCESS;
3826}
3827
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003828static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003829 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830{
3831 struct partition * pp;
3832 int starts[SDEBUG_MAX_PARTS + 2];
3833 int sectors_per_part, num_sectors, k;
3834 int heads_by_sects, start_sec, end_sec;
3835
3836 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003837 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003839 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3840 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003841 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003843 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003845 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3847 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003848 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3850 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003851 starts[sdebug_num_parts] = num_sectors;
3852 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
3854 ramp[510] = 0x55; /* magic partition markings */
3855 ramp[511] = 0xAA;
3856 pp = (struct partition *)(ramp + 0x1be);
3857 for (k = 0; starts[k + 1]; ++k, ++pp) {
3858 start_sec = starts[k];
3859 end_sec = starts[k + 1] - 1;
3860 pp->boot_ind = 0;
3861
3862 pp->cyl = start_sec / heads_by_sects;
3863 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3864 / sdebug_sectors_per;
3865 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3866
3867 pp->end_cyl = end_sec / heads_by_sects;
3868 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3869 / sdebug_sectors_per;
3870 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3871
Akinobu Mita150c3542013-08-26 22:08:40 +09003872 pp->start_sect = cpu_to_le32(start_sec);
3873 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 pp->sys_ind = 0x83; /* plain Linux partition */
3875 }
3876}
3877
Douglas Gilbertc4837392016-05-06 00:40:26 -04003878static void block_unblock_all_queues(bool block)
3879{
3880 int j;
3881 struct sdebug_queue *sqp;
3882
3883 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
3884 atomic_set(&sqp->blocked, (int)block);
3885}
3886
3887/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
3888 * commands will be processed normally before triggers occur.
3889 */
3890static void tweak_cmnd_count(void)
3891{
3892 int count, modulo;
3893
3894 modulo = abs(sdebug_every_nth);
3895 if (modulo < 2)
3896 return;
3897 block_unblock_all_queues(true);
3898 count = atomic_read(&sdebug_cmnd_count);
3899 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
3900 block_unblock_all_queues(false);
3901}
3902
3903static void clear_queue_stats(void)
3904{
3905 atomic_set(&sdebug_cmnd_count, 0);
3906 atomic_set(&sdebug_completions, 0);
3907 atomic_set(&sdebug_miss_cpus, 0);
3908 atomic_set(&sdebug_a_tsf, 0);
3909}
3910
3911static void setup_inject(struct sdebug_queue *sqp,
3912 struct sdebug_queued_cmd *sqcp)
3913{
3914 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
3915 return;
3916 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
3917 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
3918 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
3919 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
3920 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
3921}
3922
3923/* Complete the processing of the thread that queued a SCSI command to this
3924 * driver. It either completes the command by calling cmnd_done() or
3925 * schedules a hr timer or work queue then returns 0. Returns
3926 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
3927 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003928static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3929 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003931 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003932 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003933 struct sdebug_queue *sqp;
3934 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03003935 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003936 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003938 if (unlikely(devip == NULL)) {
3939 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003940 scsi_result = DID_NO_CONNECT << 16;
3941 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03003943 sdp = cmnd->device;
3944
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003945 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003946 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3947 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003948 if (delta_jiff == 0)
3949 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003951 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04003952 sqp = get_queue(cmnd);
3953 spin_lock_irqsave(&sqp->qc_lock, iflags);
3954 if (unlikely(atomic_read(&sqp->blocked))) {
3955 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3956 return SCSI_MLQUEUE_HOST_BUSY;
3957 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003958 num_in_q = atomic_read(&devip->num_in_q);
3959 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003960 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003961 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003962 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003963 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003964 goto respond_in_thread;
3965 } else
3966 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003967 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003968 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
3969 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003970 if ((num_in_q == (qdepth - 1)) &&
3971 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04003972 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003973 atomic_set(&sdebug_a_tsf, 0);
3974 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003975 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003977 }
3978
Douglas Gilbertc4837392016-05-06 00:40:26 -04003979 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003980 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003981 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003982 if (scsi_result)
3983 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003984 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003985 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003986 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003987 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003988 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003989 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003990 (scsi_result ? "status: TASK SET FULL" :
3991 "report: host busy"));
3992 if (scsi_result)
3993 goto respond_in_thread;
3994 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003995 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003997 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003998 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003999 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004000 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004001 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004002 cmnd->result = scsi_result;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004003 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004004 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4005 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4006 setup_inject(sqp, sqcp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004007 if (delta_jiff > 0 || sdebug_ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004008 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004009
Douglas Gilbertb333a812016-04-25 12:16:30 -04004010 if (delta_jiff > 0) {
4011 struct timespec ts;
4012
4013 jiffies_to_timespec(delta_jiff, &ts);
4014 kt = ktime_set(ts.tv_sec, ts.tv_nsec);
4015 } else
4016 kt = ktime_set(0, sdebug_ndelay);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004017 if (NULL == sd_dp) {
4018 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4019 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004020 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004021 sqcp->sd_dp = sd_dp;
4022 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004023 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004024 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004025 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4026 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004027 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004028 if (sdebug_statistics)
4029 sd_dp->issuing_cpu = raw_smp_processor_id();
4030 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4031 } else { /* jdelay < 0, use work queue */
Douglas Gilberta10bc122016-04-25 12:16:32 -04004032 if (NULL == sd_dp) {
4033 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
4034 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004035 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004036 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004037 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4038 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004039 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004040 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004041 if (sdebug_statistics)
4042 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilberta10bc122016-04-25 12:16:32 -04004043 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004044 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004045 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4046 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004047 sdev_printk(KERN_INFO, sdp,
4048 "%s: num_in_q=%d +1, %s%s\n", __func__,
4049 num_in_q, (inject ? "<inject> " : ""),
4050 "status: TASK SET FULL");
4051 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004052
4053respond_in_thread: /* call back to mid-layer using invocation thread */
4054 cmnd->result = scsi_result;
4055 cmnd->scsi_done(cmnd);
4056 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004058
Douglas Gilbert23183912006-09-16 20:30:47 -04004059/* Note: The following macros create attribute files in the
4060 /sys/module/scsi_debug/parameters directory. Unfortunately this
4061 driver is unaware of a change and cannot trigger auxiliary actions
4062 as it can when the corresponding attribute in the
4063 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4064 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004065module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4066module_param_named(ato, sdebug_ato, int, S_IRUGO);
4067module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004068module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004069module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4070module_param_named(dif, sdebug_dif, int, S_IRUGO);
4071module_param_named(dix, sdebug_dix, int, S_IRUGO);
4072module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4073module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4074module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4075module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4076module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
4077module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4078module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4079module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4080module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4081module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4082module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4083module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
4084module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4085module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4086module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4087module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4088module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4089module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4090module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4091module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
4092module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4093module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4094module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4095module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004096module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004097module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004098module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004099module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4100module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4101module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4102module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4103module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
4104module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004105 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004106module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004107 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
4109MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4110MODULE_DESCRIPTION("SCSI debug adapter driver");
4111MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004112MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
4114MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004115MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004116MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004117MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004118MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004119MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4120MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004121MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004122MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004123MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004124MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004125MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004126MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4127MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4128MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004129MODULE_PARM_DESC(lbprz,
4130 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004131MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004132MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004133MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
4134MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004135MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004136MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004138MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004139MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004140MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004141MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004143MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004144MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004145MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004146MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004147MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004148MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004149MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4150MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004151MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4152MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004153MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004154MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4155MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004157#define SDEBUG_INFO_LEN 256
4158static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
4160static const char * scsi_debug_info(struct Scsi_Host * shp)
4161{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004162 int k;
4163
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004164 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4165 my_name, SDEBUG_VERSION, sdebug_version_date);
4166 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004167 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004168 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4169 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4170 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4171 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 return sdebug_info;
4173}
4174
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004175/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004176static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4177 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178{
Al Viroc8ed5552013-03-31 01:46:06 -04004179 char arr[16];
4180 int opts;
4181 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
Al Viroc8ed5552013-03-31 01:46:06 -04004183 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4184 return -EACCES;
4185 memcpy(arr, buffer, minLen);
4186 arr[minLen] = '\0';
4187 if (1 != sscanf(arr, "%d", &opts))
4188 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004189 sdebug_opts = opts;
4190 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4191 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4192 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004193 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004194 return length;
4195}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004197/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4198 * same for each scsi_debug host (if more than one). Some of the counters
4199 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004200static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4201{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004202 int f, j, l;
4203 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004204
Douglas Gilbertc4837392016-05-06 00:40:26 -04004205 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4206 SDEBUG_VERSION, sdebug_version_date);
4207 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4208 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4209 sdebug_opts, sdebug_every_nth);
4210 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4211 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4212 sdebug_sector_size, "bytes");
4213 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4214 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4215 num_aborts);
4216 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4217 num_dev_resets, num_target_resets, num_bus_resets,
4218 num_host_resets);
4219 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4220 dix_reads, dix_writes, dif_errors);
4221 seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
4222 TICK_NSEC / 1000, "statistics", sdebug_statistics,
4223 sdebug_mq_active);
4224 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4225 atomic_read(&sdebug_cmnd_count),
4226 atomic_read(&sdebug_completions),
4227 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4228 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004229
Douglas Gilbertc4837392016-05-06 00:40:26 -04004230 seq_printf(m, "submit_queues=%d\n", submit_queues);
4231 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4232 seq_printf(m, " queue %d:\n", j);
4233 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4234 if (f != sdebug_max_queue) {
4235 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4236 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4237 "first,last bits", f, l);
4238 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004239 }
Al Viroc8ed5552013-03-31 01:46:06 -04004240 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241}
4242
Akinobu Mita82069372013-10-14 22:48:04 +09004243static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004245 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004247/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4248 * of delay is jiffies.
4249 */
Akinobu Mita82069372013-10-14 22:48:04 +09004250static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4251 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004253 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004255 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004256 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004257 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004258 int j, k;
4259 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004260
Douglas Gilbertc4837392016-05-06 00:40:26 -04004261 block_unblock_all_queues(true);
4262 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4263 ++j, ++sqp) {
4264 k = find_first_bit(sqp->in_use_bm,
4265 sdebug_max_queue);
4266 if (k != sdebug_max_queue) {
4267 res = -EBUSY; /* queued commands */
4268 break;
4269 }
4270 }
4271 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004272 /* make sure sdebug_defer instances get
4273 * re-allocated for new delay variant */
4274 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004275 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004276 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004277 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004278 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004280 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 }
4282 return -EINVAL;
4283}
Akinobu Mita82069372013-10-14 22:48:04 +09004284static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004286static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4287{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004288 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004289}
4290/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004291/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004292static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004293 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004294{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004295 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004296
4297 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004298 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004299 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004300 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004301 int j, k;
4302 struct sdebug_queue *sqp;
4303
4304 block_unblock_all_queues(true);
4305 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4306 ++j, ++sqp) {
4307 k = find_first_bit(sqp->in_use_bm,
4308 sdebug_max_queue);
4309 if (k != sdebug_max_queue) {
4310 res = -EBUSY; /* queued commands */
4311 break;
4312 }
4313 }
4314 if (res > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004315 /* make sure sdebug_defer instances get
4316 * re-allocated for new delay variant */
4317 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004318 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004319 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4320 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004321 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004322 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004323 }
4324 return res;
4325 }
4326 return -EINVAL;
4327}
4328static DRIVER_ATTR_RW(ndelay);
4329
Akinobu Mita82069372013-10-14 22:48:04 +09004330static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004332 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333}
4334
Akinobu Mita82069372013-10-14 22:48:04 +09004335static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4336 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337{
4338 int opts;
4339 char work[20];
4340
4341 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004342 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 if (1 == sscanf(&work[2], "%x", &opts))
4344 goto opts_done;
4345 } else {
4346 if (1 == sscanf(work, "%d", &opts))
4347 goto opts_done;
4348 }
4349 }
4350 return -EINVAL;
4351opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004352 sdebug_opts = opts;
4353 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4354 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004355 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 return count;
4357}
Akinobu Mita82069372013-10-14 22:48:04 +09004358static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359
Akinobu Mita82069372013-10-14 22:48:04 +09004360static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004362 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363}
Akinobu Mita82069372013-10-14 22:48:04 +09004364static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4365 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366{
4367 int n;
4368
4369 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004370 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 return count;
4372 }
4373 return -EINVAL;
4374}
Akinobu Mita82069372013-10-14 22:48:04 +09004375static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376
Akinobu Mita82069372013-10-14 22:48:04 +09004377static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004379 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380}
Akinobu Mita82069372013-10-14 22:48:04 +09004381static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4382 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383{
4384 int n;
4385
4386 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004387 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 return count;
4389 }
4390 return -EINVAL;
4391}
Akinobu Mita82069372013-10-14 22:48:04 +09004392static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
Akinobu Mita82069372013-10-14 22:48:04 +09004394static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004395{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004396 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004397}
Akinobu Mita82069372013-10-14 22:48:04 +09004398static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4399 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004400{
4401 int n;
4402
4403 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004404 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004405 sdebug_fake_rw = (sdebug_fake_rw > 0);
4406 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004407 if ((0 == n) && (NULL == fake_storep)) {
4408 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004409 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004410 1048576;
4411
4412 fake_storep = vmalloc(sz);
4413 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004414 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004415 return -ENOMEM;
4416 }
4417 memset(fake_storep, 0, sz);
4418 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004419 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004420 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004421 return count;
4422 }
4423 return -EINVAL;
4424}
Akinobu Mita82069372013-10-14 22:48:04 +09004425static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004426
Akinobu Mita82069372013-10-14 22:48:04 +09004427static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004428{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004429 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004430}
Akinobu Mita82069372013-10-14 22:48:04 +09004431static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4432 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004433{
4434 int n;
4435
4436 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004437 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004438 return count;
4439 }
4440 return -EINVAL;
4441}
Akinobu Mita82069372013-10-14 22:48:04 +09004442static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004443
Akinobu Mita82069372013-10-14 22:48:04 +09004444static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004446 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447}
Akinobu Mita82069372013-10-14 22:48:04 +09004448static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4449 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450{
4451 int n;
4452
4453 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004454 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 sdebug_max_tgts_luns();
4456 return count;
4457 }
4458 return -EINVAL;
4459}
Akinobu Mita82069372013-10-14 22:48:04 +09004460static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
Akinobu Mita82069372013-10-14 22:48:04 +09004462static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004464 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465}
Akinobu Mita82069372013-10-14 22:48:04 +09004466static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467
Akinobu Mita82069372013-10-14 22:48:04 +09004468static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004470 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471}
Akinobu Mita82069372013-10-14 22:48:04 +09004472static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473
Akinobu Mita82069372013-10-14 22:48:04 +09004474static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004476 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477}
Akinobu Mita82069372013-10-14 22:48:04 +09004478static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4479 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480{
4481 int nth;
4482
4483 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004484 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004485 if (nth && !sdebug_statistics) {
4486 pr_info("every_nth needs statistics=1, set it\n");
4487 sdebug_statistics = true;
4488 }
4489 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 return count;
4491 }
4492 return -EINVAL;
4493}
Akinobu Mita82069372013-10-14 22:48:04 +09004494static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
Akinobu Mita82069372013-10-14 22:48:04 +09004496static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004498 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499}
Akinobu Mita82069372013-10-14 22:48:04 +09004500static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4501 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502{
4503 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004504 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505
4506 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004507 if (n > 256) {
4508 pr_warn("max_luns can be no more than 256\n");
4509 return -EINVAL;
4510 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004511 changed = (sdebug_max_luns != n);
4512 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004514 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004515 struct sdebug_host_info *sdhp;
4516 struct sdebug_dev_info *dp;
4517
4518 spin_lock(&sdebug_host_list_lock);
4519 list_for_each_entry(sdhp, &sdebug_host_list,
4520 host_list) {
4521 list_for_each_entry(dp, &sdhp->dev_info_list,
4522 dev_list) {
4523 set_bit(SDEBUG_UA_LUNS_CHANGED,
4524 dp->uas_bm);
4525 }
4526 }
4527 spin_unlock(&sdebug_host_list_lock);
4528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 return count;
4530 }
4531 return -EINVAL;
4532}
Akinobu Mita82069372013-10-14 22:48:04 +09004533static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534
Akinobu Mita82069372013-10-14 22:48:04 +09004535static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004536{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004537 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004538}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004539/* N.B. max_queue can be changed while there are queued commands. In flight
4540 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004541static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4542 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004543{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004544 int j, n, k, a;
4545 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004546
4547 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004548 (n <= SDEBUG_CANQUEUE)) {
4549 block_unblock_all_queues(true);
4550 k = 0;
4551 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4552 ++j, ++sqp) {
4553 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4554 if (a > k)
4555 k = a;
4556 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004557 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004558 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004559 atomic_set(&retired_max_queue, 0);
4560 else if (k >= n)
4561 atomic_set(&retired_max_queue, k + 1);
4562 else
4563 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004564 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004565 return count;
4566 }
4567 return -EINVAL;
4568}
Akinobu Mita82069372013-10-14 22:48:04 +09004569static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004570
Akinobu Mita82069372013-10-14 22:48:04 +09004571static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004572{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004573 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004574}
Akinobu Mita82069372013-10-14 22:48:04 +09004575static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004576
Akinobu Mita82069372013-10-14 22:48:04 +09004577static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004579 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580}
Akinobu Mita82069372013-10-14 22:48:04 +09004581static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582
Akinobu Mita82069372013-10-14 22:48:04 +09004583static ssize_t virtual_gb_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_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004586}
Akinobu Mita82069372013-10-14 22:48:04 +09004587static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4588 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004589{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004590 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004591 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004592
4593 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004594 changed = (sdebug_virtual_gb != n);
4595 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004596 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004597 if (changed) {
4598 struct sdebug_host_info *sdhp;
4599 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004600
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004601 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004602 list_for_each_entry(sdhp, &sdebug_host_list,
4603 host_list) {
4604 list_for_each_entry(dp, &sdhp->dev_info_list,
4605 dev_list) {
4606 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4607 dp->uas_bm);
4608 }
4609 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004610 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004611 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004612 return count;
4613 }
4614 return -EINVAL;
4615}
Akinobu Mita82069372013-10-14 22:48:04 +09004616static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004617
Akinobu Mita82069372013-10-14 22:48:04 +09004618static ssize_t add_host_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_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621}
4622
Douglas Gilbertfd321192016-04-25 12:16:33 -04004623static int sdebug_add_adapter(void);
4624static void sdebug_remove_adapter(void);
4625
Akinobu Mita82069372013-10-14 22:48:04 +09004626static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4627 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004629 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004631 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 if (delta_hosts > 0) {
4634 do {
4635 sdebug_add_adapter();
4636 } while (--delta_hosts);
4637 } else if (delta_hosts < 0) {
4638 do {
4639 sdebug_remove_adapter();
4640 } while (++delta_hosts);
4641 }
4642 return count;
4643}
Akinobu Mita82069372013-10-14 22:48:04 +09004644static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645
Akinobu Mita82069372013-10-14 22:48:04 +09004646static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004647{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004648 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004649}
Akinobu Mita82069372013-10-14 22:48:04 +09004650static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4651 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004652{
4653 int n;
4654
4655 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004656 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004657 return count;
4658 }
4659 return -EINVAL;
4660}
Akinobu Mita82069372013-10-14 22:48:04 +09004661static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004662
Douglas Gilbertc4837392016-05-06 00:40:26 -04004663static ssize_t statistics_show(struct device_driver *ddp, char *buf)
4664{
4665 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
4666}
4667static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
4668 size_t count)
4669{
4670 int n;
4671
4672 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
4673 if (n > 0)
4674 sdebug_statistics = true;
4675 else {
4676 clear_queue_stats();
4677 sdebug_statistics = false;
4678 }
4679 return count;
4680 }
4681 return -EINVAL;
4682}
4683static DRIVER_ATTR_RW(statistics);
4684
Akinobu Mita82069372013-10-14 22:48:04 +09004685static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004686{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004687 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004688}
Akinobu Mita82069372013-10-14 22:48:04 +09004689static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004690
Douglas Gilbertc4837392016-05-06 00:40:26 -04004691static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
4692{
4693 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
4694}
4695static DRIVER_ATTR_RO(submit_queues);
4696
Akinobu Mita82069372013-10-14 22:48:04 +09004697static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004698{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004699 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004700}
Akinobu Mita82069372013-10-14 22:48:04 +09004701static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004702
Akinobu Mita82069372013-10-14 22:48:04 +09004703static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004704{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004705 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004706}
Akinobu Mita82069372013-10-14 22:48:04 +09004707static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004708
Akinobu Mita82069372013-10-14 22:48:04 +09004709static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004710{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004711 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004712}
Akinobu Mita82069372013-10-14 22:48:04 +09004713static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004714
Akinobu Mita82069372013-10-14 22:48:04 +09004715static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004716{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004717 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004718}
Akinobu Mita82069372013-10-14 22:48:04 +09004719static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004720
Akinobu Mita82069372013-10-14 22:48:04 +09004721static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004722{
4723 ssize_t count;
4724
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004725 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004726 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4727 sdebug_store_sectors);
4728
Tejun Heoc7badc92015-02-13 14:37:51 -08004729 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4730 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004731 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004732 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004733
4734 return count;
4735}
Akinobu Mita82069372013-10-14 22:48:04 +09004736static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004737
Akinobu Mita82069372013-10-14 22:48:04 +09004738static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004739{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004740 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004741}
Akinobu Mita82069372013-10-14 22:48:04 +09004742static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4743 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004744{
4745 int n;
4746
4747 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004748 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004749 return count;
4750 }
4751 return -EINVAL;
4752}
Akinobu Mita82069372013-10-14 22:48:04 +09004753static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004754
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004755static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4756{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004757 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004758}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004759/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004760static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4761 size_t count)
4762{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004763 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004764
4765 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004766 sdebug_host_lock = (n > 0);
4767 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004768 }
4769 return -EINVAL;
4770}
4771static DRIVER_ATTR_RW(host_lock);
4772
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004773static ssize_t strict_show(struct device_driver *ddp, char *buf)
4774{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004775 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004776}
4777static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4778 size_t count)
4779{
4780 int n;
4781
4782 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004783 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004784 return count;
4785 }
4786 return -EINVAL;
4787}
4788static DRIVER_ATTR_RW(strict);
4789
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004790
Akinobu Mita82069372013-10-14 22:48:04 +09004791/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004792 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4793 files (over those found in the /sys/module/scsi_debug/parameters
4794 directory) is that auxiliary actions can be triggered when an attribute
4795 is changed. For example see: sdebug_add_host_store() above.
4796 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004797
Akinobu Mita82069372013-10-14 22:48:04 +09004798static struct attribute *sdebug_drv_attrs[] = {
4799 &driver_attr_delay.attr,
4800 &driver_attr_opts.attr,
4801 &driver_attr_ptype.attr,
4802 &driver_attr_dsense.attr,
4803 &driver_attr_fake_rw.attr,
4804 &driver_attr_no_lun_0.attr,
4805 &driver_attr_num_tgts.attr,
4806 &driver_attr_dev_size_mb.attr,
4807 &driver_attr_num_parts.attr,
4808 &driver_attr_every_nth.attr,
4809 &driver_attr_max_luns.attr,
4810 &driver_attr_max_queue.attr,
4811 &driver_attr_no_uld.attr,
4812 &driver_attr_scsi_level.attr,
4813 &driver_attr_virtual_gb.attr,
4814 &driver_attr_add_host.attr,
4815 &driver_attr_vpd_use_hostno.attr,
4816 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004817 &driver_attr_statistics.attr,
4818 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004819 &driver_attr_dix.attr,
4820 &driver_attr_dif.attr,
4821 &driver_attr_guard.attr,
4822 &driver_attr_ato.attr,
4823 &driver_attr_map.attr,
4824 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004825 &driver_attr_host_lock.attr,
4826 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004827 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004828 NULL,
4829};
4830ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004832static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004833
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834static int __init scsi_debug_init(void)
4835{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004836 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 int host_to_add;
4838 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004839 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004841 atomic_set(&retired_max_queue, 0);
4842
Douglas Gilbert773642d2016-04-25 12:16:28 -04004843 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004844 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004845 sdebug_ndelay = 0;
4846 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04004847 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004848
Douglas Gilbert773642d2016-04-25 12:16:28 -04004849 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04004850 case 512:
4851 case 1024:
4852 case 2048:
4853 case 4096:
4854 break;
4855 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004856 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004857 return -EINVAL;
4858 }
4859
Douglas Gilbert773642d2016-04-25 12:16:28 -04004860 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004861
4862 case SD_DIF_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004863 break;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004864 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004865 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004866 case SD_DIF_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004867 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004868 break;
4869
4870 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004871 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004872 return -EINVAL;
4873 }
4874
Douglas Gilbert773642d2016-04-25 12:16:28 -04004875 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004876 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004877 return -EINVAL;
4878 }
4879
Douglas Gilbert773642d2016-04-25 12:16:28 -04004880 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004881 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004882 return -EINVAL;
4883 }
4884
Douglas Gilbert773642d2016-04-25 12:16:28 -04004885 if (sdebug_physblk_exp > 15) {
4886 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004887 return -EINVAL;
4888 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004889 if (sdebug_max_luns > 256) {
4890 pr_warn("max_luns can be no more than 256, use default\n");
4891 sdebug_max_luns = DEF_MAX_LUNS;
4892 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004893
Douglas Gilbert773642d2016-04-25 12:16:28 -04004894 if (sdebug_lowest_aligned > 0x3fff) {
4895 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004896 return -EINVAL;
4897 }
4898
Douglas Gilbertc4837392016-05-06 00:40:26 -04004899 if (submit_queues < 1) {
4900 pr_err("submit_queues must be 1 or more\n");
4901 return -EINVAL;
4902 }
4903 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
4904 GFP_KERNEL);
4905 if (sdebug_q_arr == NULL)
4906 return -ENOMEM;
4907 for (k = 0; k < submit_queues; ++k)
4908 spin_lock_init(&sdebug_q_arr[k].qc_lock);
4909
Douglas Gilbert773642d2016-04-25 12:16:28 -04004910 if (sdebug_dev_size_mb < 1)
4911 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4912 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4913 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004914 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915
4916 /* play around with geometry, don't waste too much on track 0 */
4917 sdebug_heads = 8;
4918 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004919 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004921 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02004922 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4924 (sdebug_sectors_per * sdebug_heads);
4925 if (sdebug_cylinders_per >= 1024) {
4926 /* other LLDs do this; implies >= 1GB ram disk ... */
4927 sdebug_heads = 255;
4928 sdebug_sectors_per = 63;
4929 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4930 (sdebug_sectors_per * sdebug_heads);
4931 }
4932
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004933 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004934 fake_storep = vmalloc(sz);
4935 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004936 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004937 ret = -ENOMEM;
4938 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004939 }
4940 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004941 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004942 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944
Douglas Gilbert773642d2016-04-25 12:16:28 -04004945 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004946 int dif_size;
4947
4948 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4949 dif_storep = vmalloc(dif_size);
4950
Tomas Winklerc12879702015-07-28 16:54:20 +03004951 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004952
4953 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004954 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004955 ret = -ENOMEM;
4956 goto free_vm;
4957 }
4958
4959 memset(dif_storep, 0xff, dif_size);
4960 }
4961
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004962 /* Logical Block Provisioning */
4963 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004964 sdebug_unmap_max_blocks =
4965 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004966
Douglas Gilbert773642d2016-04-25 12:16:28 -04004967 sdebug_unmap_max_desc =
4968 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04004969
Douglas Gilbert773642d2016-04-25 12:16:28 -04004970 sdebug_unmap_granularity =
4971 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004972
Douglas Gilbert773642d2016-04-25 12:16:28 -04004973 if (sdebug_unmap_alignment &&
4974 sdebug_unmap_granularity <=
4975 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004976 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004977 ret = -EINVAL;
4978 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004979 }
4980
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004981 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4982 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004983
Tomas Winklerc12879702015-07-28 16:54:20 +03004984 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004985
4986 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004987 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004988 ret = -ENOMEM;
4989 goto free_vm;
4990 }
4991
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004992 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004993
4994 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004995 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004996 map_region(0, 2);
4997 }
4998
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004999 pseudo_primary = root_device_register("pseudo_0");
5000 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005001 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005002 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005003 goto free_vm;
5004 }
5005 ret = bus_register(&pseudo_lld_bus);
5006 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005007 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005008 goto dev_unreg;
5009 }
5010 ret = driver_register(&sdebug_driverfs_driver);
5011 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005012 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005013 goto bus_unreg;
5014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015
Douglas Gilbert773642d2016-04-25 12:16:28 -04005016 host_to_add = sdebug_add_host;
5017 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018
5019 for (k = 0; k < host_to_add; k++) {
5020 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005021 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022 break;
5023 }
5024 }
5025
Douglas Gilbert773642d2016-04-25 12:16:28 -04005026 if (sdebug_verbose)
5027 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005028
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005030
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005031bus_unreg:
5032 bus_unregister(&pseudo_lld_bus);
5033dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005034 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005035free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005036 vfree(map_storep);
5037 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005038 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005039free_q_arr:
5040 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005041 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042}
5043
5044static void __exit scsi_debug_exit(void)
5045{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005046 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047
5048 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005049 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 for (; k; k--)
5051 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 driver_unregister(&sdebug_driverfs_driver);
5053 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005054 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055
Tomas Winklerde232af2015-07-28 16:54:22 +03005056 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005058 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059}
5060
5061device_initcall(scsi_debug_init);
5062module_exit(scsi_debug_exit);
5063
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064static void sdebug_release_adapter(struct device * dev)
5065{
5066 struct sdebug_host_info *sdbg_host;
5067
5068 sdbg_host = to_sdebug_host(dev);
5069 kfree(sdbg_host);
5070}
5071
5072static int sdebug_add_adapter(void)
5073{
5074 int k, devs_per_host;
5075 int error = 0;
5076 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005077 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005079 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005081 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 return -ENOMEM;
5083 }
5084
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
5086
Douglas Gilbert773642d2016-04-25 12:16:28 -04005087 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005089 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5090 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005091 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092 error = -ENOMEM;
5093 goto clean;
5094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 }
5096
5097 spin_lock(&sdebug_host_list_lock);
5098 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5099 spin_unlock(&sdebug_host_list_lock);
5100
5101 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005102 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005104 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105
5106 error = device_register(&sdbg_host->dev);
5107
5108 if (error)
5109 goto clean;
5110
Douglas Gilbert773642d2016-04-25 12:16:28 -04005111 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 return error;
5113
5114clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005115 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5116 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 list_del(&sdbg_devinfo->dev_list);
5118 kfree(sdbg_devinfo);
5119 }
5120
5121 kfree(sdbg_host);
5122 return error;
5123}
5124
5125static void sdebug_remove_adapter(void)
5126{
5127 struct sdebug_host_info * sdbg_host = NULL;
5128
5129 spin_lock(&sdebug_host_list_lock);
5130 if (!list_empty(&sdebug_host_list)) {
5131 sdbg_host = list_entry(sdebug_host_list.prev,
5132 struct sdebug_host_info, host_list);
5133 list_del(&sdbg_host->host_list);
5134 }
5135 spin_unlock(&sdebug_host_list_lock);
5136
5137 if (!sdbg_host)
5138 return;
5139
Douglas Gilbert773642d2016-04-25 12:16:28 -04005140 device_unregister(&sdbg_host->dev);
5141 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142}
5143
Douglas Gilbertfd321192016-04-25 12:16:33 -04005144static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005145{
5146 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005147 struct sdebug_dev_info *devip;
5148
Douglas Gilbertc4837392016-05-06 00:40:26 -04005149 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005150 devip = (struct sdebug_dev_info *)sdev->hostdata;
5151 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005152 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005153 return -ENODEV;
5154 }
5155 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005156
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005157 if (qdepth < 1)
5158 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005159 /* allow to exceed max host qc_arr elements for testing */
5160 if (qdepth > SDEBUG_CANQUEUE + 10)
5161 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005162 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005163
Douglas Gilbert773642d2016-04-25 12:16:28 -04005164 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005165 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005166 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005167 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005168 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005169 return sdev->queue_depth;
5170}
5171
Douglas Gilbertc4837392016-05-06 00:40:26 -04005172static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005173{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005174 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005175 if (sdebug_every_nth < -1)
5176 sdebug_every_nth = -1;
5177 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005178 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005179 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005180 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005181 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005182 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005183 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005184}
5185
Douglas Gilbertfd321192016-04-25 12:16:33 -04005186static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5187 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005188{
5189 u8 sdeb_i;
5190 struct scsi_device *sdp = scp->device;
5191 const struct opcode_info_t *oip;
5192 const struct opcode_info_t *r_oip;
5193 struct sdebug_dev_info *devip;
5194 u8 *cmd = scp->cmnd;
5195 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
5196 int k, na;
5197 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005198 u32 flags;
5199 u16 sa;
5200 u8 opcode = cmd[0];
5201 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005202
5203 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005204 if (sdebug_statistics)
5205 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005206 if (unlikely(sdebug_verbose &&
5207 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005208 char b[120];
5209 int n, len, sb;
5210
5211 len = scp->cmd_len;
5212 sb = (int)sizeof(b);
5213 if (len > 32)
5214 strcpy(b, "too long, over 32 bytes");
5215 else {
5216 for (k = 0, n = 0; k < len && n < sb; ++k)
5217 n += scnprintf(b + n, sb - n, "%02x ",
5218 (u32)cmd[k]);
5219 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005220 if (sdebug_mq_active)
5221 sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
5222 my_name, blk_mq_unique_tag(scp->request),
5223 b);
5224 else
5225 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
5226 b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005227 }
Tomas Winkler34d55432015-07-28 16:54:21 +03005228 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005229 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5230 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005231
5232 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5233 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5234 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005235 if (unlikely(!devip)) {
5236 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005237 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005238 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005239 }
5240 na = oip->num_attached;
5241 r_pfp = oip->pfp;
5242 if (na) { /* multiple commands with this opcode */
5243 r_oip = oip;
5244 if (FF_SA & r_oip->flags) {
5245 if (F_SA_LOW & oip->flags)
5246 sa = 0x1f & cmd[1];
5247 else
5248 sa = get_unaligned_be16(cmd + 8);
5249 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5250 if (opcode == oip->opcode && sa == oip->sa)
5251 break;
5252 }
5253 } else { /* since no service action only check opcode */
5254 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5255 if (opcode == oip->opcode)
5256 break;
5257 }
5258 }
5259 if (k > na) {
5260 if (F_SA_LOW & r_oip->flags)
5261 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5262 else if (F_SA_HIGH & r_oip->flags)
5263 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5264 else
5265 mk_sense_invalid_opcode(scp);
5266 goto check_cond;
5267 }
5268 } /* else (when na==0) we assume the oip is a match */
5269 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005270 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005271 mk_sense_invalid_opcode(scp);
5272 goto check_cond;
5273 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005274 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005275 if (sdebug_verbose)
5276 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5277 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005278 mk_sense_invalid_opcode(scp);
5279 goto check_cond;
5280 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005281 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005282 u8 rem;
5283 int j;
5284
5285 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5286 rem = ~oip->len_mask[k] & cmd[k];
5287 if (rem) {
5288 for (j = 7; j >= 0; --j, rem <<= 1) {
5289 if (0x80 & rem)
5290 break;
5291 }
5292 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5293 goto check_cond;
5294 }
5295 }
5296 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005297 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005298 find_first_bit(devip->uas_bm,
5299 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005300 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005301 if (errsts)
5302 goto check_cond;
5303 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005304 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005305 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005306 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005307 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5308 "%s\n", my_name, "initializing command "
5309 "required");
5310 errsts = check_condition_result;
5311 goto fini;
5312 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005313 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005314 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005315 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005316 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005317 return 0; /* ignore command: make trouble */
5318 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005319 if (likely(oip->pfp))
5320 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005321 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5322 errsts = r_pfp(scp, devip);
5323
5324fini:
5325 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005326 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005327check_cond:
5328 return schedule_resp(scp, devip, check_condition_result, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005329err_out:
5330 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005331}
5332
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005333static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005334 .show_info = scsi_debug_show_info,
5335 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005336 .proc_name = sdebug_proc_name,
5337 .name = "SCSI DEBUG",
5338 .info = scsi_debug_info,
5339 .slave_alloc = scsi_debug_slave_alloc,
5340 .slave_configure = scsi_debug_slave_configure,
5341 .slave_destroy = scsi_debug_slave_destroy,
5342 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005343 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005344 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005345 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005346 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005347 .eh_target_reset_handler = scsi_debug_target_reset,
5348 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005349 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005350 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005351 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005352 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005353 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005354 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005355 .use_clustering = DISABLE_CLUSTERING,
5356 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005357 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005358};
5359
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360static int sdebug_driver_probe(struct device * dev)
5361{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005362 int error = 0;
5363 struct sdebug_host_info *sdbg_host;
5364 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005365 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005366
5367 sdbg_host = to_sdebug_host(dev);
5368
Douglas Gilbert773642d2016-04-25 12:16:28 -04005369 sdebug_driver_template.can_queue = sdebug_max_queue;
5370 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005371 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005372 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5373 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005374 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005375 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005377 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005378 if (submit_queues > nr_cpu_ids) {
5379 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n",
5380 my_name, submit_queues, nr_cpu_ids);
5381 submit_queues = nr_cpu_ids;
5382 }
5383 /* Decide whether to tell scsi subsystem that we want mq */
5384 /* Following should give the same answer for each host */
5385 sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
5386 if (sdebug_mq_active)
5387 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
5389 sdbg_host->shost = hpnt;
5390 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005391 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5392 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005394 hpnt->max_id = sdebug_num_tgts;
5395 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005396 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005398 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005399
Douglas Gilbert773642d2016-04-25 12:16:28 -04005400 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005401
5402 case SD_DIF_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005403 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005404 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005405 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005406 break;
5407
5408 case SD_DIF_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005409 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005410 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005411 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005412 break;
5413
5414 case SD_DIF_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005415 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005416 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005417 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005418 break;
5419
5420 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005421 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005422 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005423 break;
5424 }
5425
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005426 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005427
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005428 if (have_dif_prot || sdebug_dix)
5429 pr_info("host protection%s%s%s%s%s%s%s\n",
5430 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5431 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5432 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5433 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5434 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5435 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5436 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005437
Douglas Gilbert773642d2016-04-25 12:16:28 -04005438 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005439 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5440 else
5441 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5442
Douglas Gilbert773642d2016-04-25 12:16:28 -04005443 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5444 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005445 if (sdebug_every_nth) /* need stats counters for every_nth */
5446 sdebug_statistics = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 error = scsi_add_host(hpnt, &sdbg_host->dev);
5448 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005449 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 error = -ENODEV;
5451 scsi_host_put(hpnt);
5452 } else
5453 scsi_scan_host(hpnt);
5454
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005455 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456}
5457
5458static int sdebug_driver_remove(struct device * dev)
5459{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005461 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462
5463 sdbg_host = to_sdebug_host(dev);
5464
5465 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005466 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 return -ENODEV;
5468 }
5469
5470 scsi_remove_host(sdbg_host->shost);
5471
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005472 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5473 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474 list_del(&sdbg_devinfo->dev_list);
5475 kfree(sdbg_devinfo);
5476 }
5477
5478 scsi_host_put(sdbg_host->shost);
5479 return 0;
5480}
5481
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005482static int pseudo_lld_bus_match(struct device *dev,
5483 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005485 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005487
5488static struct bus_type pseudo_lld_bus = {
5489 .name = "pseudo",
5490 .match = pseudo_lld_bus_match,
5491 .probe = sdebug_driver_probe,
5492 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005493 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005494};