blob: fc0246c322942530383cc6e75017e8857bc0aeb3 [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 Gilberte46b0342014-08-05 12:21:53 +0200128#define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */
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 Gilbertc2206092016-04-25 12:16:31 -0400138#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400140#define SDEBUG_LUN_0_VAL 0
141
Douglas Gilbert773642d2016-04-25 12:16:28 -0400142/* bit mask values for sdebug_opts */
143#define SDEBUG_OPT_NOISE 1
144#define SDEBUG_OPT_MEDIUM_ERR 2
145#define SDEBUG_OPT_TIMEOUT 4
146#define SDEBUG_OPT_RECOVERED_ERR 8
147#define SDEBUG_OPT_TRANSPORT_ERR 16
148#define SDEBUG_OPT_DIF_ERR 32
149#define SDEBUG_OPT_DIX_ERR 64
150#define SDEBUG_OPT_MAC_TIMEOUT 128
151#define SDEBUG_OPT_SHORT_TRANSFER 0x100
152#define SDEBUG_OPT_Q_NOISE 0x200
153#define SDEBUG_OPT_ALL_TSF 0x400
154#define SDEBUG_OPT_RARE_TSF 0x800
155#define SDEBUG_OPT_N_WCE 0x1000
156#define SDEBUG_OPT_RESET_NOISE 0x2000
157#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
158#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
159 SDEBUG_OPT_RESET_NOISE)
160#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
161 SDEBUG_OPT_TRANSPORT_ERR | \
162 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
163 SDEBUG_OPT_SHORT_TRANSFER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400165 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400167 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500168 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400169 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 *
171 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400172 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400174 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500175 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400176 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
177 * This will continue on every subsequent command until some other action
178 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
179 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 */
181
Douglas Gilbertfd321192016-04-25 12:16:33 -0400182/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400183 * priority order. In the subset implemented here lower numbers have higher
184 * priority. The UA numbers should be a sequence starting from 0 with
185 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
186#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
187#define SDEBUG_UA_BUS_RESET 1
188#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500189#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500190#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500191#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
192#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
193#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400194
Douglas Gilbert773642d2016-04-25 12:16:28 -0400195/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 * sector on read commands: */
197#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500198#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
200/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
201 * or "peripheral device" addressing (value 0) */
202#define SAM2_LUN_ADDRESS_METHOD 0
203
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400204/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
205 * (for response) at one time. Can be reduced by max_queue option. Command
Douglas Gilbertc2206092016-04-25 12:16:31 -0400206 * responses are not queued when jdelay=0 and ndelay=0. The per-device
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400207 * DEF_CMD_PER_LUN can be changed via sysfs:
208 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
209 * SCSI_DEBUG_CANQUEUE. */
210#define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */
211#define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
212#define DEF_CMD_PER_LUN 255
213
214#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
215#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
216#endif
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400217
Douglas Gilbertfd321192016-04-25 12:16:33 -0400218#define F_D_IN 1
219#define F_D_OUT 2
220#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
221#define F_D_UNKN 8
222#define F_RL_WLUN_OK 0x10
223#define F_SKIP_UA 0x20
224#define F_DELAY_OVERR 0x40
225#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
226#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
227#define F_INV_OP 0x200
228#define F_FAKE_RW 0x400
229#define F_M_ACCESS 0x800 /* media access */
230
231#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
232#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
233#define FF_SA (F_SA_HIGH | F_SA_LOW)
234
235#define SDEBUG_MAX_PARTS 4
236
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400237#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400238
239
240struct sdebug_dev_info {
241 struct list_head dev_list;
242 unsigned int channel;
243 unsigned int target;
244 u64 lun;
245 struct sdebug_host_info *sdbg_host;
246 unsigned long uas_bm[1];
247 atomic_t num_in_q;
248 char stopped; /* TODO: should be atomic */
249 bool used;
250};
251
252struct sdebug_host_info {
253 struct list_head host_list;
254 struct Scsi_Host *shost;
255 struct device dev;
256 struct list_head dev_info_list;
257};
258
259#define to_sdebug_host(d) \
260 container_of(d, struct sdebug_host_info, dev)
261
262struct sdebug_defer {
263 struct hrtimer hrt;
264 struct execute_work ew;
265 int qa_indx;
266};
267
268struct sdebug_queued_cmd {
269 /* in_use flagged by a bit in queued_in_use_bm[] */
270 struct sdebug_defer *sd_dp;
271 struct scsi_cmnd *a_cmnd;
272};
273
274struct sdebug_scmd_extra_t {
275 bool inj_recovered;
276 bool inj_transport;
277 bool inj_dif;
278 bool inj_dix;
279 bool inj_short;
280};
281
282struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400283 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
284 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400285 u8 opcode; /* if num_attached > 0, preferred */
286 u16 sa; /* service action */
287 u32 flags; /* OR-ed set of SDEB_F_* */
288 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
289 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
290 u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
291 /* ignore cdb bytes after position 15 */
292};
293
294/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500295enum sdeb_opcode_index {
296 SDEB_I_INVALID_OPCODE = 0,
297 SDEB_I_INQUIRY = 1,
298 SDEB_I_REPORT_LUNS = 2,
299 SDEB_I_REQUEST_SENSE = 3,
300 SDEB_I_TEST_UNIT_READY = 4,
301 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
302 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
303 SDEB_I_LOG_SENSE = 7,
304 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
305 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
306 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
307 SDEB_I_START_STOP = 11,
308 SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
309 SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
310 SDEB_I_MAINT_IN = 14,
311 SDEB_I_MAINT_OUT = 15,
312 SDEB_I_VERIFY = 16, /* 10 only */
313 SDEB_I_VARIABLE_LEN = 17,
314 SDEB_I_RESERVE = 18, /* 6, 10 */
315 SDEB_I_RELEASE = 19, /* 6, 10 */
316 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
317 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
318 SDEB_I_ATA_PT = 22, /* 12, 16 */
319 SDEB_I_SEND_DIAG = 23,
320 SDEB_I_UNMAP = 24,
321 SDEB_I_XDWRITEREAD = 25, /* 10 only */
322 SDEB_I_WRITE_BUFFER = 26,
323 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
324 SDEB_I_SYNC_CACHE = 28, /* 10 only */
325 SDEB_I_COMP_WRITE = 29,
326 SDEB_I_LAST_ELEMENT = 30, /* keep this last */
327};
328
329static const unsigned char opcode_ind_arr[256] = {
330/* 0x0; 0x0->0x1f: 6 byte cdbs */
331 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
332 0, 0, 0, 0,
333 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
334 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
335 SDEB_I_RELEASE,
336 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
337 SDEB_I_ALLOW_REMOVAL, 0,
338/* 0x20; 0x20->0x3f: 10 byte cdbs */
339 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
340 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
341 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
342 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
343/* 0x40; 0x40->0x5f: 10 byte cdbs */
344 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
345 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
346 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
347 SDEB_I_RELEASE,
348 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400349/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
352 0, SDEB_I_VARIABLE_LEN,
353/* 0x80; 0x80->0x9f: 16 byte cdbs */
354 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
355 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
356 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
357 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
358/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
359 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
360 SDEB_I_MAINT_OUT, 0, 0, 0,
361 SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
362 0, 0, 0, 0,
363 0, 0, 0, 0, 0, 0, 0, 0,
364 0, 0, 0, 0, 0, 0, 0, 0,
365/* 0xc0; 0xc0->0xff: vendor specific */
366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
370};
371
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500372static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
373static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
374static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
375static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
376static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
377static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
378static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
379static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
380static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
381static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
382static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
383static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
384static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
385static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500386static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
387static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500388static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
389static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
390static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500391static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500392static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500393
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500394static const struct opcode_info_t msense_iarr[1] = {
395 {0, 0x1a, 0, F_D_IN, NULL, NULL,
396 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
397};
398
399static const struct opcode_info_t mselect_iarr[1] = {
400 {0, 0x15, 0, F_D_OUT, NULL, NULL,
401 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
402};
403
404static const struct opcode_info_t read_iarr[3] = {
405 {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
406 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
407 0, 0, 0, 0} },
408 {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
409 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
410 {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
411 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
412 0xc7, 0, 0, 0, 0} },
413};
414
415static const struct opcode_info_t write_iarr[3] = {
416 {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
417 {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
418 0, 0, 0, 0} },
419 {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
420 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
421 {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
422 {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
423 0xc7, 0, 0, 0, 0} },
424};
425
426static const struct opcode_info_t sa_in_iarr[1] = {
427 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
428 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
429 0xff, 0xff, 0xff, 0, 0xc7} },
430};
431
432static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
433 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
434 NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
435 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
436};
437
438static const struct opcode_info_t maint_in_iarr[2] = {
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500439 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500440 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
441 0xc7, 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500442 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500443 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
444 0, 0} },
445};
446
447static const struct opcode_info_t write_same_iarr[1] = {
448 {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
449 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
450 0xff, 0xff, 0xff, 0x1f, 0xc7} },
451};
452
453static const struct opcode_info_t reserve_iarr[1] = {
454 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
455 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
456};
457
458static const struct opcode_info_t release_iarr[1] = {
459 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
460 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
461};
462
463
464/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
465 * plus the terminating elements for logic that scans this table such as
466 * REPORT SUPPORTED OPERATION CODES. */
467static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
468/* 0 */
469 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
470 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
471 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
472 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
473 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
474 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
475 0, 0} },
476 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
477 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
478 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
479 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
480 {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
481 {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
482 0} },
483 {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
484 {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
485 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
486 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
487 0, 0, 0} },
488 {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
489 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
490 0, 0} },
491 {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
492 {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
493 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */
494/* 10 */
495 {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
496 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
497 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */
498 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
499 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
500 {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
501 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
502 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
503 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
504 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
505 {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
506 {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
507 0} },
508 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
509 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500510 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
511 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
512 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500513 {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
514 vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
515 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
516 {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
517 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
518 0} },
519 {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
520 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
521 0} },
522/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500523 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
524 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500525 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
526 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
527 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
528 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
529 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
530 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
531 {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
532 {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
533 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
534 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
535 0, 0, 0, 0, 0, 0} },
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500536 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
537 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
538 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500539 {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
540 write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
541 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
542 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
543 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
544 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500545 {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500546 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
547 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
548
549/* 30 */
550 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
551 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
552};
553
Douglas Gilbert773642d2016-04-25 12:16:28 -0400554static int sdebug_add_host = DEF_NUM_HOST;
555static int sdebug_ato = DEF_ATO;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400556static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400557static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
558static int sdebug_dif = DEF_DIF;
559static int sdebug_dix = DEF_DIX;
560static int sdebug_dsense = DEF_D_SENSE;
561static int sdebug_every_nth = DEF_EVERY_NTH;
562static int sdebug_fake_rw = DEF_FAKE_RW;
563static unsigned int sdebug_guard = DEF_GUARD;
564static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
565static int sdebug_max_luns = DEF_MAX_LUNS;
566static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400567static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400568static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400569static int sdebug_no_lun_0 = DEF_NO_LUN_0;
570static int sdebug_no_uld;
571static int sdebug_num_parts = DEF_NUM_PARTS;
572static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
573static int sdebug_opt_blks = DEF_OPT_BLKS;
574static int sdebug_opts = DEF_OPTS;
575static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400576static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400577static int sdebug_scsi_level = DEF_SCSI_LEVEL;
578static int sdebug_sector_size = DEF_SECTOR_SIZE;
579static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
580static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
581static unsigned int sdebug_lbpu = DEF_LBPU;
582static unsigned int sdebug_lbpws = DEF_LBPWS;
583static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
584static unsigned int sdebug_lbprz = DEF_LBPRZ;
585static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
586static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
587static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
588static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
589static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
590static bool sdebug_removable = DEF_REMOVABLE;
591static bool sdebug_clustering;
592static bool sdebug_host_lock = DEF_HOST_LOCK;
593static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500594static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400595static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400596static bool have_dif_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400598static atomic_t sdebug_cmnd_count;
599static atomic_t sdebug_completions;
600static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400602static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603static sector_t sdebug_capacity; /* in sectors */
604
605/* old BIOS stuff, kernel may get rid of them but some mode sense pages
606 may still need them */
607static int sdebug_heads; /* heads per disk */
608static int sdebug_cylinders_per; /* cylinders per surface */
609static int sdebug_sectors_per; /* sectors per cylinder */
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611static LIST_HEAD(sdebug_host_list);
612static DEFINE_SPINLOCK(sdebug_host_list_lock);
613
Douglas Gilbertfd321192016-04-25 12:16:33 -0400614static unsigned char *fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900615static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400616static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Martin K. Petersen44d92692009-10-15 14:45:27 -0400618static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400619static int num_aborts;
620static int num_dev_resets;
621static int num_target_resets;
622static int num_bus_resets;
623static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500624static int dix_writes;
625static int dix_reads;
626static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
Douglas Gilbertfd321192016-04-25 12:16:33 -0400628static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
629static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631static DEFINE_SPINLOCK(queued_arr_lock);
632static DEFINE_RWLOCK(atomic_rw);
633
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400634static char sdebug_proc_name[] = MY_NAME;
635static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637static struct bus_type pseudo_lld_bus;
638
639static struct device_driver sdebug_driverfs_driver = {
640 .name = sdebug_proc_name,
641 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642};
643
644static const int check_condition_result =
645 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
646
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500647static const int illegal_condition_result =
648 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
649
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400650static const int device_qfull_result =
651 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
652
Douglas Gilbertfd321192016-04-25 12:16:33 -0400653
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400654static inline unsigned int scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400655{
656 return 0 == sdebug_fake_rw &&
657 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
658}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400659
Akinobu Mita14faa942013-09-18 21:27:24 +0900660static void *fake_store(unsigned long long lba)
661{
662 lba = do_div(lba, sdebug_store_sectors);
663
Douglas Gilbert773642d2016-04-25 12:16:28 -0400664 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900665}
666
667static struct sd_dif_tuple *dif_store(sector_t sector)
668{
Arnd Bergmann49413112015-11-20 17:38:28 +0100669 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900670
671 return dif_storep + sector;
672}
673
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900674static void sdebug_max_tgts_luns(void)
675{
676 struct sdebug_host_info *sdbg_host;
677 struct Scsi_Host *hpnt;
678
679 spin_lock(&sdebug_host_list_lock);
680 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
681 hpnt = sdbg_host->shost;
682 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400683 (sdebug_num_tgts > hpnt->this_id))
684 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900685 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400686 hpnt->max_id = sdebug_num_tgts;
687 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300688 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900689 }
690 spin_unlock(&sdebug_host_list_lock);
691}
692
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500693enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
694
695/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400696static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
697 enum sdeb_cmd_data c_d,
698 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500699{
700 unsigned char *sbuff;
701 u8 sks[4];
702 int sl, asc;
703
704 sbuff = scp->sense_buffer;
705 if (!sbuff) {
706 sdev_printk(KERN_ERR, scp->device,
707 "%s: sense_buffer is NULL\n", __func__);
708 return;
709 }
710 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
711 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400712 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500713 memset(sks, 0, sizeof(sks));
714 sks[0] = 0x80;
715 if (c_d)
716 sks[0] |= 0x40;
717 if (in_bit >= 0) {
718 sks[0] |= 0x8;
719 sks[0] |= 0x7 & in_bit;
720 }
721 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400722 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500723 sl = sbuff[7] + 8;
724 sbuff[7] = sl;
725 sbuff[sl] = 0x2;
726 sbuff[sl + 1] = 0x6;
727 memcpy(sbuff + sl + 4, sks, 3);
728 } else
729 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400730 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500731 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
732 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
733 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
734}
735
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400736static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900737{
738 unsigned char *sbuff;
739
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400740 sbuff = scp->sense_buffer;
741 if (!sbuff) {
742 sdev_printk(KERN_ERR, scp->device,
743 "%s: sense_buffer is NULL\n", __func__);
744 return;
745 }
746 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900747
Douglas Gilbert773642d2016-04-25 12:16:28 -0400748 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900749
Douglas Gilbert773642d2016-04-25 12:16:28 -0400750 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400751 sdev_printk(KERN_INFO, scp->device,
752 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
753 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900754}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Douglas Gilbertfd321192016-04-25 12:16:33 -0400756static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500757{
758 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
759}
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
762{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400763 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400764 if (0x1261 == cmd)
765 sdev_printk(KERN_INFO, dev,
766 "%s: BLKFLSBUF [0x1261]\n", __func__);
767 else if (0x5331 == cmd)
768 sdev_printk(KERN_INFO, dev,
769 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
770 __func__);
771 else
772 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
773 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
775 return -EINVAL;
776 /* return -ENOTTY; // correct return but upsets fdisk */
777}
778
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500779static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
780{
781 struct sdebug_host_info *sdhp;
782 struct sdebug_dev_info *dp;
783
784 spin_lock(&sdebug_host_list_lock);
785 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
786 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
787 if ((devip->sdbg_host == dp->sdbg_host) &&
788 (devip->target == dp->target))
789 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
790 }
791 }
792 spin_unlock(&sdebug_host_list_lock);
793}
794
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400795static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400797 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400798
799 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
800 if (k != SDEBUG_NUM_UAS) {
801 const char *cp = NULL;
802
803 switch (k) {
804 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400805 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
806 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400807 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400808 cp = "power on reset";
809 break;
810 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400811 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
812 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400813 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400814 cp = "bus reset";
815 break;
816 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400817 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
818 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400819 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400820 cp = "mode parameters changed";
821 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500822 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400823 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
824 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400825 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500826 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500827 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500828 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400829 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400830 TARGET_CHANGED_ASC,
831 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400832 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500833 cp = "microcode has been changed";
834 break;
835 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400836 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500837 TARGET_CHANGED_ASC,
838 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400839 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500840 cp = "microcode has been changed without reset";
841 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500842 case SDEBUG_UA_LUNS_CHANGED:
843 /*
844 * SPC-3 behavior is to report a UNIT ATTENTION with
845 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
846 * on the target, until a REPORT LUNS command is
847 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400848 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500849 * values as struct scsi_device->scsi_level.
850 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400851 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500852 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400853 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500854 TARGET_CHANGED_ASC,
855 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400856 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500857 cp = "reported luns data has changed";
858 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400859 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400860 pr_warn("unexpected unit attention code=%d\n", k);
861 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400862 cp = "unknown";
863 break;
864 }
865 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400866 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400867 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400868 "%s reports: Unit attention: %s\n",
869 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 return check_condition_result;
871 }
872 return 0;
873}
874
875/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900876static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 int arr_len)
878{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900879 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900880 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900882 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900884 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400885 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900886
887 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
888 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700889 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900890
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return 0;
892}
893
894/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900895static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
896 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900898 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900900 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900902
903 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904}
905
906
907static const char * inq_vendor_id = "Linux ";
908static const char * inq_product_id = "scsi_debug ";
Douglas Gilbert773642d2016-04-25 12:16:28 -0400909static const char *inq_product_rev = "0186"; /* version less '.' */
910static const u64 naa5_comp_a = 0x5222222000000000ULL;
911static const u64 naa5_comp_b = 0x5333333000000000ULL;
912static const u64 naa5_comp_c = 0x5111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400914/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200915static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
916 int target_dev_id, int dev_id_num,
917 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400918 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400920 int num, port_a;
921 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400923 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 /* T10 vendor identifier field format (faked) */
925 arr[0] = 0x2; /* ASCII */
926 arr[1] = 0x1;
927 arr[2] = 0x0;
928 memcpy(&arr[4], inq_vendor_id, 8);
929 memcpy(&arr[12], inq_product_id, 16);
930 memcpy(&arr[28], dev_id_str, dev_id_str_len);
931 num = 8 + 16 + dev_id_str_len;
932 arr[3] = num;
933 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400934 if (dev_id_num >= 0) {
935 /* NAA-5, Logical unit identifier (binary) */
936 arr[num++] = 0x1; /* binary (not necessarily sas) */
937 arr[num++] = 0x3; /* PIV=0, lu, naa */
938 arr[num++] = 0x0;
939 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400940 put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
941 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400942 /* Target relative port number */
943 arr[num++] = 0x61; /* proto=sas, binary */
944 arr[num++] = 0x94; /* PIV=1, target port, rel port */
945 arr[num++] = 0x0; /* reserved */
946 arr[num++] = 0x4; /* length */
947 arr[num++] = 0x0; /* reserved */
948 arr[num++] = 0x0; /* reserved */
949 arr[num++] = 0x0;
950 arr[num++] = 0x1; /* relative port A */
951 }
952 /* NAA-5, Target port identifier */
953 arr[num++] = 0x61; /* proto=sas, binary */
954 arr[num++] = 0x93; /* piv=1, target port, naa */
955 arr[num++] = 0x0;
956 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400957 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
958 num += 8;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200959 /* NAA-5, Target port group identifier */
960 arr[num++] = 0x61; /* proto=sas, binary */
961 arr[num++] = 0x95; /* piv=1, target port group id */
962 arr[num++] = 0x0;
963 arr[num++] = 0x4;
964 arr[num++] = 0;
965 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400966 put_unaligned_be16(port_group_id, arr + num);
967 num += 2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400968 /* NAA-5, Target device identifier */
969 arr[num++] = 0x61; /* proto=sas, binary */
970 arr[num++] = 0xa3; /* piv=1, target device, naa */
971 arr[num++] = 0x0;
972 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400973 put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
974 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400975 /* SCSI name string: Target device identifier */
976 arr[num++] = 0x63; /* proto=sas, UTF-8 */
977 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
978 arr[num++] = 0x0;
979 arr[num++] = 24;
980 memcpy(arr + num, "naa.52222220", 12);
981 num += 12;
982 snprintf(b, sizeof(b), "%08X", target_dev_id);
983 memcpy(arr + num, b, 8);
984 num += 8;
985 memset(arr + num, 0, 4);
986 num += 4;
987 return num;
988}
989
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400990static unsigned char vpd84_data[] = {
991/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
992 0x22,0x22,0x22,0x0,0xbb,0x1,
993 0x22,0x22,0x22,0x0,0xbb,0x2,
994};
995
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400996/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400997static int inquiry_evpd_84(unsigned char * arr)
998{
999 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1000 return sizeof(vpd84_data);
1001}
1002
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001003/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001004static int inquiry_evpd_85(unsigned char * arr)
1005{
1006 int num = 0;
1007 const char * na1 = "https://www.kernel.org/config";
1008 const char * na2 = "http://www.kernel.org/log";
1009 int plen, olen;
1010
1011 arr[num++] = 0x1; /* lu, storage config */
1012 arr[num++] = 0x0; /* reserved */
1013 arr[num++] = 0x0;
1014 olen = strlen(na1);
1015 plen = olen + 1;
1016 if (plen % 4)
1017 plen = ((plen / 4) + 1) * 4;
1018 arr[num++] = plen; /* length, null termianted, padded */
1019 memcpy(arr + num, na1, olen);
1020 memset(arr + num + olen, 0, plen - olen);
1021 num += plen;
1022
1023 arr[num++] = 0x4; /* lu, logging */
1024 arr[num++] = 0x0; /* reserved */
1025 arr[num++] = 0x0;
1026 olen = strlen(na2);
1027 plen = olen + 1;
1028 if (plen % 4)
1029 plen = ((plen / 4) + 1) * 4;
1030 arr[num++] = plen; /* length, null terminated, padded */
1031 memcpy(arr + num, na2, olen);
1032 memset(arr + num + olen, 0, plen - olen);
1033 num += plen;
1034
1035 return num;
1036}
1037
1038/* SCSI ports VPD page */
1039static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1040{
1041 int num = 0;
1042 int port_a, port_b;
1043
1044 port_a = target_dev_id + 1;
1045 port_b = port_a + 1;
1046 arr[num++] = 0x0; /* reserved */
1047 arr[num++] = 0x0; /* reserved */
1048 arr[num++] = 0x0;
1049 arr[num++] = 0x1; /* relative port 1 (primary) */
1050 memset(arr + num, 0, 6);
1051 num += 6;
1052 arr[num++] = 0x0;
1053 arr[num++] = 12; /* length tp descriptor */
1054 /* naa-5 target port identifier (A) */
1055 arr[num++] = 0x61; /* proto=sas, binary */
1056 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1057 arr[num++] = 0x0; /* reserved */
1058 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001059 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1060 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001061 arr[num++] = 0x0; /* reserved */
1062 arr[num++] = 0x0; /* reserved */
1063 arr[num++] = 0x0;
1064 arr[num++] = 0x2; /* relative port 2 (secondary) */
1065 memset(arr + num, 0, 6);
1066 num += 6;
1067 arr[num++] = 0x0;
1068 arr[num++] = 12; /* length tp descriptor */
1069 /* naa-5 target port identifier (B) */
1070 arr[num++] = 0x61; /* proto=sas, binary */
1071 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1072 arr[num++] = 0x0; /* reserved */
1073 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001074 put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1075 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001076
1077 return num;
1078}
1079
1080
1081static unsigned char vpd89_data[] = {
1082/* from 4th byte */ 0,0,0,0,
1083'l','i','n','u','x',' ',' ',' ',
1084'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1085'1','2','3','4',
10860x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
10870xec,0,0,0,
10880x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
10890,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
10900x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
10910x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
10920x53,0x41,
10930x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
10940x20,0x20,
10950x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
10960x10,0x80,
10970,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
10980x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
10990x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
11000,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
11010x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
11020x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11030,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
11040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11050,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11060,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11070x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11080,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11090xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11100,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
11110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11170,0,0,0,0,0,0,0,0,0,0,0,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,
11210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11220,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1123};
1124
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001125/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001126static int inquiry_evpd_89(unsigned char * arr)
1127{
1128 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1129 return sizeof(vpd89_data);
1130}
1131
1132
1133static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001134 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1135 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1136 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1137 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001138};
1139
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001140/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001141static int inquiry_evpd_b0(unsigned char * arr)
1142{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001143 unsigned int gran;
1144
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001145 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001146
1147 /* Optimal transfer length granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001148 gran = 1 << sdebug_physblk_exp;
1149 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001150
1151 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001152 if (sdebug_store_sectors > 0x400)
1153 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001154
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001155 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001156 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001157
Douglas Gilbert773642d2016-04-25 12:16:28 -04001158 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001159 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001160 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001161
1162 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001163 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001164 }
1165
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001166 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001167 if (sdebug_unmap_alignment) {
1168 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001169 arr[28] |= 0x80; /* UGAVALID */
1170 }
1171
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001172 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001173 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001174
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001175 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001176 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001177
1178 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001179
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001180 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181}
1182
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001183/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001184static int inquiry_evpd_b1(unsigned char *arr)
1185{
1186 memset(arr, 0, 0x3c);
1187 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001188 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1189 arr[2] = 0;
1190 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001191
1192 return 0x3c;
1193}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001195/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001196static int inquiry_evpd_b2(unsigned char *arr)
1197{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001198 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001199 arr[0] = 0; /* threshold exponent */
1200
Douglas Gilbert773642d2016-04-25 12:16:28 -04001201 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001202 arr[1] = 1 << 7;
1203
Douglas Gilbert773642d2016-04-25 12:16:28 -04001204 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001205 arr[1] |= 1 << 6;
1206
Douglas Gilbert773642d2016-04-25 12:16:28 -04001207 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001208 arr[1] |= 1 << 5;
1209
Douglas Gilbert773642d2016-04-25 12:16:28 -04001210 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001211 arr[1] |= 1 << 2;
1212
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001213 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001214}
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001217#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001219static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220{
1221 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001222 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001223 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001224 int alloc_len, n, ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001225 bool have_wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Douglas Gilbert773642d2016-04-25 12:16:28 -04001227 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001228 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1229 if (! arr)
1230 return DID_REQUEUE << 16;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001231 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001232 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001233 pq_pdt = TYPE_WLUN; /* present, wlun */
1234 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1235 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001236 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001237 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 arr[0] = pq_pdt;
1239 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001240 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001241 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 return check_condition_result;
1243 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001244 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001245 char lu_id_str[6];
1246 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001248 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1249 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001250 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001251 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001252 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001253 (devip->target * 1000) + devip->lun);
1254 target_dev_id = ((host_no + 1) * 2000) +
1255 (devip->target * 1000) - 3;
1256 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001258 arr[1] = cmd[2]; /*sanity */
1259 n = 4;
1260 arr[n++] = 0x0; /* this page */
1261 arr[n++] = 0x80; /* unit serial number */
1262 arr[n++] = 0x83; /* device identification */
1263 arr[n++] = 0x84; /* software interface ident. */
1264 arr[n++] = 0x85; /* management network addresses */
1265 arr[n++] = 0x86; /* extended inquiry */
1266 arr[n++] = 0x87; /* mode page policy */
1267 arr[n++] = 0x88; /* SCSI ports */
1268 arr[n++] = 0x89; /* ATA information */
1269 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001270 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001271 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
1272 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001273 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001275 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001277 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001279 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001280 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1281 target_dev_id, lu_id_num,
1282 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001283 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1284 arr[1] = cmd[2]; /*sanity */
1285 arr[3] = inquiry_evpd_84(&arr[4]);
1286 } else if (0x85 == cmd[2]) { /* Management network addresses */
1287 arr[1] = cmd[2]; /*sanity */
1288 arr[3] = inquiry_evpd_85(&arr[4]);
1289 } else if (0x86 == cmd[2]) { /* extended inquiry */
1290 arr[1] = cmd[2]; /*sanity */
1291 arr[3] = 0x3c; /* number of following entries */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001292 if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001293 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001294 else if (sdebug_dif)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001295 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1296 else
1297 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001298 arr[5] = 0x7; /* head of q, ordered + simple q's */
1299 } else if (0x87 == cmd[2]) { /* mode page policy */
1300 arr[1] = cmd[2]; /*sanity */
1301 arr[3] = 0x8; /* number of following entries */
1302 arr[4] = 0x2; /* disconnect-reconnect mp */
1303 arr[6] = 0x80; /* mlus, shared */
1304 arr[8] = 0x18; /* protocol specific lu */
1305 arr[10] = 0x82; /* mlus, per initiator port */
1306 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1307 arr[1] = cmd[2]; /*sanity */
1308 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1309 } else if (0x89 == cmd[2]) { /* ATA information */
1310 arr[1] = cmd[2]; /*sanity */
1311 n = inquiry_evpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001312 put_unaligned_be16(n, arr + 2);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001313 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1314 arr[1] = cmd[2]; /*sanity */
1315 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001316 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1317 arr[1] = cmd[2]; /*sanity */
1318 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001319 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001320 arr[1] = cmd[2]; /*sanity */
1321 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001323 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001324 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 return check_condition_result;
1326 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001327 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001328 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001329 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001330 kfree(arr);
1331 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 }
1333 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001334 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1335 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 arr[3] = 2; /* response_data_format==2 */
1337 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001338 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001339 if (sdebug_vpd_use_hostno == 0)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001340 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001341 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001343 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 memcpy(&arr[8], inq_vendor_id, 8);
1345 memcpy(&arr[16], inq_product_id, 16);
1346 memcpy(&arr[32], inq_product_rev, 4);
1347 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001348 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1349 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001350 n = 62;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001351 if (sdebug_ptype == TYPE_DISK) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001352 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001353 } else if (sdebug_ptype == TYPE_TAPE) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001354 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001356 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001357 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001359 kfree(arr);
1360 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361}
1362
Douglas Gilbertfd321192016-04-25 12:16:33 -04001363static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1364 0, 0, 0x0, 0x0};
1365
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366static int resp_requests(struct scsi_cmnd * scp,
1367 struct sdebug_dev_info * devip)
1368{
1369 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001370 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001371 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001372 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 int len = 18;
1374
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001375 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001376 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001377 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001378 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001379 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001380 arr[0] = 0x72;
1381 arr[1] = 0x0; /* NO_SENSE in sense_key */
1382 arr[2] = THRESHOLD_EXCEEDED;
1383 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001384 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001385 } else {
1386 arr[0] = 0x70;
1387 arr[2] = 0x0; /* NO_SENSE in sense_key */
1388 arr[7] = 0xa; /* 18 byte sense buffer */
1389 arr[12] = THRESHOLD_EXCEEDED;
1390 arr[13] = 0xff; /* TEST set and MRIE==6 */
1391 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001392 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001393 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001394 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001395 ; /* have sense and formats match */
1396 else if (arr[0] <= 0x70) {
1397 if (dsense) {
1398 memset(arr, 0, 8);
1399 arr[0] = 0x72;
1400 len = 8;
1401 } else {
1402 memset(arr, 0, 18);
1403 arr[0] = 0x70;
1404 arr[7] = 0xa;
1405 }
1406 } else if (dsense) {
1407 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001408 arr[0] = 0x72;
1409 arr[1] = sbuff[2]; /* sense key */
1410 arr[2] = sbuff[12]; /* asc */
1411 arr[3] = sbuff[13]; /* ascq */
1412 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001413 } else {
1414 memset(arr, 0, 18);
1415 arr[0] = 0x70;
1416 arr[2] = sbuff[1];
1417 arr[7] = 0xa;
1418 arr[12] = sbuff[1];
1419 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001420 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001421
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001422 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001423 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 return fill_from_dev_buffer(scp, arr, len);
1425}
1426
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001427static int resp_start_stop(struct scsi_cmnd * scp,
1428 struct sdebug_dev_info * devip)
1429{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001430 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001431 int power_cond, start;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001432
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001433 power_cond = (cmd[4] & 0xf0) >> 4;
1434 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001435 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001436 return check_condition_result;
1437 }
1438 start = cmd[4] & 1;
1439 if (start == devip->stopped)
1440 devip->stopped = !start;
1441 return 0;
1442}
1443
FUJITA Tomonori28898872008-03-30 00:59:55 +09001444static sector_t get_sdebug_capacity(void)
1445{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001446 static const unsigned int gibibyte = 1073741824;
1447
1448 if (sdebug_virtual_gb > 0)
1449 return (sector_t)sdebug_virtual_gb *
1450 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001451 else
1452 return sdebug_store_sectors;
1453}
1454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455#define SDEBUG_READCAP_ARR_SZ 8
1456static int resp_readcap(struct scsi_cmnd * scp,
1457 struct sdebug_dev_info * devip)
1458{
1459 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001460 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001463 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001465 if (sdebug_capacity < 0xffffffff) {
1466 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001467 put_unaligned_be32(capac, arr + 0);
1468 } else
1469 put_unaligned_be32(0xffffffff, arr + 0);
1470 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1472}
1473
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001474#define SDEBUG_READCAP16_ARR_SZ 32
1475static int resp_readcap16(struct scsi_cmnd * scp,
1476 struct sdebug_dev_info * devip)
1477{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001478 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001479 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001480 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001481
Douglas Gilbert773642d2016-04-25 12:16:28 -04001482 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001483 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001484 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001485 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001486 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1487 put_unaligned_be32(sdebug_sector_size, arr + 8);
1488 arr[13] = sdebug_physblk_exp & 0xf;
1489 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001490
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001491 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001492 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001493 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001494 arr[14] |= 0x40; /* LBPRZ */
1495 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001496
Douglas Gilbert773642d2016-04-25 12:16:28 -04001497 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001498
Douglas Gilbert773642d2016-04-25 12:16:28 -04001499 if (sdebug_dif) {
1500 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001501 arr[12] |= 1; /* PROT_EN */
1502 }
1503
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001504 return fill_from_dev_buffer(scp, arr,
1505 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1506}
1507
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001508#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1509
1510static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1511 struct sdebug_dev_info * devip)
1512{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001513 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001514 unsigned char * arr;
1515 int host_no = devip->sdbg_host->shost->host_no;
1516 int n, ret, alen, rlen;
1517 int port_group_a, port_group_b, port_a, port_b;
1518
Douglas Gilbert773642d2016-04-25 12:16:28 -04001519 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001520 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1521 if (! arr)
1522 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001523 /*
1524 * EVPD page 0x88 states we have two ports, one
1525 * real and a fake port with no device connected.
1526 * So we create two port groups with one port each
1527 * and set the group with port B to unavailable.
1528 */
1529 port_a = 0x1; /* relative port A */
1530 port_b = 0x2; /* relative port B */
1531 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001532 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001533 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001534 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001535
1536 /*
1537 * The asymmetric access state is cycled according to the host_id.
1538 */
1539 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001540 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001541 arr[n++] = host_no % 3; /* Asymm access state */
1542 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001543 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001544 arr[n++] = 0x0; /* Active/Optimized path */
1545 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001546 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001547 put_unaligned_be16(port_group_a, arr + n);
1548 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001549 arr[n++] = 0; /* Reserved */
1550 arr[n++] = 0; /* Status code */
1551 arr[n++] = 0; /* Vendor unique */
1552 arr[n++] = 0x1; /* One port per group */
1553 arr[n++] = 0; /* Reserved */
1554 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001555 put_unaligned_be16(port_a, arr + n);
1556 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001557 arr[n++] = 3; /* Port unavailable */
1558 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001559 put_unaligned_be16(port_group_b, arr + n);
1560 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001561 arr[n++] = 0; /* Reserved */
1562 arr[n++] = 0; /* Status code */
1563 arr[n++] = 0; /* Vendor unique */
1564 arr[n++] = 0x1; /* One port per group */
1565 arr[n++] = 0; /* Reserved */
1566 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001567 put_unaligned_be16(port_b, arr + n);
1568 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001569
1570 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001571 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001572
1573 /*
1574 * Return the smallest value of either
1575 * - The allocated length
1576 * - The constructed command length
1577 * - The maximum array size
1578 */
1579 rlen = min(alen,n);
1580 ret = fill_from_dev_buffer(scp, arr,
1581 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1582 kfree(arr);
1583 return ret;
1584}
1585
Douglas Gilbertfd321192016-04-25 12:16:33 -04001586static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1587 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001588{
1589 bool rctd;
1590 u8 reporting_opts, req_opcode, sdeb_i, supp;
1591 u16 req_sa, u;
1592 u32 alloc_len, a_len;
1593 int k, offset, len, errsts, count, bump, na;
1594 const struct opcode_info_t *oip;
1595 const struct opcode_info_t *r_oip;
1596 u8 *arr;
1597 u8 *cmd = scp->cmnd;
1598
1599 rctd = !!(cmd[2] & 0x80);
1600 reporting_opts = cmd[2] & 0x7;
1601 req_opcode = cmd[3];
1602 req_sa = get_unaligned_be16(cmd + 4);
1603 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001604 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001605 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1606 return check_condition_result;
1607 }
1608 if (alloc_len > 8192)
1609 a_len = 8192;
1610 else
1611 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001612 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001613 if (NULL == arr) {
1614 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1615 INSUFF_RES_ASCQ);
1616 return check_condition_result;
1617 }
1618 switch (reporting_opts) {
1619 case 0: /* all commands */
1620 /* count number of commands */
1621 for (count = 0, oip = opcode_info_arr;
1622 oip->num_attached != 0xff; ++oip) {
1623 if (F_INV_OP & oip->flags)
1624 continue;
1625 count += (oip->num_attached + 1);
1626 }
1627 bump = rctd ? 20 : 8;
1628 put_unaligned_be32(count * bump, arr);
1629 for (offset = 4, oip = opcode_info_arr;
1630 oip->num_attached != 0xff && offset < a_len; ++oip) {
1631 if (F_INV_OP & oip->flags)
1632 continue;
1633 na = oip->num_attached;
1634 arr[offset] = oip->opcode;
1635 put_unaligned_be16(oip->sa, arr + offset + 2);
1636 if (rctd)
1637 arr[offset + 5] |= 0x2;
1638 if (FF_SA & oip->flags)
1639 arr[offset + 5] |= 0x1;
1640 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1641 if (rctd)
1642 put_unaligned_be16(0xa, arr + offset + 8);
1643 r_oip = oip;
1644 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1645 if (F_INV_OP & oip->flags)
1646 continue;
1647 offset += bump;
1648 arr[offset] = oip->opcode;
1649 put_unaligned_be16(oip->sa, arr + offset + 2);
1650 if (rctd)
1651 arr[offset + 5] |= 0x2;
1652 if (FF_SA & oip->flags)
1653 arr[offset + 5] |= 0x1;
1654 put_unaligned_be16(oip->len_mask[0],
1655 arr + offset + 6);
1656 if (rctd)
1657 put_unaligned_be16(0xa,
1658 arr + offset + 8);
1659 }
1660 oip = r_oip;
1661 offset += bump;
1662 }
1663 break;
1664 case 1: /* one command: opcode only */
1665 case 2: /* one command: opcode plus service action */
1666 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1667 sdeb_i = opcode_ind_arr[req_opcode];
1668 oip = &opcode_info_arr[sdeb_i];
1669 if (F_INV_OP & oip->flags) {
1670 supp = 1;
1671 offset = 4;
1672 } else {
1673 if (1 == reporting_opts) {
1674 if (FF_SA & oip->flags) {
1675 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1676 2, 2);
1677 kfree(arr);
1678 return check_condition_result;
1679 }
1680 req_sa = 0;
1681 } else if (2 == reporting_opts &&
1682 0 == (FF_SA & oip->flags)) {
1683 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1684 kfree(arr); /* point at requested sa */
1685 return check_condition_result;
1686 }
1687 if (0 == (FF_SA & oip->flags) &&
1688 req_opcode == oip->opcode)
1689 supp = 3;
1690 else if (0 == (FF_SA & oip->flags)) {
1691 na = oip->num_attached;
1692 for (k = 0, oip = oip->arrp; k < na;
1693 ++k, ++oip) {
1694 if (req_opcode == oip->opcode)
1695 break;
1696 }
1697 supp = (k >= na) ? 1 : 3;
1698 } else if (req_sa != oip->sa) {
1699 na = oip->num_attached;
1700 for (k = 0, oip = oip->arrp; k < na;
1701 ++k, ++oip) {
1702 if (req_sa == oip->sa)
1703 break;
1704 }
1705 supp = (k >= na) ? 1 : 3;
1706 } else
1707 supp = 3;
1708 if (3 == supp) {
1709 u = oip->len_mask[0];
1710 put_unaligned_be16(u, arr + 2);
1711 arr[4] = oip->opcode;
1712 for (k = 1; k < u; ++k)
1713 arr[4 + k] = (k < 16) ?
1714 oip->len_mask[k] : 0xff;
1715 offset = 4 + u;
1716 } else
1717 offset = 4;
1718 }
1719 arr[1] = (rctd ? 0x80 : 0) | supp;
1720 if (rctd) {
1721 put_unaligned_be16(0xa, arr + offset);
1722 offset += 12;
1723 }
1724 break;
1725 default:
1726 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1727 kfree(arr);
1728 return check_condition_result;
1729 }
1730 offset = (offset < a_len) ? offset : a_len;
1731 len = (offset < alloc_len) ? offset : alloc_len;
1732 errsts = fill_from_dev_buffer(scp, arr, len);
1733 kfree(arr);
1734 return errsts;
1735}
1736
Douglas Gilbertfd321192016-04-25 12:16:33 -04001737static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1738 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001739{
1740 bool repd;
1741 u32 alloc_len, len;
1742 u8 arr[16];
1743 u8 *cmd = scp->cmnd;
1744
1745 memset(arr, 0, sizeof(arr));
1746 repd = !!(cmd[2] & 0x80);
1747 alloc_len = get_unaligned_be32(cmd + 6);
1748 if (alloc_len < 4) {
1749 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1750 return check_condition_result;
1751 }
1752 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1753 arr[1] = 0x1; /* ITNRS */
1754 if (repd) {
1755 arr[3] = 0xc;
1756 len = 16;
1757 } else
1758 len = 4;
1759
1760 len = (len < alloc_len) ? len : alloc_len;
1761 return fill_from_dev_buffer(scp, arr, len);
1762}
1763
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764/* <<Following mode page info copied from ST318451LW>> */
1765
1766static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1767{ /* Read-Write Error Recovery page for mode_sense */
1768 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1769 5, 0, 0xff, 0xff};
1770
1771 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1772 if (1 == pcontrol)
1773 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1774 return sizeof(err_recov_pg);
1775}
1776
1777static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1778{ /* Disconnect-Reconnect page for mode_sense */
1779 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1780 0, 0, 0, 0, 0, 0, 0, 0};
1781
1782 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1783 if (1 == pcontrol)
1784 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1785 return sizeof(disconnect_pg);
1786}
1787
1788static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1789{ /* Format device page for mode_sense */
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001790 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1791 0, 0, 0, 0, 0, 0, 0, 0,
1792 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001794 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001795 put_unaligned_be16(sdebug_sectors_per, p + 10);
1796 put_unaligned_be16(sdebug_sector_size, p + 12);
1797 if (sdebug_removable)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001798 p[20] |= 0x20; /* should agree with INQUIRY */
1799 if (1 == pcontrol)
1800 memset(p + 2, 0, sizeof(format_pg) - 2);
1801 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802}
1803
Douglas Gilbertfd321192016-04-25 12:16:33 -04001804static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1805 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1806 0, 0, 0, 0};
1807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1809{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001810 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1811 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1812 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1814
Douglas Gilbert773642d2016-04-25 12:16:28 -04001815 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001816 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 memcpy(p, caching_pg, sizeof(caching_pg));
1818 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001819 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1820 else if (2 == pcontrol)
1821 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 return sizeof(caching_pg);
1823}
1824
Douglas Gilbertfd321192016-04-25 12:16:33 -04001825static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1826 0, 0, 0x2, 0x4b};
1827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1829{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001830 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1831 0, 0, 0, 0};
1832 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 0, 0, 0x2, 0x4b};
1834
Douglas Gilbert773642d2016-04-25 12:16:28 -04001835 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001837 else
1838 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001839
Douglas Gilbert773642d2016-04-25 12:16:28 -04001840 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001841 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1844 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001845 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1846 else if (2 == pcontrol)
1847 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 return sizeof(ctrl_m_pg);
1849}
1850
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1853{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001854 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1855 0, 0, 0x0, 0x0};
1856 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1857 0, 0, 0x0, 0x0};
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1860 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001861 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1862 else if (2 == pcontrol)
1863 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 return sizeof(iec_m_pg);
1865}
1866
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001867static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1868{ /* SAS SSP mode page - short format for mode_sense */
1869 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1870 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1871
1872 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1873 if (1 == pcontrol)
1874 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1875 return sizeof(sas_sf_m_pg);
1876}
1877
1878
1879static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1880 int target_dev_id)
1881{ /* SAS phy control and discover mode page for mode_sense */
1882 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1883 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001884 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1885 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001886 0x2, 0, 0, 0, 0, 0, 0, 0,
1887 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1888 0, 0, 0, 0, 0, 0, 0, 0,
1889 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001890 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1891 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001892 0x3, 0, 0, 0, 0, 0, 0, 0,
1893 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1894 0, 0, 0, 0, 0, 0, 0, 0,
1895 };
1896 int port_a, port_b;
1897
Douglas Gilbert773642d2016-04-25 12:16:28 -04001898 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1899 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1900 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1901 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001902 port_a = target_dev_id + 1;
1903 port_b = port_a + 1;
1904 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001905 put_unaligned_be32(port_a, p + 20);
1906 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001907 if (1 == pcontrol)
1908 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1909 return sizeof(sas_pcd_m_pg);
1910}
1911
1912static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1913{ /* SAS SSP shared protocol specific port mode subpage */
1914 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1915 0, 0, 0, 0, 0, 0, 0, 0,
1916 };
1917
1918 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1919 if (1 == pcontrol)
1920 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1921 return sizeof(sas_sha_m_pg);
1922}
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924#define SDEBUG_MAX_MSENSE_SZ 256
1925
Douglas Gilbertfd321192016-04-25 12:16:33 -04001926static int resp_mode_sense(struct scsi_cmnd *scp,
1927 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
Douglas Gilbert23183912006-09-16 20:30:47 -04001929 unsigned char dbd, llbaa;
1930 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 unsigned char dev_spec;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001932 int alloc_len, msense_6, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001933 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 unsigned char * ap;
1935 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001936 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
Douglas Gilbert23183912006-09-16 20:30:47 -04001938 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 pcontrol = (cmd[2] & 0xc0) >> 6;
1940 pcode = cmd[2] & 0x3f;
1941 subpcode = cmd[3];
1942 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001943 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001944 if ((sdebug_ptype == TYPE_DISK) && (dbd == 0))
Douglas Gilbert23183912006-09-16 20:30:47 -04001945 bd_len = llbaa ? 16 : 8;
1946 else
1947 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001948 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1950 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001951 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 return check_condition_result;
1953 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001954 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1955 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001956 /* for disks set DPOFUA bit and clear write protect (WP) bit */
1957 if (sdebug_ptype == TYPE_DISK)
1958 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04001959 else
1960 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 if (msense_6) {
1962 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001963 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 offset = 4;
1965 } else {
1966 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001967 if (16 == bd_len)
1968 arr[4] = 0x1; /* set LONGLBA bit */
1969 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 offset = 8;
1971 }
1972 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001973 if ((bd_len > 0) && (!sdebug_capacity))
1974 sdebug_capacity = get_sdebug_capacity();
1975
Douglas Gilbert23183912006-09-16 20:30:47 -04001976 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001977 if (sdebug_capacity > 0xfffffffe)
1978 put_unaligned_be32(0xffffffff, ap + 0);
1979 else
1980 put_unaligned_be32(sdebug_capacity, ap + 0);
1981 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04001982 offset += bd_len;
1983 ap = arr + offset;
1984 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001985 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
1986 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04001987 offset += bd_len;
1988 ap = arr + offset;
1989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001991 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1992 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001993 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 return check_condition_result;
1995 }
1996 switch (pcode) {
1997 case 0x1: /* Read-Write error recovery page, direct access */
1998 len = resp_err_recov_pg(ap, pcontrol, target);
1999 offset += len;
2000 break;
2001 case 0x2: /* Disconnect-Reconnect page, all devices */
2002 len = resp_disconnect_pg(ap, pcontrol, target);
2003 offset += len;
2004 break;
2005 case 0x3: /* Format device page, direct access */
2006 len = resp_format_pg(ap, pcontrol, target);
2007 offset += len;
2008 break;
2009 case 0x8: /* Caching page, direct access */
2010 len = resp_caching_pg(ap, pcontrol, target);
2011 offset += len;
2012 break;
2013 case 0xa: /* Control Mode page, all devices */
2014 len = resp_ctrl_m_pg(ap, pcontrol, target);
2015 offset += len;
2016 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002017 case 0x19: /* if spc==1 then sas phy, control+discover */
2018 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002019 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002020 return check_condition_result;
2021 }
2022 len = 0;
2023 if ((0x0 == subpcode) || (0xff == subpcode))
2024 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2025 if ((0x1 == subpcode) || (0xff == subpcode))
2026 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2027 target_dev_id);
2028 if ((0x2 == subpcode) || (0xff == subpcode))
2029 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2030 offset += len;
2031 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 case 0x1c: /* Informational Exceptions Mode page, all devices */
2033 len = resp_iec_m_pg(ap, pcontrol, target);
2034 offset += len;
2035 break;
2036 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002037 if ((0 == subpcode) || (0xff == subpcode)) {
2038 len = resp_err_recov_pg(ap, pcontrol, target);
2039 len += resp_disconnect_pg(ap + len, pcontrol, target);
2040 len += resp_format_pg(ap + len, pcontrol, target);
2041 len += resp_caching_pg(ap + len, pcontrol, target);
2042 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2043 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2044 if (0xff == subpcode) {
2045 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2046 target, target_dev_id);
2047 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2048 }
2049 len += resp_iec_m_pg(ap + len, pcontrol, target);
2050 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002051 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002052 return check_condition_result;
2053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 offset += len;
2055 break;
2056 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002057 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 return check_condition_result;
2059 }
2060 if (msense_6)
2061 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002062 else
2063 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2065}
2066
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002067#define SDEBUG_MAX_MSELECT_SZ 512
2068
Douglas Gilbertfd321192016-04-25 12:16:33 -04002069static int resp_mode_select(struct scsi_cmnd *scp,
2070 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002071{
2072 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002073 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002074 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002075 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002076 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002077
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002078 memset(arr, 0, sizeof(arr));
2079 pf = cmd[1] & 0x10;
2080 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002081 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002082 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002083 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002084 return check_condition_result;
2085 }
2086 res = fetch_to_dev_buffer(scp, arr, param_len);
2087 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002088 return DID_ERROR << 16;
2089 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002090 sdev_printk(KERN_INFO, scp->device,
2091 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2092 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002093 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2094 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002095 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002096 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002097 return check_condition_result;
2098 }
2099 off = bd_len + (mselect6 ? 4 : 8);
2100 mpage = arr[off] & 0x3f;
2101 ps = !!(arr[off] & 0x80);
2102 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002103 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002104 return check_condition_result;
2105 }
2106 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002107 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002108 (arr[off + 1] + 2);
2109 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002110 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002111 PARAMETER_LIST_LENGTH_ERR, 0);
2112 return check_condition_result;
2113 }
2114 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002115 case 0x8: /* Caching Mode page */
2116 if (caching_pg[1] == arr[off + 1]) {
2117 memcpy(caching_pg + 2, arr + off + 2,
2118 sizeof(caching_pg) - 2);
2119 goto set_mode_changed_ua;
2120 }
2121 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002122 case 0xa: /* Control Mode page */
2123 if (ctrl_m_pg[1] == arr[off + 1]) {
2124 memcpy(ctrl_m_pg + 2, arr + off + 2,
2125 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002126 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002127 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002128 }
2129 break;
2130 case 0x1c: /* Informational Exceptions Mode page */
2131 if (iec_m_pg[1] == arr[off + 1]) {
2132 memcpy(iec_m_pg + 2, arr + off + 2,
2133 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002134 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002135 }
2136 break;
2137 default:
2138 break;
2139 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002140 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002141 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002142set_mode_changed_ua:
2143 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2144 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002145}
2146
2147static int resp_temp_l_pg(unsigned char * arr)
2148{
2149 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2150 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2151 };
2152
2153 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2154 return sizeof(temp_l_pg);
2155}
2156
2157static int resp_ie_l_pg(unsigned char * arr)
2158{
2159 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2160 };
2161
2162 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2163 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2164 arr[4] = THRESHOLD_EXCEEDED;
2165 arr[5] = 0xff;
2166 }
2167 return sizeof(ie_l_pg);
2168}
2169
2170#define SDEBUG_MAX_LSENSE_SZ 512
2171
2172static int resp_log_sense(struct scsi_cmnd * scp,
2173 struct sdebug_dev_info * devip)
2174{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002175 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002176 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002177 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002178
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002179 memset(arr, 0, sizeof(arr));
2180 ppc = cmd[1] & 0x2;
2181 sp = cmd[1] & 0x1;
2182 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002183 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002184 return check_condition_result;
2185 }
2186 pcontrol = (cmd[2] & 0xc0) >> 6;
2187 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002188 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002189 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002190 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002191 if (0 == subpcode) {
2192 switch (pcode) {
2193 case 0x0: /* Supported log pages log page */
2194 n = 4;
2195 arr[n++] = 0x0; /* this page */
2196 arr[n++] = 0xd; /* Temperature */
2197 arr[n++] = 0x2f; /* Informational exceptions */
2198 arr[3] = n - 4;
2199 break;
2200 case 0xd: /* Temperature log page */
2201 arr[3] = resp_temp_l_pg(arr + 4);
2202 break;
2203 case 0x2f: /* Informational exceptions log page */
2204 arr[3] = resp_ie_l_pg(arr + 4);
2205 break;
2206 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002207 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002208 return check_condition_result;
2209 }
2210 } else if (0xff == subpcode) {
2211 arr[0] |= 0x40;
2212 arr[1] = subpcode;
2213 switch (pcode) {
2214 case 0x0: /* Supported log pages and subpages log page */
2215 n = 4;
2216 arr[n++] = 0x0;
2217 arr[n++] = 0x0; /* 0,0 page */
2218 arr[n++] = 0x0;
2219 arr[n++] = 0xff; /* this page */
2220 arr[n++] = 0xd;
2221 arr[n++] = 0x0; /* Temperature */
2222 arr[n++] = 0x2f;
2223 arr[n++] = 0x0; /* Informational exceptions */
2224 arr[3] = n - 4;
2225 break;
2226 case 0xd: /* Temperature subpages */
2227 n = 4;
2228 arr[n++] = 0xd;
2229 arr[n++] = 0x0; /* Temperature */
2230 arr[3] = n - 4;
2231 break;
2232 case 0x2f: /* Informational exceptions subpages */
2233 n = 4;
2234 arr[n++] = 0x2f;
2235 arr[n++] = 0x0; /* Informational exceptions */
2236 arr[3] = n - 4;
2237 break;
2238 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002239 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002240 return check_condition_result;
2241 }
2242 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002243 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002244 return check_condition_result;
2245 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002246 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002247 return fill_from_dev_buffer(scp, arr,
2248 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2249}
2250
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002251static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002252 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002254 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002255 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 return check_condition_result;
2257 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002258 /* transfer length excessive (tie in to block limits VPD page) */
2259 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002260 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002261 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 return check_condition_result;
2263 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002264 return 0;
2265}
2266
Akinobu Mitaa4517512013-07-08 16:01:57 -07002267/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002268static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2269 bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002270{
2271 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002272 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002273 struct scsi_data_buffer *sdb;
2274 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002275
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002276 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002277 sdb = scsi_out(scmd);
2278 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002279 } else {
2280 sdb = scsi_in(scmd);
2281 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002282 }
2283
2284 if (!sdb->length)
2285 return 0;
2286 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2287 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002288
2289 block = do_div(lba, sdebug_store_sectors);
2290 if (block + num > sdebug_store_sectors)
2291 rest = block + num - sdebug_store_sectors;
2292
Dave Gordon386ecb12015-06-30 14:58:57 -07002293 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002294 fake_storep + (block * sdebug_sector_size),
2295 (num - rest) * sdebug_sector_size, 0, do_write);
2296 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002297 return ret;
2298
2299 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002300 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002301 fake_storep, rest * sdebug_sector_size,
2302 (num - rest) * sdebug_sector_size, do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002303 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002304
2305 return ret;
2306}
2307
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002308/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2309 * arr into fake_store(lba,num) and return true. If comparison fails then
2310 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002311static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002312{
2313 bool res;
2314 u64 block, rest = 0;
2315 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002316 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002317
2318 block = do_div(lba, store_blks);
2319 if (block + num > store_blks)
2320 rest = block + num - store_blks;
2321
2322 res = !memcmp(fake_storep + (block * lb_size), arr,
2323 (num - rest) * lb_size);
2324 if (!res)
2325 return res;
2326 if (rest)
2327 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2328 rest * lb_size);
2329 if (!res)
2330 return res;
2331 arr += num * lb_size;
2332 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2333 if (rest)
2334 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2335 rest * lb_size);
2336 return res;
2337}
2338
Akinobu Mita51d648a2013-09-18 21:27:28 +09002339static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002340{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002341 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002342
Douglas Gilbert773642d2016-04-25 12:16:28 -04002343 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002344 csum = (__force __be16)ip_compute_csum(buf, len);
2345 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002346 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002347
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002348 return csum;
2349}
2350
2351static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2352 sector_t sector, u32 ei_lba)
2353{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002354 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002355
2356 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002357 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002358 (unsigned long)sector,
2359 be16_to_cpu(sdt->guard_tag),
2360 be16_to_cpu(csum));
2361 return 0x01;
2362 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002363 if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002364 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002365 pr_err("REF check failed on sector %lu\n",
2366 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002367 return 0x03;
2368 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002369 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002370 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002371 pr_err("REF check failed on sector %lu\n",
2372 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002373 return 0x03;
2374 }
2375 return 0;
2376}
2377
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002378static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002379 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002380{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002381 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002382 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002383 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002384 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002385
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002386 /* Bytes of protection data to copy into sgl */
2387 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002388
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002389 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2390 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2391 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2392
2393 while (sg_miter_next(&miter) && resid > 0) {
2394 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002395 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002396 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002397
2398 if (dif_store_end < start + len)
2399 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002400
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002401 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002402
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002403 if (read)
2404 memcpy(paddr, start, len - rest);
2405 else
2406 memcpy(start, paddr, len - rest);
2407
2408 if (rest) {
2409 if (read)
2410 memcpy(paddr + len - rest, dif_storep, rest);
2411 else
2412 memcpy(dif_storep, paddr + len - rest, rest);
2413 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002414
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002415 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002416 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002417 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002418 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002419}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002420
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002421static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2422 unsigned int sectors, u32 ei_lba)
2423{
2424 unsigned int i;
2425 struct sd_dif_tuple *sdt;
2426 sector_t sector;
2427
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002428 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002429 int ret;
2430
2431 sector = start_sec + i;
2432 sdt = dif_store(sector);
2433
Akinobu Mita51d648a2013-09-18 21:27:28 +09002434 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002435 continue;
2436
2437 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2438 if (ret) {
2439 dif_errors++;
2440 return ret;
2441 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002442 }
2443
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002444 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002445 dix_reads++;
2446
2447 return 0;
2448}
2449
Douglas Gilbertfd321192016-04-25 12:16:33 -04002450static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002451{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002452 u8 *cmd = scp->cmnd;
2453 u64 lba;
2454 u32 num;
2455 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002456 unsigned long iflags;
2457 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002458 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002459
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002460 switch (cmd[0]) {
2461 case READ_16:
2462 ei_lba = 0;
2463 lba = get_unaligned_be64(cmd + 2);
2464 num = get_unaligned_be32(cmd + 10);
2465 check_prot = true;
2466 break;
2467 case READ_10:
2468 ei_lba = 0;
2469 lba = get_unaligned_be32(cmd + 2);
2470 num = get_unaligned_be16(cmd + 7);
2471 check_prot = true;
2472 break;
2473 case READ_6:
2474 ei_lba = 0;
2475 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2476 (u32)(cmd[1] & 0x1f) << 16;
2477 num = (0 == cmd[4]) ? 256 : cmd[4];
2478 check_prot = true;
2479 break;
2480 case READ_12:
2481 ei_lba = 0;
2482 lba = get_unaligned_be32(cmd + 2);
2483 num = get_unaligned_be32(cmd + 6);
2484 check_prot = true;
2485 break;
2486 case XDWRITEREAD_10:
2487 ei_lba = 0;
2488 lba = get_unaligned_be32(cmd + 2);
2489 num = get_unaligned_be16(cmd + 7);
2490 check_prot = false;
2491 break;
2492 default: /* assume READ(32) */
2493 lba = get_unaligned_be64(cmd + 12);
2494 ei_lba = get_unaligned_be32(cmd + 20);
2495 num = get_unaligned_be32(cmd + 28);
2496 check_prot = false;
2497 break;
2498 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002499 if (unlikely(have_dif_prot && check_prot)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002500 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002501 (cmd[1] & 0xe0)) {
2502 mk_sense_invalid_opcode(scp);
2503 return check_condition_result;
2504 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002505 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2506 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002507 (cmd[1] & 0xe0) == 0)
2508 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2509 "to DIF device\n");
2510 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002511 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002512 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2513
2514 if (ep->inj_short)
2515 num /= 2;
2516 }
2517
2518 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002519 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002520 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2521 return check_condition_result;
2522 }
2523 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002524 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002525 /* needs work to find which cdb byte 'num' comes from */
2526 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2527 return check_condition_result;
2528 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002529
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002530 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2531 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2532 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002533 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002534 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002535 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002536 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2537 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002538 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2539 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002540 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002541 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002542 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 return check_condition_result;
2544 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002545
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002546 read_lock_irqsave(&atomic_rw, iflags);
2547
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002548 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002549 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002550 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002551
2552 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002553 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002554 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002555 return illegal_condition_result;
2556 }
2557 }
2558
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002559 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002561 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002562 return DID_ERROR << 16;
2563
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002564 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002565
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002566 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002567 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2568
2569 if (ep->inj_recovered) {
2570 mk_sense_buffer(scp, RECOVERED_ERROR,
2571 THRESHOLD_EXCEEDED, 0);
2572 return check_condition_result;
2573 } else if (ep->inj_transport) {
2574 mk_sense_buffer(scp, ABORTED_COMMAND,
2575 TRANSPORT_PROBLEM, ACK_NAK_TO);
2576 return check_condition_result;
2577 } else if (ep->inj_dif) {
2578 /* Logical block guard check failed */
2579 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2580 return illegal_condition_result;
2581 } else if (ep->inj_dix) {
2582 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2583 return illegal_condition_result;
2584 }
2585 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002586 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587}
2588
Tomas Winkler58a86352015-07-28 16:54:23 +03002589static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002590{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002591 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002592
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002593 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002594 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002595 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002596
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002597 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002598 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002599
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002600 if (c >= 0x20 && c < 0x7e)
2601 n += scnprintf(b + n, sizeof(b) - n,
2602 " %c ", buf[i+j]);
2603 else
2604 n += scnprintf(b + n, sizeof(b) - n,
2605 "%02x ", buf[i+j]);
2606 }
2607 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002608 }
2609}
2610
2611static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002612 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002613{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002614 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002615 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002616 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002617 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002618 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002619 int dpage_offset;
2620 struct sg_mapping_iter diter;
2621 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002622
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002623 BUG_ON(scsi_sg_count(SCpnt) == 0);
2624 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2625
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002626 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2627 scsi_prot_sg_count(SCpnt),
2628 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2629 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2630 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002631
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002632 /* For each protection page */
2633 while (sg_miter_next(&piter)) {
2634 dpage_offset = 0;
2635 if (WARN_ON(!sg_miter_next(&diter))) {
2636 ret = 0x01;
2637 goto out;
2638 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002639
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002640 for (ppage_offset = 0; ppage_offset < piter.length;
2641 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002642 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002643 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002644 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002645 if (dpage_offset >= diter.length) {
2646 if (WARN_ON(!sg_miter_next(&diter))) {
2647 ret = 0x01;
2648 goto out;
2649 }
2650 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002651 }
2652
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002653 sdt = piter.addr + ppage_offset;
2654 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002655
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002656 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002657 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002658 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002659 goto out;
2660 }
2661
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002662 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002663 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002664 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002665 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002666 diter.consumed = dpage_offset;
2667 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002668 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002669 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002670
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002671 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002672 dix_writes++;
2673
2674 return 0;
2675
2676out:
2677 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002678 sg_miter_stop(&diter);
2679 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002680 return ret;
2681}
2682
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002683static unsigned long lba_to_map_index(sector_t lba)
2684{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002685 if (sdebug_unmap_alignment)
2686 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2687 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002688 return lba;
2689}
2690
2691static sector_t map_index_to_lba(unsigned long index)
2692{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002693 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002694
Douglas Gilbert773642d2016-04-25 12:16:28 -04002695 if (sdebug_unmap_alignment)
2696 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002697 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002698}
2699
Martin K. Petersen44d92692009-10-15 14:45:27 -04002700static unsigned int map_state(sector_t lba, unsigned int *num)
2701{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002702 sector_t end;
2703 unsigned int mapped;
2704 unsigned long index;
2705 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002706
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002707 index = lba_to_map_index(lba);
2708 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002709
2710 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002711 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002712 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002713 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002714
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002715 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002716 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002717 return mapped;
2718}
2719
2720static void map_region(sector_t lba, unsigned int len)
2721{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002722 sector_t end = lba + len;
2723
Martin K. Petersen44d92692009-10-15 14:45:27 -04002724 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002725 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002726
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002727 if (index < map_size)
2728 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002729
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002730 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002731 }
2732}
2733
2734static void unmap_region(sector_t lba, unsigned int len)
2735{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002736 sector_t end = lba + len;
2737
Martin K. Petersen44d92692009-10-15 14:45:27 -04002738 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002739 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002740
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002741 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002742 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002743 index < map_size) {
2744 clear_bit(index, map_storep);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002745 if (sdebug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002746 memset(fake_storep +
Douglas Gilbert773642d2016-04-25 12:16:28 -04002747 lba * sdebug_sector_size, 0,
2748 sdebug_sector_size *
2749 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002750 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002751 if (dif_storep) {
2752 memset(dif_storep + lba, 0xff,
2753 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002754 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002755 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002756 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002757 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002758 }
2759}
2760
Douglas Gilbertfd321192016-04-25 12:16:33 -04002761static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002763 u8 *cmd = scp->cmnd;
2764 u64 lba;
2765 u32 num;
2766 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002768 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002769 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002771 switch (cmd[0]) {
2772 case WRITE_16:
2773 ei_lba = 0;
2774 lba = get_unaligned_be64(cmd + 2);
2775 num = get_unaligned_be32(cmd + 10);
2776 check_prot = true;
2777 break;
2778 case WRITE_10:
2779 ei_lba = 0;
2780 lba = get_unaligned_be32(cmd + 2);
2781 num = get_unaligned_be16(cmd + 7);
2782 check_prot = true;
2783 break;
2784 case WRITE_6:
2785 ei_lba = 0;
2786 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2787 (u32)(cmd[1] & 0x1f) << 16;
2788 num = (0 == cmd[4]) ? 256 : cmd[4];
2789 check_prot = true;
2790 break;
2791 case WRITE_12:
2792 ei_lba = 0;
2793 lba = get_unaligned_be32(cmd + 2);
2794 num = get_unaligned_be32(cmd + 6);
2795 check_prot = true;
2796 break;
2797 case 0x53: /* XDWRITEREAD(10) */
2798 ei_lba = 0;
2799 lba = get_unaligned_be32(cmd + 2);
2800 num = get_unaligned_be16(cmd + 7);
2801 check_prot = false;
2802 break;
2803 default: /* assume WRITE(32) */
2804 lba = get_unaligned_be64(cmd + 12);
2805 ei_lba = get_unaligned_be32(cmd + 20);
2806 num = get_unaligned_be32(cmd + 28);
2807 check_prot = false;
2808 break;
2809 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002810 if (unlikely(have_dif_prot && check_prot)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002811 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002812 (cmd[1] & 0xe0)) {
2813 mk_sense_invalid_opcode(scp);
2814 return check_condition_result;
2815 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002816 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2817 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002818 (cmd[1] & 0xe0) == 0)
2819 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2820 "to DIF device\n");
2821 }
2822
2823 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002824 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002825 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2826 return check_condition_result;
2827 }
2828 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002829 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002830 /* needs work to find which cdb byte 'num' comes from */
2831 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2832 return check_condition_result;
2833 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002835 write_lock_irqsave(&atomic_rw, iflags);
2836
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002837 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002838 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002839 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002840
2841 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002842 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002843 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002844 return illegal_condition_result;
2845 }
2846 }
2847
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002848 ret = do_device_access(scp, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002849 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04002850 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002852 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04002853 return DID_ERROR << 16;
2854 else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002855 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002856 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002857 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002858
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002859 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002860 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2861
2862 if (ep->inj_recovered) {
2863 mk_sense_buffer(scp, RECOVERED_ERROR,
2864 THRESHOLD_EXCEEDED, 0);
2865 return check_condition_result;
2866 } else if (ep->inj_dif) {
2867 /* Logical block guard check failed */
2868 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2869 return illegal_condition_result;
2870 } else if (ep->inj_dix) {
2871 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2872 return illegal_condition_result;
2873 }
2874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 return 0;
2876}
2877
Douglas Gilbertfd321192016-04-25 12:16:33 -04002878static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2879 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002880{
2881 unsigned long iflags;
2882 unsigned long long i;
2883 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002884 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002885
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002886 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002887 if (ret)
2888 return ret;
2889
2890 write_lock_irqsave(&atomic_rw, iflags);
2891
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002892 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002893 unmap_region(lba, num);
2894 goto out;
2895 }
2896
Douglas Gilbert773642d2016-04-25 12:16:28 -04002897 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002898 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2899 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002900 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002901 ret = 0;
2902 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04002903 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2904 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002905
2906 if (-1 == ret) {
2907 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002908 return DID_ERROR << 16;
2909 } else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002910 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002911 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2912 my_name, "write same",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002913 num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002914
2915 /* Copy first sector to remaining blocks */
2916 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002917 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2918 fake_storep + lba_off,
2919 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002920
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002921 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002922 map_region(lba, num);
2923out:
2924 write_unlock_irqrestore(&atomic_rw, iflags);
2925
2926 return 0;
2927}
2928
Douglas Gilbertfd321192016-04-25 12:16:33 -04002929static int resp_write_same_10(struct scsi_cmnd *scp,
2930 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002931{
2932 u8 *cmd = scp->cmnd;
2933 u32 lba;
2934 u16 num;
2935 u32 ei_lba = 0;
2936 bool unmap = false;
2937
2938 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002939 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002940 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2941 return check_condition_result;
2942 } else
2943 unmap = true;
2944 }
2945 lba = get_unaligned_be32(cmd + 2);
2946 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002947 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002948 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2949 return check_condition_result;
2950 }
2951 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2952}
2953
Douglas Gilbertfd321192016-04-25 12:16:33 -04002954static int resp_write_same_16(struct scsi_cmnd *scp,
2955 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002956{
2957 u8 *cmd = scp->cmnd;
2958 u64 lba;
2959 u32 num;
2960 u32 ei_lba = 0;
2961 bool unmap = false;
2962 bool ndob = false;
2963
2964 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002965 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002966 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2967 return check_condition_result;
2968 } else
2969 unmap = true;
2970 }
2971 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
2972 ndob = true;
2973 lba = get_unaligned_be64(cmd + 2);
2974 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002975 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002976 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2977 return check_condition_result;
2978 }
2979 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
2980}
2981
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05002982/* Note the mode field is in the same position as the (lower) service action
2983 * field. For the Report supported operation codes command, SPC-4 suggests
2984 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002985static int resp_write_buffer(struct scsi_cmnd *scp,
2986 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05002987{
2988 u8 *cmd = scp->cmnd;
2989 struct scsi_device *sdp = scp->device;
2990 struct sdebug_dev_info *dp;
2991 u8 mode;
2992
2993 mode = cmd[1] & 0x1f;
2994 switch (mode) {
2995 case 0x4: /* download microcode (MC) and activate (ACT) */
2996 /* set UAs on this device only */
2997 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2998 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
2999 break;
3000 case 0x5: /* download MC, save and ACT */
3001 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3002 break;
3003 case 0x6: /* download MC with offsets and ACT */
3004 /* set UAs on most devices (LUs) in this target */
3005 list_for_each_entry(dp,
3006 &devip->sdbg_host->dev_info_list,
3007 dev_list)
3008 if (dp->target == sdp->id) {
3009 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3010 if (devip != dp)
3011 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3012 dp->uas_bm);
3013 }
3014 break;
3015 case 0x7: /* download MC with offsets, save, and ACT */
3016 /* set UA on all devices (LUs) in this target */
3017 list_for_each_entry(dp,
3018 &devip->sdbg_host->dev_info_list,
3019 dev_list)
3020 if (dp->target == sdp->id)
3021 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3022 dp->uas_bm);
3023 break;
3024 default:
3025 /* do nothing for this command for other mode values */
3026 break;
3027 }
3028 return 0;
3029}
3030
Douglas Gilbertfd321192016-04-25 12:16:33 -04003031static int resp_comp_write(struct scsi_cmnd *scp,
3032 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003033{
3034 u8 *cmd = scp->cmnd;
3035 u8 *arr;
3036 u8 *fake_storep_hold;
3037 u64 lba;
3038 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003039 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003040 u8 num;
3041 unsigned long iflags;
3042 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003043 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003044
Douglas Gilbertd467d312014-11-26 12:33:48 -05003045 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003046 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3047 if (0 == num)
3048 return 0; /* degenerate case, not an error */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003049 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003050 (cmd[1] & 0xe0)) {
3051 mk_sense_invalid_opcode(scp);
3052 return check_condition_result;
3053 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003054 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3055 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003056 (cmd[1] & 0xe0) == 0)
3057 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3058 "to DIF device\n");
3059
3060 /* inline check_device_access_params() */
3061 if (lba + num > sdebug_capacity) {
3062 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3063 return check_condition_result;
3064 }
3065 /* transfer length excessive (tie in to block limits VPD page) */
3066 if (num > sdebug_store_sectors) {
3067 /* needs work to find which cdb byte 'num' comes from */
3068 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3069 return check_condition_result;
3070 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003071 dnum = 2 * num;
3072 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3073 if (NULL == arr) {
3074 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3075 INSUFF_RES_ASCQ);
3076 return check_condition_result;
3077 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003078
3079 write_lock_irqsave(&atomic_rw, iflags);
3080
3081 /* trick do_device_access() to fetch both compare and write buffers
3082 * from data-in into arr. Safe (atomic) since write_lock held. */
3083 fake_storep_hold = fake_storep;
3084 fake_storep = arr;
3085 ret = do_device_access(scp, 0, dnum, true);
3086 fake_storep = fake_storep_hold;
3087 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003088 retval = DID_ERROR << 16;
3089 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003090 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003091 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3092 "indicated=%u, IO sent=%d bytes\n", my_name,
3093 dnum * lb_size, ret);
3094 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003095 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003096 retval = check_condition_result;
3097 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003098 }
3099 if (scsi_debug_lbp())
3100 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003101cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003102 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003103 kfree(arr);
3104 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003105}
3106
Martin K. Petersen44d92692009-10-15 14:45:27 -04003107struct unmap_block_desc {
3108 __be64 lba;
3109 __be32 blocks;
3110 __be32 __reserved;
3111};
3112
Douglas Gilbertfd321192016-04-25 12:16:33 -04003113static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003114{
3115 unsigned char *buf;
3116 struct unmap_block_desc *desc;
3117 unsigned int i, payload_len, descriptors;
3118 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003119 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003120
Martin K. Petersen44d92692009-10-15 14:45:27 -04003121
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003122 if (!scsi_debug_lbp())
3123 return 0; /* fib and say its done */
3124 payload_len = get_unaligned_be16(scp->cmnd + 7);
3125 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003126
3127 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003128 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003129 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003130 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003131 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003132
Douglas Gilbertb333a812016-04-25 12:16:30 -04003133 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003134 if (!buf) {
3135 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3136 INSUFF_RES_ASCQ);
3137 return check_condition_result;
3138 }
3139
3140 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003141
3142 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3143 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3144
3145 desc = (void *)&buf[8];
3146
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003147 write_lock_irqsave(&atomic_rw, iflags);
3148
Martin K. Petersen44d92692009-10-15 14:45:27 -04003149 for (i = 0 ; i < descriptors ; i++) {
3150 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3151 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3152
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003153 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003154 if (ret)
3155 goto out;
3156
3157 unmap_region(lba, num);
3158 }
3159
3160 ret = 0;
3161
3162out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003163 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003164 kfree(buf);
3165
3166 return ret;
3167}
3168
3169#define SDEBUG_GET_LBA_STATUS_LEN 32
3170
Douglas Gilbertfd321192016-04-25 12:16:33 -04003171static int resp_get_lba_status(struct scsi_cmnd *scp,
3172 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003173{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003174 u8 *cmd = scp->cmnd;
3175 u64 lba;
3176 u32 alloc_len, mapped, num;
3177 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003178 int ret;
3179
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003180 lba = get_unaligned_be64(cmd + 2);
3181 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003182
3183 if (alloc_len < 24)
3184 return 0;
3185
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003186 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003187 if (ret)
3188 return ret;
3189
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003190 if (scsi_debug_lbp())
3191 mapped = map_state(lba, &num);
3192 else {
3193 mapped = 1;
3194 /* following just in case virtual_gb changed */
3195 sdebug_capacity = get_sdebug_capacity();
3196 if (sdebug_capacity - lba <= 0xffffffff)
3197 num = sdebug_capacity - lba;
3198 else
3199 num = 0xffffffff;
3200 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003201
3202 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003203 put_unaligned_be32(20, arr); /* Parameter Data Length */
3204 put_unaligned_be64(lba, arr + 8); /* LBA */
3205 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3206 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003207
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003208 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003209}
3210
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003211#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212
3213static int resp_report_luns(struct scsi_cmnd * scp,
3214 struct sdebug_dev_info * devip)
3215{
3216 unsigned int alloc_len;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003217 int lun_cnt, i, upper, num, n, want_wlun, shortish;
3218 u64 lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003219 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 int select_report = (int)cmd[2];
3221 struct scsi_lun *one_lun;
3222 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003223 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003225 clear_luns_changed_on_target(devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003227 shortish = (alloc_len < 4);
3228 if (shortish || (select_report > 2)) {
3229 mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 return check_condition_result;
3231 }
3232 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
3233 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003234 lun_cnt = sdebug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003235 if (1 == select_report)
3236 lun_cnt = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003237 else if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003238 --lun_cnt;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003239 want_wlun = (select_report > 0) ? 1 : 0;
3240 num = lun_cnt + want_wlun;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003241 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3242 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3243 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3244 sizeof(struct scsi_lun)), num);
3245 if (n < num) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003246 want_wlun = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003247 lun_cnt = n;
3248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003250 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003251 for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003252 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3253 i++, lun++) {
3254 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 if (upper)
3256 one_lun[i].scsi_lun[0] =
3257 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003258 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003260 if (want_wlun) {
Tomas Winkler34d55432015-07-28 16:54:21 +03003261 one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
3262 one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003263 i++;
3264 }
3265 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 return fill_from_dev_buffer(scp, arr,
3267 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
3268}
3269
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003270static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3271 unsigned int num, struct sdebug_dev_info *devip)
3272{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003273 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003274 unsigned char *kaddr, *buf;
3275 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003276 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003277 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003278
3279 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003280 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003281 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003282 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3283 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003284 return check_condition_result;
3285 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003286
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003287 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003288
3289 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003290 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3291 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003292
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003293 while (sg_miter_next(&miter)) {
3294 kaddr = miter.addr;
3295 for (j = 0; j < miter.length; j++)
3296 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003297
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003298 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003299 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003300 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003301 kfree(buf);
3302
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003303 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003304}
3305
Douglas Gilbertfd321192016-04-25 12:16:33 -04003306static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3307 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003308{
3309 u8 *cmd = scp->cmnd;
3310 u64 lba;
3311 u32 num;
3312 int errsts;
3313
3314 if (!scsi_bidi_cmnd(scp)) {
3315 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3316 INSUFF_RES_ASCQ);
3317 return check_condition_result;
3318 }
3319 errsts = resp_read_dt0(scp, devip);
3320 if (errsts)
3321 return errsts;
3322 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3323 errsts = resp_write_dt0(scp, devip);
3324 if (errsts)
3325 return errsts;
3326 }
3327 lba = get_unaligned_be32(cmd + 2);
3328 num = get_unaligned_be16(cmd + 7);
3329 return resp_xdwriteread(scp, lba, num, devip);
3330}
3331
Douglas Gilberta10bc122016-04-25 12:16:32 -04003332/* Queued command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003333static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003335 int qa_indx;
3336 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003338 struct sdebug_queued_cmd *sqcp;
3339 struct scsi_cmnd *scp;
3340 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003342 atomic_inc(&sdebug_completions);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003343 qa_indx = sd_dp->qa_indx;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003344 if (unlikely((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE))) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003345 pr_err("wild qa_indx=%d\n", qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 return;
3347 }
3348 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003349 sqcp = &queued_arr[qa_indx];
3350 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003351 if (unlikely(scp == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003353 pr_err("scp is NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 return;
3355 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003356 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003357 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003358 atomic_dec(&devip->num_in_q);
3359 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003360 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003361 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003362 retiring = 1;
3363
3364 sqcp->a_cmnd = NULL;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003365 if (unlikely(!test_and_clear_bit(qa_indx, queued_in_use_bm))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003366 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003367 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003368 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003370
3371 if (unlikely(retiring)) { /* user has reduced max_queue */
3372 int k, retval;
3373
3374 retval = atomic_read(&retired_max_queue);
3375 if (qa_indx >= retval) {
3376 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003377 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003378 return;
3379 }
3380 k = find_last_bit(queued_in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003381 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003382 atomic_set(&retired_max_queue, 0);
3383 else
3384 atomic_set(&retired_max_queue, k + 1);
3385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003387 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388}
3389
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003390/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003391static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003392{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003393 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3394 hrt);
3395 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003396 return HRTIMER_NORESTART;
3397}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398
Douglas Gilberta10bc122016-04-25 12:16:32 -04003399/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003400static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003401{
3402 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3403 ew.work);
3404 sdebug_q_cmd_complete(sd_dp);
3405}
3406
Douglas Gilbertfd321192016-04-25 12:16:33 -04003407static struct sdebug_dev_info *sdebug_device_create(
3408 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003409{
3410 struct sdebug_dev_info *devip;
3411
3412 devip = kzalloc(sizeof(*devip), flags);
3413 if (devip) {
3414 devip->sdbg_host = sdbg_host;
3415 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3416 }
3417 return devip;
3418}
3419
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003420static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003422 struct sdebug_host_info *sdbg_host;
3423 struct sdebug_dev_info *open_devip = NULL;
3424 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003426 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3427 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003428 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 return NULL;
3430 }
3431 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3432 if ((devip->used) && (devip->channel == sdev->channel) &&
3433 (devip->target == sdev->id) &&
3434 (devip->lun == sdev->lun))
3435 return devip;
3436 else {
3437 if ((!devip->used) && (!open_devip))
3438 open_devip = devip;
3439 }
3440 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003441 if (!open_devip) { /* try and make a new one */
3442 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3443 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003444 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 return NULL;
3446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003448
3449 open_devip->channel = sdev->channel;
3450 open_devip->target = sdev->id;
3451 open_devip->lun = sdev->lun;
3452 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003453 atomic_set(&open_devip->num_in_q, 0);
3454 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003455 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003456 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457}
3458
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003459static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003461 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003462 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003463 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003464 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003465 return 0;
3466}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003468static int scsi_debug_slave_configure(struct scsi_device *sdp)
3469{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003470 struct sdebug_dev_info *devip =
3471 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003472
Douglas Gilbert773642d2016-04-25 12:16:28 -04003473 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003474 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003475 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003476 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3477 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3478 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003479 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003480 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003481 return 1; /* no resources, will be marked offline */
3482 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003483 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003484 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003485 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003486 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003487 return 0;
3488}
3489
3490static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3491{
3492 struct sdebug_dev_info *devip =
3493 (struct sdebug_dev_info *)sdp->hostdata;
3494
Douglas Gilbert773642d2016-04-25 12:16:28 -04003495 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003496 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003497 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3498 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003499 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003500 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003501 sdp->hostdata = NULL;
3502 }
3503}
3504
Douglas Gilberta10bc122016-04-25 12:16:32 -04003505/* If @cmnd found deletes its timer or work queue and returns true; else
3506 returns false */
3507static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003508{
3509 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003510 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003511 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003512 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003513 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003514
3515 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003516 qmax = sdebug_max_queue;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003517 r_qmax = atomic_read(&retired_max_queue);
3518 if (r_qmax > qmax)
3519 qmax = r_qmax;
3520 for (k = 0; k < qmax; ++k) {
3521 if (test_bit(k, queued_in_use_bm)) {
3522 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003523 if (cmnd != sqcp->a_cmnd)
3524 continue;
3525 /* found command */
3526 devip = (struct sdebug_dev_info *)
3527 cmnd->device->hostdata;
3528 if (devip)
3529 atomic_dec(&devip->num_in_q);
3530 sqcp->a_cmnd = NULL;
3531 sd_dp = sqcp->sd_dp;
3532 spin_unlock_irqrestore(&queued_arr_lock,
3533 iflags);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003534 if (sdebug_jdelay > 0 || sdebug_ndelay > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003535 if (sd_dp)
3536 hrtimer_cancel(&sd_dp->hrt);
3537 } else if (sdebug_jdelay < 0) {
3538 if (sd_dp)
3539 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003540 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003541 clear_bit(k, queued_in_use_bm);
3542 return true;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003543 }
3544 }
3545 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003546 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003547}
3548
Douglas Gilberta10bc122016-04-25 12:16:32 -04003549/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003550static void stop_all_queued(void)
3551{
3552 unsigned long iflags;
3553 int k;
3554 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003555 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003556 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003557
3558 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003559 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3560 if (test_bit(k, queued_in_use_bm)) {
3561 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003562 if (NULL == sqcp->a_cmnd)
3563 continue;
3564 devip = (struct sdebug_dev_info *)
3565 sqcp->a_cmnd->device->hostdata;
3566 if (devip)
3567 atomic_dec(&devip->num_in_q);
3568 sqcp->a_cmnd = NULL;
3569 sd_dp = sqcp->sd_dp;
3570 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003571 if (sdebug_jdelay > 0 || sdebug_ndelay > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003572 if (sd_dp)
3573 hrtimer_cancel(&sd_dp->hrt);
3574 } else if (sdebug_jdelay < 0) {
3575 if (sd_dp)
3576 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003577 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003578 clear_bit(k, queued_in_use_bm);
3579 spin_lock_irqsave(&queued_arr_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003580 }
3581 }
3582 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583}
3584
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003585/* Free queued command memory on heap */
3586static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003588 int k;
3589 struct sdebug_queued_cmd *sqcp;
3590
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003591 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3592 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003593 kfree(sqcp->sd_dp);
3594 sqcp->sd_dp = NULL;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596}
3597
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003598static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003600 bool ok;
3601
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003602 ++num_aborts;
3603 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003604 ok = stop_queued_cmnd(SCpnt);
3605 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3606 sdev_printk(KERN_INFO, SCpnt->device,
3607 "%s: command%s found\n", __func__,
3608 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003610 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611}
3612
3613static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3614{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003616 if (SCpnt && SCpnt->device) {
3617 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003618 struct sdebug_dev_info *devip =
3619 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003620
Douglas Gilbert773642d2016-04-25 12:16:28 -04003621 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003622 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003624 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 }
3626 return SUCCESS;
3627}
3628
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003629static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3630{
3631 struct sdebug_host_info *sdbg_host;
3632 struct sdebug_dev_info *devip;
3633 struct scsi_device *sdp;
3634 struct Scsi_Host *hp;
3635 int k = 0;
3636
3637 ++num_target_resets;
3638 if (!SCpnt)
3639 goto lie;
3640 sdp = SCpnt->device;
3641 if (!sdp)
3642 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003643 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003644 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3645 hp = sdp->host;
3646 if (!hp)
3647 goto lie;
3648 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3649 if (sdbg_host) {
3650 list_for_each_entry(devip,
3651 &sdbg_host->dev_info_list,
3652 dev_list)
3653 if (devip->target == sdp->id) {
3654 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3655 ++k;
3656 }
3657 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003658 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003659 sdev_printk(KERN_INFO, sdp,
3660 "%s: %d device(s) found in target\n", __func__, k);
3661lie:
3662 return SUCCESS;
3663}
3664
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3666{
3667 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003668 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 struct scsi_device * sdp;
3670 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003671 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003674 if (!(SCpnt && SCpnt->device))
3675 goto lie;
3676 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003677 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003678 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3679 hp = sdp->host;
3680 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003681 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003683 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003685 dev_list) {
3686 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3687 ++k;
3688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 }
3690 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003691 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003692 sdev_printk(KERN_INFO, sdp,
3693 "%s: %d device(s) found in host\n", __func__, k);
3694lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 return SUCCESS;
3696}
3697
3698static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3699{
3700 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003701 struct sdebug_dev_info *devip;
3702 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003705 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003706 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 spin_lock(&sdebug_host_list_lock);
3708 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003709 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3710 dev_list) {
3711 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3712 ++k;
3713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 }
3715 spin_unlock(&sdebug_host_list_lock);
3716 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003717 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003718 sdev_printk(KERN_INFO, SCpnt->device,
3719 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 return SUCCESS;
3721}
3722
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003723static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003724 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725{
3726 struct partition * pp;
3727 int starts[SDEBUG_MAX_PARTS + 2];
3728 int sectors_per_part, num_sectors, k;
3729 int heads_by_sects, start_sec, end_sec;
3730
3731 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003732 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003734 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3735 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003736 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003738 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003740 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3742 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003743 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3745 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003746 starts[sdebug_num_parts] = num_sectors;
3747 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748
3749 ramp[510] = 0x55; /* magic partition markings */
3750 ramp[511] = 0xAA;
3751 pp = (struct partition *)(ramp + 0x1be);
3752 for (k = 0; starts[k + 1]; ++k, ++pp) {
3753 start_sec = starts[k];
3754 end_sec = starts[k + 1] - 1;
3755 pp->boot_ind = 0;
3756
3757 pp->cyl = start_sec / heads_by_sects;
3758 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3759 / sdebug_sectors_per;
3760 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3761
3762 pp->end_cyl = end_sec / heads_by_sects;
3763 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3764 / sdebug_sectors_per;
3765 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3766
Akinobu Mita150c3542013-08-26 22:08:40 +09003767 pp->start_sect = cpu_to_le32(start_sec);
3768 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 pp->sys_ind = 0x83; /* plain Linux partition */
3770 }
3771}
3772
Douglas Gilbertfd321192016-04-25 12:16:33 -04003773static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3774 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003776 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003777 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003778 struct sdebug_queued_cmd *sqcp = NULL;
Tomas Winkler299b6c02015-07-28 16:54:24 +03003779 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003780 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003782 if (unlikely(WARN_ON(!cmnd)))
Tomas Winkler299b6c02015-07-28 16:54:24 +03003783 return SCSI_MLQUEUE_HOST_BUSY;
3784
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003785 if (unlikely(devip == NULL)) {
3786 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003787 scsi_result = DID_NO_CONNECT << 16;
3788 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03003790
3791 sdp = cmnd->device;
3792
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003793 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003794 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3795 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003796 if (delta_jiff == 0)
3797 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003799 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003800 spin_lock_irqsave(&queued_arr_lock, iflags);
3801 num_in_q = atomic_read(&devip->num_in_q);
3802 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003803 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003804 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003805 if (scsi_result) {
3806 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3807 goto respond_in_thread;
3808 } else
3809 scsi_result = device_qfull_result;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003810 } else if (unlikely((sdebug_every_nth != 0) &&
3811 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
3812 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003813 if ((num_in_q == (qdepth - 1)) &&
3814 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04003815 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003816 atomic_set(&sdebug_a_tsf, 0);
3817 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003818 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003820 }
3821
Douglas Gilbert773642d2016-04-25 12:16:28 -04003822 k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003823 if (unlikely(k >= sdebug_max_queue)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003825 if (scsi_result)
3826 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003827 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003828 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003829 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003830 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003831 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003832 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003833 (scsi_result ? "status: TASK SET FULL" :
3834 "report: host busy"));
3835 if (scsi_result)
3836 goto respond_in_thread;
3837 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003838 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003840 __set_bit(k, queued_in_use_bm);
3841 atomic_inc(&devip->num_in_q);
3842 sqcp = &queued_arr[k];
3843 sqcp->a_cmnd = cmnd;
3844 cmnd->result = scsi_result;
3845 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003846 sd_dp = sqcp->sd_dp;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003847 if (delta_jiff > 0 || sdebug_ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04003848 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003849
Douglas Gilbertb333a812016-04-25 12:16:30 -04003850 if (delta_jiff > 0) {
3851 struct timespec ts;
3852
3853 jiffies_to_timespec(delta_jiff, &ts);
3854 kt = ktime_set(ts.tv_sec, ts.tv_nsec);
3855 } else
3856 kt = ktime_set(0, sdebug_ndelay);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003857 if (NULL == sd_dp) {
3858 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
3859 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003860 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003861 sqcp->sd_dp = sd_dp;
3862 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003863 HRTIMER_MODE_REL);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003864 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
3865 sd_dp->qa_indx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003866 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003867 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003868 } else { /* jdelay < 0 */
Douglas Gilberta10bc122016-04-25 12:16:32 -04003869 if (NULL == sd_dp) {
3870 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
3871 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003872 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003873 sqcp->sd_dp = sd_dp;
3874 sd_dp->qa_indx = k;
3875 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003876 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003877 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003878 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003879 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
3880 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003881 sdev_printk(KERN_INFO, sdp,
3882 "%s: num_in_q=%d +1, %s%s\n", __func__,
3883 num_in_q, (inject ? "<inject> " : ""),
3884 "status: TASK SET FULL");
3885 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003886
3887respond_in_thread: /* call back to mid-layer using invocation thread */
3888 cmnd->result = scsi_result;
3889 cmnd->scsi_done(cmnd);
3890 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003892
Douglas Gilbert23183912006-09-16 20:30:47 -04003893/* Note: The following macros create attribute files in the
3894 /sys/module/scsi_debug/parameters directory. Unfortunately this
3895 driver is unaware of a change and cannot trigger auxiliary actions
3896 as it can when the corresponding attribute in the
3897 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3898 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003899module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3900module_param_named(ato, sdebug_ato, int, S_IRUGO);
3901module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003902module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003903module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3904module_param_named(dif, sdebug_dif, int, S_IRUGO);
3905module_param_named(dix, sdebug_dix, int, S_IRUGO);
3906module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3907module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3908module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3909module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3910module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3911module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3912module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3913module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
3914module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
3915module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
3916module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
3917module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
3918module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
3919module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
3920module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
3921module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
3922module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
3923module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
3924module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
3925module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
3926module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
3927module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
3928module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
3929module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
3930module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
3931module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
3932module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
3933module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
3934module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
3935module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
3936module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04003937 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003938module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003939 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940
3941MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
3942MODULE_DESCRIPTION("SCSI debug adapter driver");
3943MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003944MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945
3946MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003947MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09003948MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003949MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003950MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003951MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
3952MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003953MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07003954MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04003955MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003956MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04003957MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003958MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
3959MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
3960MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003961MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003962MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003963MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003964MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3965MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003966MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003967MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003969MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05003970MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05003971MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003972MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02003974MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02003975MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003976MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003977MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003978MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
3979MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04003980MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
3981MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003982MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003983MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
3984MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985
3986static char sdebug_info[256];
3987
3988static const char * scsi_debug_info(struct Scsi_Host * shp)
3989{
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003990 sprintf(sdebug_info,
3991 "scsi_debug, version %s [%s], dev_size_mb=%d, opts=0x%x",
3992 SDEBUG_VERSION, sdebug_version_date, sdebug_dev_size_mb,
3993 sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 return sdebug_info;
3995}
3996
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003997/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003998static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
3999 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000{
Al Viroc8ed5552013-03-31 01:46:06 -04004001 char arr[16];
4002 int opts;
4003 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004
Al Viroc8ed5552013-03-31 01:46:06 -04004005 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4006 return -EACCES;
4007 memcpy(arr, buffer, minLen);
4008 arr[minLen] = '\0';
4009 if (1 != sscanf(arr, "%d", &opts))
4010 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004011 sdebug_opts = opts;
4012 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4013 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4014 if (sdebug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004015 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04004016 return length;
4017}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004019/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4020 * same for each scsi_debug host (if more than one). Some of the counters
4021 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004022static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4023{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004024 int f, l;
4025 char b[32];
4026
Douglas Gilbert773642d2016-04-25 12:16:28 -04004027 if (sdebug_every_nth > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004028 snprintf(b, sizeof(b), " (curr:%d)",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004029 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004030 atomic_read(&sdebug_a_tsf) :
4031 atomic_read(&sdebug_cmnd_count)));
4032 else
4033 b[0] = '\0';
4034
4035 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
4036 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4037 "every_nth=%d%s\n"
4038 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
4039 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4040 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4041 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4042 "usec_in_jiffy=%lu\n",
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004043 SDEBUG_VERSION, sdebug_version_date,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004044 sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04004045 sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004046 sdebug_max_luns, atomic_read(&sdebug_completions),
4047 sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004048 sdebug_sectors_per, num_aborts, num_dev_resets,
4049 num_target_resets, num_bus_resets, num_host_resets,
4050 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4051
Douglas Gilbert773642d2016-04-25 12:16:28 -04004052 f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4053 if (f != sdebug_max_queue) {
4054 l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004055 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
4056 "queued_in_use_bm", f, l);
4057 }
Al Viroc8ed5552013-03-31 01:46:06 -04004058 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059}
4060
Akinobu Mita82069372013-10-14 22:48:04 +09004061static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004063 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064}
Douglas Gilbertc2206092016-04-25 12:16:31 -04004065/* Returns -EBUSY if jdelay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09004066static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4067 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004069 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004071 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004072 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004073 if (sdebug_jdelay != jdelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004074 unsigned long iflags;
4075 int k;
4076
4077 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004078 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4079 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004080 res = -EBUSY; /* have queued commands */
4081 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004082 /* make sure sdebug_defer instances get
4083 * re-allocated for new delay variant */
4084 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004085 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004086 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004087 }
4088 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004090 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 }
4092 return -EINVAL;
4093}
Akinobu Mita82069372013-10-14 22:48:04 +09004094static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004096static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4097{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004098 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004099}
4100/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004101/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004102static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004103 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004104{
4105 unsigned long iflags;
4106 int ndelay, res, k;
4107
4108 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4109 (ndelay >= 0) && (ndelay < 1000000000)) {
4110 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004111 if (sdebug_ndelay != ndelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004112 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004113 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4114 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004115 res = -EBUSY; /* have queued commands */
4116 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004117 /* make sure sdebug_defer instances get
4118 * re-allocated for new delay variant */
4119 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004120 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004121 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4122 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004123 }
4124 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4125 }
4126 return res;
4127 }
4128 return -EINVAL;
4129}
4130static DRIVER_ATTR_RW(ndelay);
4131
Akinobu Mita82069372013-10-14 22:48:04 +09004132static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004134 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135}
4136
Akinobu Mita82069372013-10-14 22:48:04 +09004137static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4138 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139{
4140 int opts;
4141 char work[20];
4142
4143 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004144 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 if (1 == sscanf(&work[2], "%x", &opts))
4146 goto opts_done;
4147 } else {
4148 if (1 == sscanf(work, "%d", &opts))
4149 goto opts_done;
4150 }
4151 }
4152 return -EINVAL;
4153opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004154 sdebug_opts = opts;
4155 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4156 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004157 atomic_set(&sdebug_cmnd_count, 0);
4158 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 return count;
4160}
Akinobu Mita82069372013-10-14 22:48:04 +09004161static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162
Akinobu Mita82069372013-10-14 22:48:04 +09004163static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004165 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166}
Akinobu Mita82069372013-10-14 22:48:04 +09004167static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4168 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169{
4170 int n;
4171
4172 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004173 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 return count;
4175 }
4176 return -EINVAL;
4177}
Akinobu Mita82069372013-10-14 22:48:04 +09004178static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179
Akinobu Mita82069372013-10-14 22:48:04 +09004180static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004182 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183}
Akinobu Mita82069372013-10-14 22:48:04 +09004184static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4185 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186{
4187 int n;
4188
4189 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004190 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 return count;
4192 }
4193 return -EINVAL;
4194}
Akinobu Mita82069372013-10-14 22:48:04 +09004195static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196
Akinobu Mita82069372013-10-14 22:48:04 +09004197static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004198{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004199 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004200}
Akinobu Mita82069372013-10-14 22:48:04 +09004201static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4202 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004203{
4204 int n;
4205
4206 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004207 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004208 sdebug_fake_rw = (sdebug_fake_rw > 0);
4209 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004210 if ((0 == n) && (NULL == fake_storep)) {
4211 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004212 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004213 1048576;
4214
4215 fake_storep = vmalloc(sz);
4216 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004217 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004218 return -ENOMEM;
4219 }
4220 memset(fake_storep, 0, sz);
4221 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004222 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004223 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004224 return count;
4225 }
4226 return -EINVAL;
4227}
Akinobu Mita82069372013-10-14 22:48:04 +09004228static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004229
Akinobu Mita82069372013-10-14 22:48:04 +09004230static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004231{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004232 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004233}
Akinobu Mita82069372013-10-14 22:48:04 +09004234static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4235 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004236{
4237 int n;
4238
4239 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004240 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004241 return count;
4242 }
4243 return -EINVAL;
4244}
Akinobu Mita82069372013-10-14 22:48:04 +09004245static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004246
Akinobu Mita82069372013-10-14 22:48:04 +09004247static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004249 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250}
Akinobu Mita82069372013-10-14 22:48:04 +09004251static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4252 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253{
4254 int n;
4255
4256 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004257 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 sdebug_max_tgts_luns();
4259 return count;
4260 }
4261 return -EINVAL;
4262}
Akinobu Mita82069372013-10-14 22:48:04 +09004263static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264
Akinobu Mita82069372013-10-14 22:48:04 +09004265static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004267 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268}
Akinobu Mita82069372013-10-14 22:48:04 +09004269static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270
Akinobu Mita82069372013-10-14 22:48:04 +09004271static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004273 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274}
Akinobu Mita82069372013-10-14 22:48:04 +09004275static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276
Akinobu Mita82069372013-10-14 22:48:04 +09004277static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004279 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280}
Akinobu Mita82069372013-10-14 22:48:04 +09004281static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4282 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283{
4284 int nth;
4285
4286 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004287 sdebug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004288 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 return count;
4290 }
4291 return -EINVAL;
4292}
Akinobu Mita82069372013-10-14 22:48:04 +09004293static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294
Akinobu Mita82069372013-10-14 22:48:04 +09004295static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004297 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298}
Akinobu Mita82069372013-10-14 22:48:04 +09004299static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4300 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301{
4302 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004303 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304
4305 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004306 changed = (sdebug_max_luns != n);
4307 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004309 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004310 struct sdebug_host_info *sdhp;
4311 struct sdebug_dev_info *dp;
4312
4313 spin_lock(&sdebug_host_list_lock);
4314 list_for_each_entry(sdhp, &sdebug_host_list,
4315 host_list) {
4316 list_for_each_entry(dp, &sdhp->dev_info_list,
4317 dev_list) {
4318 set_bit(SDEBUG_UA_LUNS_CHANGED,
4319 dp->uas_bm);
4320 }
4321 }
4322 spin_unlock(&sdebug_host_list_lock);
4323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324 return count;
4325 }
4326 return -EINVAL;
4327}
Akinobu Mita82069372013-10-14 22:48:04 +09004328static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329
Akinobu Mita82069372013-10-14 22:48:04 +09004330static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004331{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004332 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004333}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004334/* N.B. max_queue can be changed while there are queued commands. In flight
4335 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004336static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4337 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004338{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004339 unsigned long iflags;
4340 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004341
4342 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4343 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004344 spin_lock_irqsave(&queued_arr_lock, iflags);
4345 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004346 sdebug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004347 if (SCSI_DEBUG_CANQUEUE == k)
4348 atomic_set(&retired_max_queue, 0);
4349 else if (k >= n)
4350 atomic_set(&retired_max_queue, k + 1);
4351 else
4352 atomic_set(&retired_max_queue, 0);
4353 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004354 return count;
4355 }
4356 return -EINVAL;
4357}
Akinobu Mita82069372013-10-14 22:48:04 +09004358static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004359
Akinobu Mita82069372013-10-14 22:48:04 +09004360static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004361{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004362 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004363}
Akinobu Mita82069372013-10-14 22:48:04 +09004364static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004365
Akinobu Mita82069372013-10-14 22:48:04 +09004366static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004368 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369}
Akinobu Mita82069372013-10-14 22:48:04 +09004370static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371
Akinobu Mita82069372013-10-14 22:48:04 +09004372static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004373{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004374 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004375}
Akinobu Mita82069372013-10-14 22:48:04 +09004376static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4377 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004378{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004379 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004380 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004381
4382 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004383 changed = (sdebug_virtual_gb != n);
4384 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004385 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004386 if (changed) {
4387 struct sdebug_host_info *sdhp;
4388 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004389
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004390 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004391 list_for_each_entry(sdhp, &sdebug_host_list,
4392 host_list) {
4393 list_for_each_entry(dp, &sdhp->dev_info_list,
4394 dev_list) {
4395 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4396 dp->uas_bm);
4397 }
4398 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004399 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004400 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004401 return count;
4402 }
4403 return -EINVAL;
4404}
Akinobu Mita82069372013-10-14 22:48:04 +09004405static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004406
Akinobu Mita82069372013-10-14 22:48:04 +09004407static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004409 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410}
4411
Douglas Gilbertfd321192016-04-25 12:16:33 -04004412static int sdebug_add_adapter(void);
4413static void sdebug_remove_adapter(void);
4414
Akinobu Mita82069372013-10-14 22:48:04 +09004415static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4416 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004418 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004420 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 if (delta_hosts > 0) {
4423 do {
4424 sdebug_add_adapter();
4425 } while (--delta_hosts);
4426 } else if (delta_hosts < 0) {
4427 do {
4428 sdebug_remove_adapter();
4429 } while (++delta_hosts);
4430 }
4431 return count;
4432}
Akinobu Mita82069372013-10-14 22:48:04 +09004433static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Akinobu Mita82069372013-10-14 22:48:04 +09004435static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004436{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004437 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004438}
Akinobu Mita82069372013-10-14 22:48:04 +09004439static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4440 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004441{
4442 int n;
4443
4444 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004445 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004446 return count;
4447 }
4448 return -EINVAL;
4449}
Akinobu Mita82069372013-10-14 22:48:04 +09004450static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004451
Akinobu Mita82069372013-10-14 22:48:04 +09004452static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004453{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004454 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004455}
Akinobu Mita82069372013-10-14 22:48:04 +09004456static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004457
Akinobu Mita82069372013-10-14 22:48:04 +09004458static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004459{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004460 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004461}
Akinobu Mita82069372013-10-14 22:48:04 +09004462static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004463
Akinobu Mita82069372013-10-14 22:48:04 +09004464static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004465{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004466 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004467}
Akinobu Mita82069372013-10-14 22:48:04 +09004468static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004469
Akinobu Mita82069372013-10-14 22:48:04 +09004470static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004471{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004472 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004473}
Akinobu Mita82069372013-10-14 22:48:04 +09004474static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004475
Akinobu Mita82069372013-10-14 22:48:04 +09004476static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004477{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004478 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004479}
Akinobu Mita82069372013-10-14 22:48:04 +09004480static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004481
Akinobu Mita82069372013-10-14 22:48:04 +09004482static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004483{
4484 ssize_t count;
4485
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004486 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004487 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4488 sdebug_store_sectors);
4489
Tejun Heoc7badc92015-02-13 14:37:51 -08004490 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4491 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004492 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004493 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004494
4495 return count;
4496}
Akinobu Mita82069372013-10-14 22:48:04 +09004497static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004498
Akinobu Mita82069372013-10-14 22:48:04 +09004499static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004500{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004501 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004502}
Akinobu Mita82069372013-10-14 22:48:04 +09004503static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4504 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004505{
4506 int n;
4507
4508 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004509 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004510 return count;
4511 }
4512 return -EINVAL;
4513}
Akinobu Mita82069372013-10-14 22:48:04 +09004514static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004515
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004516static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4517{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004518 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004519}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004520/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004521static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4522 size_t count)
4523{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004524 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004525
4526 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004527 sdebug_host_lock = (n > 0);
4528 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004529 }
4530 return -EINVAL;
4531}
4532static DRIVER_ATTR_RW(host_lock);
4533
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004534static ssize_t strict_show(struct device_driver *ddp, char *buf)
4535{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004536 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004537}
4538static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4539 size_t count)
4540{
4541 int n;
4542
4543 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004544 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004545 return count;
4546 }
4547 return -EINVAL;
4548}
4549static DRIVER_ATTR_RW(strict);
4550
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004551
Akinobu Mita82069372013-10-14 22:48:04 +09004552/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004553 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4554 files (over those found in the /sys/module/scsi_debug/parameters
4555 directory) is that auxiliary actions can be triggered when an attribute
4556 is changed. For example see: sdebug_add_host_store() above.
4557 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004558
Akinobu Mita82069372013-10-14 22:48:04 +09004559static struct attribute *sdebug_drv_attrs[] = {
4560 &driver_attr_delay.attr,
4561 &driver_attr_opts.attr,
4562 &driver_attr_ptype.attr,
4563 &driver_attr_dsense.attr,
4564 &driver_attr_fake_rw.attr,
4565 &driver_attr_no_lun_0.attr,
4566 &driver_attr_num_tgts.attr,
4567 &driver_attr_dev_size_mb.attr,
4568 &driver_attr_num_parts.attr,
4569 &driver_attr_every_nth.attr,
4570 &driver_attr_max_luns.attr,
4571 &driver_attr_max_queue.attr,
4572 &driver_attr_no_uld.attr,
4573 &driver_attr_scsi_level.attr,
4574 &driver_attr_virtual_gb.attr,
4575 &driver_attr_add_host.attr,
4576 &driver_attr_vpd_use_hostno.attr,
4577 &driver_attr_sector_size.attr,
4578 &driver_attr_dix.attr,
4579 &driver_attr_dif.attr,
4580 &driver_attr_guard.attr,
4581 &driver_attr_ato.attr,
4582 &driver_attr_map.attr,
4583 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004584 &driver_attr_host_lock.attr,
4585 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004586 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004587 NULL,
4588};
4589ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004591static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004592
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593static int __init scsi_debug_init(void)
4594{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004595 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 int host_to_add;
4597 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004598 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004600 atomic_set(&sdebug_cmnd_count, 0);
4601 atomic_set(&sdebug_completions, 0);
4602 atomic_set(&retired_max_queue, 0);
4603
Douglas Gilbert773642d2016-04-25 12:16:28 -04004604 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004605 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004606 sdebug_ndelay = 0;
4607 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04004608 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004609
Douglas Gilbert773642d2016-04-25 12:16:28 -04004610 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004611 case 512:
4612 case 1024:
4613 case 2048:
4614 case 4096:
4615 break;
4616 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004617 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004618 return -EINVAL;
4619 }
4620
Douglas Gilbert773642d2016-04-25 12:16:28 -04004621 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004622
4623 case SD_DIF_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004624 break;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004625 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004626 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004627 case SD_DIF_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004628 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004629 break;
4630
4631 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004632 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004633 return -EINVAL;
4634 }
4635
Douglas Gilbert773642d2016-04-25 12:16:28 -04004636 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004637 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004638 return -EINVAL;
4639 }
4640
Douglas Gilbert773642d2016-04-25 12:16:28 -04004641 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004642 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004643 return -EINVAL;
4644 }
4645
Douglas Gilbert773642d2016-04-25 12:16:28 -04004646 if (sdebug_physblk_exp > 15) {
4647 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004648 return -EINVAL;
4649 }
4650
Douglas Gilbert773642d2016-04-25 12:16:28 -04004651 if (sdebug_lowest_aligned > 0x3fff) {
4652 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004653 return -EINVAL;
4654 }
4655
Douglas Gilbert773642d2016-04-25 12:16:28 -04004656 if (sdebug_dev_size_mb < 1)
4657 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4658 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4659 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004660 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661
4662 /* play around with geometry, don't waste too much on track 0 */
4663 sdebug_heads = 8;
4664 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004665 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004667 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02004668 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4670 (sdebug_sectors_per * sdebug_heads);
4671 if (sdebug_cylinders_per >= 1024) {
4672 /* other LLDs do this; implies >= 1GB ram disk ... */
4673 sdebug_heads = 255;
4674 sdebug_sectors_per = 63;
4675 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4676 (sdebug_sectors_per * sdebug_heads);
4677 }
4678
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004679 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004680 fake_storep = vmalloc(sz);
4681 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004682 pr_err("out of memory, 1\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004683 return -ENOMEM;
4684 }
4685 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004686 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004687 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689
Douglas Gilbert773642d2016-04-25 12:16:28 -04004690 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004691 int dif_size;
4692
4693 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4694 dif_storep = vmalloc(dif_size);
4695
Tomas Winklerc12879702015-07-28 16:54:20 +03004696 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004697
4698 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004699 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004700 ret = -ENOMEM;
4701 goto free_vm;
4702 }
4703
4704 memset(dif_storep, 0xff, dif_size);
4705 }
4706
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004707 /* Logical Block Provisioning */
4708 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004709 sdebug_unmap_max_blocks =
4710 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004711
Douglas Gilbert773642d2016-04-25 12:16:28 -04004712 sdebug_unmap_max_desc =
4713 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04004714
Douglas Gilbert773642d2016-04-25 12:16:28 -04004715 sdebug_unmap_granularity =
4716 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004717
Douglas Gilbert773642d2016-04-25 12:16:28 -04004718 if (sdebug_unmap_alignment &&
4719 sdebug_unmap_granularity <=
4720 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004721 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004722 return -EINVAL;
4723 }
4724
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004725 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4726 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004727
Tomas Winklerc12879702015-07-28 16:54:20 +03004728 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004729
4730 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004731 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004732 ret = -ENOMEM;
4733 goto free_vm;
4734 }
4735
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004736 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004737
4738 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004739 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004740 map_region(0, 2);
4741 }
4742
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004743 pseudo_primary = root_device_register("pseudo_0");
4744 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004745 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004746 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004747 goto free_vm;
4748 }
4749 ret = bus_register(&pseudo_lld_bus);
4750 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004751 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004752 goto dev_unreg;
4753 }
4754 ret = driver_register(&sdebug_driverfs_driver);
4755 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004756 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004757 goto bus_unreg;
4758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759
Douglas Gilbert773642d2016-04-25 12:16:28 -04004760 host_to_add = sdebug_add_host;
4761 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
4763 for (k = 0; k < host_to_add; k++) {
4764 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004765 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 break;
4767 }
4768 }
4769
Douglas Gilbert773642d2016-04-25 12:16:28 -04004770 if (sdebug_verbose)
4771 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03004772
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004774
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004775bus_unreg:
4776 bus_unregister(&pseudo_lld_bus);
4777dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004778 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004779free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03004780 vfree(map_storep);
4781 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004782 vfree(fake_storep);
4783
4784 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785}
4786
4787static void __exit scsi_debug_exit(void)
4788{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004789 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790
4791 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004792 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 for (; k; k--)
4794 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 driver_unregister(&sdebug_driverfs_driver);
4796 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004797 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798
Tomas Winklerde232af2015-07-28 16:54:22 +03004799 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 vfree(fake_storep);
4801}
4802
4803device_initcall(scsi_debug_init);
4804module_exit(scsi_debug_exit);
4805
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806static void sdebug_release_adapter(struct device * dev)
4807{
4808 struct sdebug_host_info *sdbg_host;
4809
4810 sdbg_host = to_sdebug_host(dev);
4811 kfree(sdbg_host);
4812}
4813
4814static int sdebug_add_adapter(void)
4815{
4816 int k, devs_per_host;
4817 int error = 0;
4818 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004819 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004821 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004823 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 return -ENOMEM;
4825 }
4826
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4828
Douglas Gilbert773642d2016-04-25 12:16:28 -04004829 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004831 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4832 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004833 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 error = -ENOMEM;
4835 goto clean;
4836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 }
4838
4839 spin_lock(&sdebug_host_list_lock);
4840 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4841 spin_unlock(&sdebug_host_list_lock);
4842
4843 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004844 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004846 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847
4848 error = device_register(&sdbg_host->dev);
4849
4850 if (error)
4851 goto clean;
4852
Douglas Gilbert773642d2016-04-25 12:16:28 -04004853 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 return error;
4855
4856clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004857 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4858 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 list_del(&sdbg_devinfo->dev_list);
4860 kfree(sdbg_devinfo);
4861 }
4862
4863 kfree(sdbg_host);
4864 return error;
4865}
4866
4867static void sdebug_remove_adapter(void)
4868{
4869 struct sdebug_host_info * sdbg_host = NULL;
4870
4871 spin_lock(&sdebug_host_list_lock);
4872 if (!list_empty(&sdebug_host_list)) {
4873 sdbg_host = list_entry(sdebug_host_list.prev,
4874 struct sdebug_host_info, host_list);
4875 list_del(&sdbg_host->host_list);
4876 }
4877 spin_unlock(&sdebug_host_list_lock);
4878
4879 if (!sdbg_host)
4880 return;
4881
Douglas Gilbert773642d2016-04-25 12:16:28 -04004882 device_unregister(&sdbg_host->dev);
4883 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884}
4885
Douglas Gilbertfd321192016-04-25 12:16:33 -04004886static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004887{
4888 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004889 unsigned long iflags;
4890 struct sdebug_dev_info *devip;
4891
4892 spin_lock_irqsave(&queued_arr_lock, iflags);
4893 devip = (struct sdebug_dev_info *)sdev->hostdata;
4894 if (NULL == devip) {
4895 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4896 return -ENODEV;
4897 }
4898 num_in_q = atomic_read(&devip->num_in_q);
4899 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004900
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004901 if (qdepth < 1)
4902 qdepth = 1;
4903 /* allow to exceed max host queued_arr elements for testing */
4904 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4905 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004906 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004907
Douglas Gilbert773642d2016-04-25 12:16:28 -04004908 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004909 sdev_printk(KERN_INFO, sdev,
4910 "%s: qdepth=%d, num_in_q=%d\n",
4911 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004912 }
4913 return sdev->queue_depth;
4914}
4915
Douglas Gilbertfd321192016-04-25 12:16:33 -04004916static int check_inject(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004917{
4918 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4919
4920 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4921
Douglas Gilbert773642d2016-04-25 12:16:28 -04004922 if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
Douglas Gilbert817fd662014-11-24 20:18:02 -05004923 atomic_set(&sdebug_cmnd_count, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004924 if (sdebug_every_nth < -1)
4925 sdebug_every_nth = -1;
4926 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004927 return 1; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004928 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05004929 scsi_medium_access_command(scp))
4930 return 1; /* time out reads and writes */
4931 if (sdebug_any_injecting_opt) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004932 if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004933 ep->inj_recovered = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004934 if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004935 ep->inj_transport = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004936 if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004937 ep->inj_dif = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004938 if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004939 ep->inj_dix = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004940 if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004941 ep->inj_short = true;
4942 }
4943 }
4944 return 0;
4945}
4946
Douglas Gilbertfd321192016-04-25 12:16:33 -04004947static int scsi_debug_queuecommand(struct Scsi_Host *shost,
4948 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004949{
4950 u8 sdeb_i;
4951 struct scsi_device *sdp = scp->device;
4952 const struct opcode_info_t *oip;
4953 const struct opcode_info_t *r_oip;
4954 struct sdebug_dev_info *devip;
4955 u8 *cmd = scp->cmnd;
4956 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
4957 int k, na;
4958 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004959 u32 flags;
4960 u16 sa;
4961 u8 opcode = cmd[0];
4962 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004963
4964 scsi_set_resid(scp, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004965 if (unlikely(sdebug_verbose &&
4966 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004967 char b[120];
4968 int n, len, sb;
4969
4970 len = scp->cmd_len;
4971 sb = (int)sizeof(b);
4972 if (len > 32)
4973 strcpy(b, "too long, over 32 bytes");
4974 else {
4975 for (k = 0, n = 0; k < len && n < sb; ++k)
4976 n += scnprintf(b + n, sb - n, "%02x ",
4977 (u32)cmd[k]);
4978 }
4979 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
4980 }
Tomas Winkler34d55432015-07-28 16:54:21 +03004981 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004982 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
4983 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004984
4985 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
4986 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
4987 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004988 if (unlikely(!devip)) {
4989 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004990 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004991 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004992 }
4993 na = oip->num_attached;
4994 r_pfp = oip->pfp;
4995 if (na) { /* multiple commands with this opcode */
4996 r_oip = oip;
4997 if (FF_SA & r_oip->flags) {
4998 if (F_SA_LOW & oip->flags)
4999 sa = 0x1f & cmd[1];
5000 else
5001 sa = get_unaligned_be16(cmd + 8);
5002 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5003 if (opcode == oip->opcode && sa == oip->sa)
5004 break;
5005 }
5006 } else { /* since no service action only check opcode */
5007 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5008 if (opcode == oip->opcode)
5009 break;
5010 }
5011 }
5012 if (k > na) {
5013 if (F_SA_LOW & r_oip->flags)
5014 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5015 else if (F_SA_HIGH & r_oip->flags)
5016 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5017 else
5018 mk_sense_invalid_opcode(scp);
5019 goto check_cond;
5020 }
5021 } /* else (when na==0) we assume the oip is a match */
5022 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005023 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005024 mk_sense_invalid_opcode(scp);
5025 goto check_cond;
5026 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005027 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005028 if (sdebug_verbose)
5029 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5030 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005031 mk_sense_invalid_opcode(scp);
5032 goto check_cond;
5033 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005034 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005035 u8 rem;
5036 int j;
5037
5038 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5039 rem = ~oip->len_mask[k] & cmd[k];
5040 if (rem) {
5041 for (j = 7; j >= 0; --j, rem <<= 1) {
5042 if (0x80 & rem)
5043 break;
5044 }
5045 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5046 goto check_cond;
5047 }
5048 }
5049 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005050 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005051 find_first_bit(devip->uas_bm,
5052 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005053 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005054 if (errsts)
5055 goto check_cond;
5056 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005057 if (unlikely((F_M_ACCESS & flags) && devip->stopped)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005058 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005059 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005060 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5061 "%s\n", my_name, "initializing command "
5062 "required");
5063 errsts = check_condition_result;
5064 goto fini;
5065 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005066 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005067 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005068 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005069 if (check_inject(scp))
5070 return 0; /* ignore command: make trouble */
5071 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005072 if (likely(oip->pfp))
5073 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005074 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5075 errsts = r_pfp(scp, devip);
5076
5077fini:
5078 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005079 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005080check_cond:
5081 return schedule_resp(scp, devip, check_condition_result, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005082err_out:
5083 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005084}
5085
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005086static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005087 .show_info = scsi_debug_show_info,
5088 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005089 .proc_name = sdebug_proc_name,
5090 .name = "SCSI DEBUG",
5091 .info = scsi_debug_info,
5092 .slave_alloc = scsi_debug_slave_alloc,
5093 .slave_configure = scsi_debug_slave_configure,
5094 .slave_destroy = scsi_debug_slave_destroy,
5095 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005096 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005097 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005098 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005099 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005100 .eh_target_reset_handler = scsi_debug_target_reset,
5101 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005102 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005103 .can_queue = SCSI_DEBUG_CANQUEUE,
5104 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005105 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005106 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005107 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005108 .use_clustering = DISABLE_CLUSTERING,
5109 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005110 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05005111 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005112};
5113
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114static int sdebug_driver_probe(struct device * dev)
5115{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005116 int error = 0;
5117 struct sdebug_host_info *sdbg_host;
5118 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005119 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120
5121 sdbg_host = to_sdebug_host(dev);
5122
Douglas Gilbert773642d2016-04-25 12:16:28 -04005123 sdebug_driver_template.can_queue = sdebug_max_queue;
5124 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005125 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005126 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5127 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005128 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005129 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132
5133 sdbg_host->shost = hpnt;
5134 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005135 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5136 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005138 hpnt->max_id = sdebug_num_tgts;
5139 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005140 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005142 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005143
Douglas Gilbert773642d2016-04-25 12:16:28 -04005144 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005145
5146 case SD_DIF_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005147 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005148 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005149 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005150 break;
5151
5152 case SD_DIF_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005153 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005154 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005155 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005156 break;
5157
5158 case SD_DIF_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005159 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005160 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005161 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005162 break;
5163
5164 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005165 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005166 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005167 break;
5168 }
5169
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005170 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005171
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005172 if (have_dif_prot || sdebug_dix)
5173 pr_info("host protection%s%s%s%s%s%s%s\n",
5174 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5175 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5176 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5177 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5178 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5179 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5180 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005181
Douglas Gilbert773642d2016-04-25 12:16:28 -04005182 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005183 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5184 else
5185 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5186
Douglas Gilbert773642d2016-04-25 12:16:28 -04005187 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5188 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 error = scsi_add_host(hpnt, &sdbg_host->dev);
5190 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005191 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 error = -ENODEV;
5193 scsi_host_put(hpnt);
5194 } else
5195 scsi_scan_host(hpnt);
5196
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005197 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198}
5199
5200static int sdebug_driver_remove(struct device * dev)
5201{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005203 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204
5205 sdbg_host = to_sdebug_host(dev);
5206
5207 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005208 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 return -ENODEV;
5210 }
5211
5212 scsi_remove_host(sdbg_host->shost);
5213
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005214 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5215 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 list_del(&sdbg_devinfo->dev_list);
5217 kfree(sdbg_devinfo);
5218 }
5219
5220 scsi_host_put(sdbg_host->shost);
5221 return 0;
5222}
5223
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005224static int pseudo_lld_bus_match(struct device *dev,
5225 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005227 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005229
5230static struct bus_type pseudo_lld_bus = {
5231 .name = "pseudo",
5232 .match = pseudo_lld_bus_match,
5233 .probe = sdebug_driver_probe,
5234 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005235 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005236};