blob: e97ddf0574c826780581132aea299dbea9deb26d [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 Gilbert8d039e22016-04-30 22:44:43 -04003211/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3212 * (W-LUN), the normal Linux scanning logic does not associate it with a
3213 * device (e.g. /dev/sg7). The following magic will make that association:
3214 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3215 * where <n> is a host number. If there are multiple targets in a host then
3216 * the above will associate a W-LUN to each target. To only get a W-LUN
3217 * for target 2, then use "echo '- 2 49409' > scan" .
3218 */
3219static int resp_report_luns(struct scsi_cmnd *scp,
3220 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003222 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003223 unsigned int alloc_len;
3224 unsigned char select_report;
3225 u64 lun;
3226 struct scsi_lun *lun_p;
3227 u8 *arr;
3228 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3229 unsigned int wlun_cnt; /* report luns W-LUN count */
3230 unsigned int tlun_cnt; /* total LUN count */
3231 unsigned int rlen; /* response length (in bytes) */
3232 int i, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003234 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003235
3236 select_report = cmd[2];
3237 alloc_len = get_unaligned_be32(cmd + 6);
3238
3239 if (alloc_len < 4) {
3240 pr_err("alloc len too small %d\n", alloc_len);
3241 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 return check_condition_result;
3243 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003244
3245 switch (select_report) {
3246 case 0: /* all LUNs apart from W-LUNs */
3247 lun_cnt = sdebug_max_luns;
3248 wlun_cnt = 0;
3249 break;
3250 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003251 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003252 wlun_cnt = 1;
3253 break;
3254 case 2: /* all LUNs */
3255 lun_cnt = sdebug_max_luns;
3256 wlun_cnt = 1;
3257 break;
3258 case 0x10: /* only administrative LUs */
3259 case 0x11: /* see SPC-5 */
3260 case 0x12: /* only subsiduary LUs owned by referenced LU */
3261 default:
3262 pr_debug("select report invalid %d\n", select_report);
3263 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3264 return check_condition_result;
3265 }
3266
3267 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003268 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003269
3270 tlun_cnt = lun_cnt + wlun_cnt;
3271
3272 rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8;
3273 arr = vmalloc(rlen);
3274 if (!arr) {
3275 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3276 INSUFF_RES_ASCQ);
3277 return check_condition_result;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003278 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003279 memset(arr, 0, rlen);
3280 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3281 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3282
3283 /* luns start at byte 8 in response following the header */
3284 lun_p = (struct scsi_lun *)&arr[8];
3285
3286 /* LUNs use single level peripheral device addressing method */
3287 lun = sdebug_no_lun_0 ? 1 : 0;
3288 for (i = 0; i < lun_cnt; i++)
3289 int_to_scsilun(lun++, lun_p++);
3290
3291 if (wlun_cnt)
3292 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++);
3293
3294 put_unaligned_be32(rlen - 8, &arr[0]);
3295
3296 res = fill_from_dev_buffer(scp, arr, rlen);
3297 vfree(arr);
3298 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299}
3300
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003301static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3302 unsigned int num, struct sdebug_dev_info *devip)
3303{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003304 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003305 unsigned char *kaddr, *buf;
3306 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003307 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003308 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003309
3310 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003311 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003312 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003313 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3314 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003315 return check_condition_result;
3316 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003317
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003318 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003319
3320 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003321 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3322 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003323
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003324 while (sg_miter_next(&miter)) {
3325 kaddr = miter.addr;
3326 for (j = 0; j < miter.length; j++)
3327 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003328
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003329 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003330 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003331 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003332 kfree(buf);
3333
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003334 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003335}
3336
Douglas Gilbertfd321192016-04-25 12:16:33 -04003337static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3338 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003339{
3340 u8 *cmd = scp->cmnd;
3341 u64 lba;
3342 u32 num;
3343 int errsts;
3344
3345 if (!scsi_bidi_cmnd(scp)) {
3346 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3347 INSUFF_RES_ASCQ);
3348 return check_condition_result;
3349 }
3350 errsts = resp_read_dt0(scp, devip);
3351 if (errsts)
3352 return errsts;
3353 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3354 errsts = resp_write_dt0(scp, devip);
3355 if (errsts)
3356 return errsts;
3357 }
3358 lba = get_unaligned_be32(cmd + 2);
3359 num = get_unaligned_be16(cmd + 7);
3360 return resp_xdwriteread(scp, lba, num, devip);
3361}
3362
Douglas Gilberta10bc122016-04-25 12:16:32 -04003363/* Queued command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003364static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003366 int qa_indx;
3367 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003369 struct sdebug_queued_cmd *sqcp;
3370 struct scsi_cmnd *scp;
3371 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003373 atomic_inc(&sdebug_completions);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003374 qa_indx = sd_dp->qa_indx;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003375 if (unlikely((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE))) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003376 pr_err("wild qa_indx=%d\n", qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 return;
3378 }
3379 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003380 sqcp = &queued_arr[qa_indx];
3381 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003382 if (unlikely(scp == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003384 pr_err("scp is NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 return;
3386 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003387 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003388 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003389 atomic_dec(&devip->num_in_q);
3390 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003391 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003392 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003393 retiring = 1;
3394
3395 sqcp->a_cmnd = NULL;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003396 if (unlikely(!test_and_clear_bit(qa_indx, queued_in_use_bm))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003397 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003398 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003399 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003401
3402 if (unlikely(retiring)) { /* user has reduced max_queue */
3403 int k, retval;
3404
3405 retval = atomic_read(&retired_max_queue);
3406 if (qa_indx >= retval) {
3407 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003408 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003409 return;
3410 }
3411 k = find_last_bit(queued_in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003412 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003413 atomic_set(&retired_max_queue, 0);
3414 else
3415 atomic_set(&retired_max_queue, k + 1);
3416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003418 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419}
3420
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003421/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003422static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003423{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003424 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3425 hrt);
3426 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003427 return HRTIMER_NORESTART;
3428}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429
Douglas Gilberta10bc122016-04-25 12:16:32 -04003430/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003431static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003432{
3433 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3434 ew.work);
3435 sdebug_q_cmd_complete(sd_dp);
3436}
3437
Douglas Gilbertfd321192016-04-25 12:16:33 -04003438static struct sdebug_dev_info *sdebug_device_create(
3439 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003440{
3441 struct sdebug_dev_info *devip;
3442
3443 devip = kzalloc(sizeof(*devip), flags);
3444 if (devip) {
3445 devip->sdbg_host = sdbg_host;
3446 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3447 }
3448 return devip;
3449}
3450
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003451static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003453 struct sdebug_host_info *sdbg_host;
3454 struct sdebug_dev_info *open_devip = NULL;
3455 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003457 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3458 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003459 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 return NULL;
3461 }
3462 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3463 if ((devip->used) && (devip->channel == sdev->channel) &&
3464 (devip->target == sdev->id) &&
3465 (devip->lun == sdev->lun))
3466 return devip;
3467 else {
3468 if ((!devip->used) && (!open_devip))
3469 open_devip = devip;
3470 }
3471 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003472 if (!open_devip) { /* try and make a new one */
3473 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3474 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003475 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 return NULL;
3477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003479
3480 open_devip->channel = sdev->channel;
3481 open_devip->target = sdev->id;
3482 open_devip->lun = sdev->lun;
3483 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003484 atomic_set(&open_devip->num_in_q, 0);
3485 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003486 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003487 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488}
3489
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003490static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003492 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003493 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003494 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003495 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003496 return 0;
3497}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003499static int scsi_debug_slave_configure(struct scsi_device *sdp)
3500{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003501 struct sdebug_dev_info *devip =
3502 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003503
Douglas Gilbert773642d2016-04-25 12:16:28 -04003504 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003505 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003506 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003507 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3508 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3509 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003510 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003511 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003512 return 1; /* no resources, will be marked offline */
3513 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003514 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003515 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003516 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003517 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003518 return 0;
3519}
3520
3521static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3522{
3523 struct sdebug_dev_info *devip =
3524 (struct sdebug_dev_info *)sdp->hostdata;
3525
Douglas Gilbert773642d2016-04-25 12:16:28 -04003526 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003527 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003528 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3529 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003530 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003531 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003532 sdp->hostdata = NULL;
3533 }
3534}
3535
Douglas Gilberta10bc122016-04-25 12:16:32 -04003536/* If @cmnd found deletes its timer or work queue and returns true; else
3537 returns false */
3538static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003539{
3540 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003541 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003542 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003543 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003544 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003545
3546 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003547 qmax = sdebug_max_queue;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003548 r_qmax = atomic_read(&retired_max_queue);
3549 if (r_qmax > qmax)
3550 qmax = r_qmax;
3551 for (k = 0; k < qmax; ++k) {
3552 if (test_bit(k, queued_in_use_bm)) {
3553 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003554 if (cmnd != sqcp->a_cmnd)
3555 continue;
3556 /* found command */
3557 devip = (struct sdebug_dev_info *)
3558 cmnd->device->hostdata;
3559 if (devip)
3560 atomic_dec(&devip->num_in_q);
3561 sqcp->a_cmnd = NULL;
3562 sd_dp = sqcp->sd_dp;
3563 spin_unlock_irqrestore(&queued_arr_lock,
3564 iflags);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003565 if (sdebug_jdelay > 0 || sdebug_ndelay > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003566 if (sd_dp)
3567 hrtimer_cancel(&sd_dp->hrt);
3568 } else if (sdebug_jdelay < 0) {
3569 if (sd_dp)
3570 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003571 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003572 clear_bit(k, queued_in_use_bm);
3573 return true;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003574 }
3575 }
3576 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003577 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003578}
3579
Douglas Gilberta10bc122016-04-25 12:16:32 -04003580/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003581static void stop_all_queued(void)
3582{
3583 unsigned long iflags;
3584 int k;
3585 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003586 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003587 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003588
3589 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003590 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3591 if (test_bit(k, queued_in_use_bm)) {
3592 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003593 if (NULL == sqcp->a_cmnd)
3594 continue;
3595 devip = (struct sdebug_dev_info *)
3596 sqcp->a_cmnd->device->hostdata;
3597 if (devip)
3598 atomic_dec(&devip->num_in_q);
3599 sqcp->a_cmnd = NULL;
3600 sd_dp = sqcp->sd_dp;
3601 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003602 if (sdebug_jdelay > 0 || sdebug_ndelay > 0) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003603 if (sd_dp)
3604 hrtimer_cancel(&sd_dp->hrt);
3605 } else if (sdebug_jdelay < 0) {
3606 if (sd_dp)
3607 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003608 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003609 clear_bit(k, queued_in_use_bm);
3610 spin_lock_irqsave(&queued_arr_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003611 }
3612 }
3613 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614}
3615
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003616/* Free queued command memory on heap */
3617static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003619 int k;
3620 struct sdebug_queued_cmd *sqcp;
3621
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003622 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3623 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003624 kfree(sqcp->sd_dp);
3625 sqcp->sd_dp = NULL;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627}
3628
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003629static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003631 bool ok;
3632
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003633 ++num_aborts;
3634 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003635 ok = stop_queued_cmnd(SCpnt);
3636 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3637 sdev_printk(KERN_INFO, SCpnt->device,
3638 "%s: command%s found\n", __func__,
3639 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003641 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642}
3643
3644static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3645{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003647 if (SCpnt && SCpnt->device) {
3648 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003649 struct sdebug_dev_info *devip =
3650 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003651
Douglas Gilbert773642d2016-04-25 12:16:28 -04003652 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003653 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003655 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 }
3657 return SUCCESS;
3658}
3659
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003660static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3661{
3662 struct sdebug_host_info *sdbg_host;
3663 struct sdebug_dev_info *devip;
3664 struct scsi_device *sdp;
3665 struct Scsi_Host *hp;
3666 int k = 0;
3667
3668 ++num_target_resets;
3669 if (!SCpnt)
3670 goto lie;
3671 sdp = SCpnt->device;
3672 if (!sdp)
3673 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003674 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003675 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3676 hp = sdp->host;
3677 if (!hp)
3678 goto lie;
3679 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3680 if (sdbg_host) {
3681 list_for_each_entry(devip,
3682 &sdbg_host->dev_info_list,
3683 dev_list)
3684 if (devip->target == sdp->id) {
3685 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3686 ++k;
3687 }
3688 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003689 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003690 sdev_printk(KERN_INFO, sdp,
3691 "%s: %d device(s) found in target\n", __func__, k);
3692lie:
3693 return SUCCESS;
3694}
3695
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3697{
3698 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003699 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 struct scsi_device * sdp;
3701 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003702 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003705 if (!(SCpnt && SCpnt->device))
3706 goto lie;
3707 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003708 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003709 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3710 hp = sdp->host;
3711 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003712 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003714 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003716 dev_list) {
3717 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3718 ++k;
3719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 }
3721 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003722 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003723 sdev_printk(KERN_INFO, sdp,
3724 "%s: %d device(s) found in host\n", __func__, k);
3725lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 return SUCCESS;
3727}
3728
3729static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3730{
3731 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003732 struct sdebug_dev_info *devip;
3733 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003736 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003737 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 spin_lock(&sdebug_host_list_lock);
3739 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003740 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3741 dev_list) {
3742 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3743 ++k;
3744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 }
3746 spin_unlock(&sdebug_host_list_lock);
3747 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003748 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003749 sdev_printk(KERN_INFO, SCpnt->device,
3750 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 return SUCCESS;
3752}
3753
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003754static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003755 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756{
3757 struct partition * pp;
3758 int starts[SDEBUG_MAX_PARTS + 2];
3759 int sectors_per_part, num_sectors, k;
3760 int heads_by_sects, start_sec, end_sec;
3761
3762 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003763 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003765 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3766 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003767 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003769 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003771 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3773 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003774 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3776 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003777 starts[sdebug_num_parts] = num_sectors;
3778 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779
3780 ramp[510] = 0x55; /* magic partition markings */
3781 ramp[511] = 0xAA;
3782 pp = (struct partition *)(ramp + 0x1be);
3783 for (k = 0; starts[k + 1]; ++k, ++pp) {
3784 start_sec = starts[k];
3785 end_sec = starts[k + 1] - 1;
3786 pp->boot_ind = 0;
3787
3788 pp->cyl = start_sec / heads_by_sects;
3789 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3790 / sdebug_sectors_per;
3791 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3792
3793 pp->end_cyl = end_sec / heads_by_sects;
3794 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3795 / sdebug_sectors_per;
3796 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3797
Akinobu Mita150c3542013-08-26 22:08:40 +09003798 pp->start_sect = cpu_to_le32(start_sec);
3799 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 pp->sys_ind = 0x83; /* plain Linux partition */
3801 }
3802}
3803
Douglas Gilbertfd321192016-04-25 12:16:33 -04003804static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3805 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003807 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003808 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003809 struct sdebug_queued_cmd *sqcp = NULL;
Tomas Winkler299b6c02015-07-28 16:54:24 +03003810 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003811 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003813 if (unlikely(WARN_ON(!cmnd)))
Tomas Winkler299b6c02015-07-28 16:54:24 +03003814 return SCSI_MLQUEUE_HOST_BUSY;
3815
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003816 if (unlikely(devip == NULL)) {
3817 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003818 scsi_result = DID_NO_CONNECT << 16;
3819 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03003821
3822 sdp = cmnd->device;
3823
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003824 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003825 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3826 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003827 if (delta_jiff == 0)
3828 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003830 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003831 spin_lock_irqsave(&queued_arr_lock, iflags);
3832 num_in_q = atomic_read(&devip->num_in_q);
3833 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003834 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003835 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003836 if (scsi_result) {
3837 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3838 goto respond_in_thread;
3839 } else
3840 scsi_result = device_qfull_result;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003841 } else if (unlikely((sdebug_every_nth != 0) &&
3842 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
3843 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003844 if ((num_in_q == (qdepth - 1)) &&
3845 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04003846 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003847 atomic_set(&sdebug_a_tsf, 0);
3848 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003849 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003851 }
3852
Douglas Gilbert773642d2016-04-25 12:16:28 -04003853 k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003854 if (unlikely(k >= sdebug_max_queue)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003856 if (scsi_result)
3857 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003858 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003859 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003860 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003861 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003862 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003863 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003864 (scsi_result ? "status: TASK SET FULL" :
3865 "report: host busy"));
3866 if (scsi_result)
3867 goto respond_in_thread;
3868 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003869 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003871 __set_bit(k, queued_in_use_bm);
3872 atomic_inc(&devip->num_in_q);
3873 sqcp = &queued_arr[k];
3874 sqcp->a_cmnd = cmnd;
3875 cmnd->result = scsi_result;
3876 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003877 sd_dp = sqcp->sd_dp;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003878 if (delta_jiff > 0 || sdebug_ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04003879 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003880
Douglas Gilbertb333a812016-04-25 12:16:30 -04003881 if (delta_jiff > 0) {
3882 struct timespec ts;
3883
3884 jiffies_to_timespec(delta_jiff, &ts);
3885 kt = ktime_set(ts.tv_sec, ts.tv_nsec);
3886 } else
3887 kt = ktime_set(0, sdebug_ndelay);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003888 if (NULL == sd_dp) {
3889 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
3890 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003891 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003892 sqcp->sd_dp = sd_dp;
3893 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003894 HRTIMER_MODE_REL);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003895 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
3896 sd_dp->qa_indx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003897 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003898 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003899 } else { /* jdelay < 0 */
Douglas Gilberta10bc122016-04-25 12:16:32 -04003900 if (NULL == sd_dp) {
3901 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
3902 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003903 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003904 sqcp->sd_dp = sd_dp;
3905 sd_dp->qa_indx = k;
3906 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003907 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003908 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003909 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003910 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
3911 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003912 sdev_printk(KERN_INFO, sdp,
3913 "%s: num_in_q=%d +1, %s%s\n", __func__,
3914 num_in_q, (inject ? "<inject> " : ""),
3915 "status: TASK SET FULL");
3916 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003917
3918respond_in_thread: /* call back to mid-layer using invocation thread */
3919 cmnd->result = scsi_result;
3920 cmnd->scsi_done(cmnd);
3921 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003923
Douglas Gilbert23183912006-09-16 20:30:47 -04003924/* Note: The following macros create attribute files in the
3925 /sys/module/scsi_debug/parameters directory. Unfortunately this
3926 driver is unaware of a change and cannot trigger auxiliary actions
3927 as it can when the corresponding attribute in the
3928 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3929 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003930module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3931module_param_named(ato, sdebug_ato, int, S_IRUGO);
3932module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003933module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003934module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3935module_param_named(dif, sdebug_dif, int, S_IRUGO);
3936module_param_named(dix, sdebug_dix, int, S_IRUGO);
3937module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3938module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3939module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3940module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3941module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3942module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3943module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3944module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
3945module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
3946module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
3947module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
3948module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
3949module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
3950module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
3951module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
3952module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
3953module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
3954module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
3955module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
3956module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
3957module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
3958module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
3959module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
3960module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
3961module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
3962module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
3963module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
3964module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
3965module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
3966module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
3967module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04003968 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003969module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003970 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971
3972MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
3973MODULE_DESCRIPTION("SCSI debug adapter driver");
3974MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003975MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976
3977MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003978MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09003979MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003980MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003981MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003982MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
3983MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003984MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07003985MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04003986MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003987MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04003988MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003989MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
3990MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
3991MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003992MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003993MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003994MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003995MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3996MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003997MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003998MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004000MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004001MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004002MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004003MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004005MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02004006MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004007MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004008MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004009MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4010MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004011MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4012MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004013MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004014MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4015MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016
4017static char sdebug_info[256];
4018
4019static const char * scsi_debug_info(struct Scsi_Host * shp)
4020{
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004021 sprintf(sdebug_info,
4022 "scsi_debug, version %s [%s], dev_size_mb=%d, opts=0x%x",
4023 SDEBUG_VERSION, sdebug_version_date, sdebug_dev_size_mb,
4024 sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 return sdebug_info;
4026}
4027
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004028/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004029static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4030 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031{
Al Viroc8ed5552013-03-31 01:46:06 -04004032 char arr[16];
4033 int opts;
4034 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035
Al Viroc8ed5552013-03-31 01:46:06 -04004036 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4037 return -EACCES;
4038 memcpy(arr, buffer, minLen);
4039 arr[minLen] = '\0';
4040 if (1 != sscanf(arr, "%d", &opts))
4041 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004042 sdebug_opts = opts;
4043 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4044 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4045 if (sdebug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004046 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04004047 return length;
4048}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004050/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4051 * same for each scsi_debug host (if more than one). Some of the counters
4052 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004053static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4054{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004055 int f, l;
4056 char b[32];
4057
Douglas Gilbert773642d2016-04-25 12:16:28 -04004058 if (sdebug_every_nth > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004059 snprintf(b, sizeof(b), " (curr:%d)",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004060 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004061 atomic_read(&sdebug_a_tsf) :
4062 atomic_read(&sdebug_cmnd_count)));
4063 else
4064 b[0] = '\0';
4065
4066 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
4067 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4068 "every_nth=%d%s\n"
4069 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
4070 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4071 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4072 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4073 "usec_in_jiffy=%lu\n",
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004074 SDEBUG_VERSION, sdebug_version_date,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004075 sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04004076 sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004077 sdebug_max_luns, atomic_read(&sdebug_completions),
4078 sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004079 sdebug_sectors_per, num_aborts, num_dev_resets,
4080 num_target_resets, num_bus_resets, num_host_resets,
4081 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4082
Douglas Gilbert773642d2016-04-25 12:16:28 -04004083 f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4084 if (f != sdebug_max_queue) {
4085 l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004086 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
4087 "queued_in_use_bm", f, l);
4088 }
Al Viroc8ed5552013-03-31 01:46:06 -04004089 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090}
4091
Akinobu Mita82069372013-10-14 22:48:04 +09004092static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004094 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095}
Douglas Gilbertc2206092016-04-25 12:16:31 -04004096/* Returns -EBUSY if jdelay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09004097static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4098 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004100 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004102 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004103 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004104 if (sdebug_jdelay != jdelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004105 unsigned long iflags;
4106 int k;
4107
4108 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004109 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4110 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004111 res = -EBUSY; /* have queued commands */
4112 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004113 /* make sure sdebug_defer instances get
4114 * re-allocated for new delay variant */
4115 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004116 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004117 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004118 }
4119 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004121 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 }
4123 return -EINVAL;
4124}
Akinobu Mita82069372013-10-14 22:48:04 +09004125static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004127static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4128{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004129 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004130}
4131/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004132/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004133static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004134 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004135{
4136 unsigned long iflags;
4137 int ndelay, res, k;
4138
4139 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4140 (ndelay >= 0) && (ndelay < 1000000000)) {
4141 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004142 if (sdebug_ndelay != ndelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004143 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004144 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4145 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004146 res = -EBUSY; /* have queued commands */
4147 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004148 /* make sure sdebug_defer instances get
4149 * re-allocated for new delay variant */
4150 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004151 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004152 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4153 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004154 }
4155 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4156 }
4157 return res;
4158 }
4159 return -EINVAL;
4160}
4161static DRIVER_ATTR_RW(ndelay);
4162
Akinobu Mita82069372013-10-14 22:48:04 +09004163static ssize_t opts_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, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166}
4167
Akinobu Mita82069372013-10-14 22:48:04 +09004168static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4169 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170{
4171 int opts;
4172 char work[20];
4173
4174 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004175 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 if (1 == sscanf(&work[2], "%x", &opts))
4177 goto opts_done;
4178 } else {
4179 if (1 == sscanf(work, "%d", &opts))
4180 goto opts_done;
4181 }
4182 }
4183 return -EINVAL;
4184opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004185 sdebug_opts = opts;
4186 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4187 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004188 atomic_set(&sdebug_cmnd_count, 0);
4189 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 return count;
4191}
Akinobu Mita82069372013-10-14 22:48:04 +09004192static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193
Akinobu Mita82069372013-10-14 22:48:04 +09004194static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004196 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197}
Akinobu Mita82069372013-10-14 22:48:04 +09004198static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4199 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200{
4201 int n;
4202
4203 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004204 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004205 return count;
4206 }
4207 return -EINVAL;
4208}
Akinobu Mita82069372013-10-14 22:48:04 +09004209static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210
Akinobu Mita82069372013-10-14 22:48:04 +09004211static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004213 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214}
Akinobu Mita82069372013-10-14 22:48:04 +09004215static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4216 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218 int n;
4219
4220 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004221 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 return count;
4223 }
4224 return -EINVAL;
4225}
Akinobu Mita82069372013-10-14 22:48:04 +09004226static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227
Akinobu Mita82069372013-10-14 22:48:04 +09004228static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004229{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004230 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004231}
Akinobu Mita82069372013-10-14 22:48:04 +09004232static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4233 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004234{
4235 int n;
4236
4237 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004238 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004239 sdebug_fake_rw = (sdebug_fake_rw > 0);
4240 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004241 if ((0 == n) && (NULL == fake_storep)) {
4242 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004243 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004244 1048576;
4245
4246 fake_storep = vmalloc(sz);
4247 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004248 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004249 return -ENOMEM;
4250 }
4251 memset(fake_storep, 0, sz);
4252 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004253 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004254 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004255 return count;
4256 }
4257 return -EINVAL;
4258}
Akinobu Mita82069372013-10-14 22:48:04 +09004259static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004260
Akinobu Mita82069372013-10-14 22:48:04 +09004261static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004262{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004263 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004264}
Akinobu Mita82069372013-10-14 22:48:04 +09004265static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4266 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004267{
4268 int n;
4269
4270 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004271 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004272 return count;
4273 }
4274 return -EINVAL;
4275}
Akinobu Mita82069372013-10-14 22:48:04 +09004276static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004277
Akinobu Mita82069372013-10-14 22:48:04 +09004278static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004280 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281}
Akinobu Mita82069372013-10-14 22:48:04 +09004282static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4283 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284{
4285 int n;
4286
4287 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004288 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 sdebug_max_tgts_luns();
4290 return count;
4291 }
4292 return -EINVAL;
4293}
Akinobu Mita82069372013-10-14 22:48:04 +09004294static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295
Akinobu Mita82069372013-10-14 22:48:04 +09004296static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004298 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299}
Akinobu Mita82069372013-10-14 22:48:04 +09004300static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301
Akinobu Mita82069372013-10-14 22:48:04 +09004302static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004304 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305}
Akinobu Mita82069372013-10-14 22:48:04 +09004306static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307
Akinobu Mita82069372013-10-14 22:48:04 +09004308static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004310 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311}
Akinobu Mita82069372013-10-14 22:48:04 +09004312static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4313 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314{
4315 int nth;
4316
4317 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004318 sdebug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004319 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 return count;
4321 }
4322 return -EINVAL;
4323}
Akinobu Mita82069372013-10-14 22:48:04 +09004324static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325
Akinobu Mita82069372013-10-14 22:48:04 +09004326static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004328 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329}
Akinobu Mita82069372013-10-14 22:48:04 +09004330static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4331 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332{
4333 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004334 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335
4336 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004337 if (n > 256) {
4338 pr_warn("max_luns can be no more than 256\n");
4339 return -EINVAL;
4340 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004341 changed = (sdebug_max_luns != n);
4342 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004344 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004345 struct sdebug_host_info *sdhp;
4346 struct sdebug_dev_info *dp;
4347
4348 spin_lock(&sdebug_host_list_lock);
4349 list_for_each_entry(sdhp, &sdebug_host_list,
4350 host_list) {
4351 list_for_each_entry(dp, &sdhp->dev_info_list,
4352 dev_list) {
4353 set_bit(SDEBUG_UA_LUNS_CHANGED,
4354 dp->uas_bm);
4355 }
4356 }
4357 spin_unlock(&sdebug_host_list_lock);
4358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 return count;
4360 }
4361 return -EINVAL;
4362}
Akinobu Mita82069372013-10-14 22:48:04 +09004363static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364
Akinobu Mita82069372013-10-14 22:48:04 +09004365static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004366{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004367 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004368}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004369/* N.B. max_queue can be changed while there are queued commands. In flight
4370 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004371static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4372 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004373{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004374 unsigned long iflags;
4375 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004376
4377 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4378 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004379 spin_lock_irqsave(&queued_arr_lock, iflags);
4380 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004381 sdebug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004382 if (SCSI_DEBUG_CANQUEUE == k)
4383 atomic_set(&retired_max_queue, 0);
4384 else if (k >= n)
4385 atomic_set(&retired_max_queue, k + 1);
4386 else
4387 atomic_set(&retired_max_queue, 0);
4388 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004389 return count;
4390 }
4391 return -EINVAL;
4392}
Akinobu Mita82069372013-10-14 22:48:04 +09004393static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004394
Akinobu Mita82069372013-10-14 22:48:04 +09004395static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004396{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004397 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004398}
Akinobu Mita82069372013-10-14 22:48:04 +09004399static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004400
Akinobu Mita82069372013-10-14 22:48:04 +09004401static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004403 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404}
Akinobu Mita82069372013-10-14 22:48:04 +09004405static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406
Akinobu Mita82069372013-10-14 22:48:04 +09004407static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004408{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004409 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004410}
Akinobu Mita82069372013-10-14 22:48:04 +09004411static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4412 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004413{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004414 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004415 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004416
4417 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004418 changed = (sdebug_virtual_gb != n);
4419 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004420 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004421 if (changed) {
4422 struct sdebug_host_info *sdhp;
4423 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004424
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004425 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004426 list_for_each_entry(sdhp, &sdebug_host_list,
4427 host_list) {
4428 list_for_each_entry(dp, &sdhp->dev_info_list,
4429 dev_list) {
4430 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4431 dp->uas_bm);
4432 }
4433 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004434 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004435 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004436 return count;
4437 }
4438 return -EINVAL;
4439}
Akinobu Mita82069372013-10-14 22:48:04 +09004440static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004441
Akinobu Mita82069372013-10-14 22:48:04 +09004442static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004444 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445}
4446
Douglas Gilbertfd321192016-04-25 12:16:33 -04004447static int sdebug_add_adapter(void);
4448static void sdebug_remove_adapter(void);
4449
Akinobu Mita82069372013-10-14 22:48:04 +09004450static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4451 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004453 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004455 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 if (delta_hosts > 0) {
4458 do {
4459 sdebug_add_adapter();
4460 } while (--delta_hosts);
4461 } else if (delta_hosts < 0) {
4462 do {
4463 sdebug_remove_adapter();
4464 } while (++delta_hosts);
4465 }
4466 return count;
4467}
Akinobu Mita82069372013-10-14 22:48:04 +09004468static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469
Akinobu Mita82069372013-10-14 22:48:04 +09004470static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004471{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004472 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004473}
Akinobu Mita82069372013-10-14 22:48:04 +09004474static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4475 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004476{
4477 int n;
4478
4479 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004480 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004481 return count;
4482 }
4483 return -EINVAL;
4484}
Akinobu Mita82069372013-10-14 22:48:04 +09004485static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004486
Akinobu Mita82069372013-10-14 22:48:04 +09004487static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004488{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004489 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004490}
Akinobu Mita82069372013-10-14 22:48:04 +09004491static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004492
Akinobu Mita82069372013-10-14 22:48:04 +09004493static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004494{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004495 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004496}
Akinobu Mita82069372013-10-14 22:48:04 +09004497static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004498
Akinobu Mita82069372013-10-14 22:48:04 +09004499static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004500{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004501 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004502}
Akinobu Mita82069372013-10-14 22:48:04 +09004503static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004504
Akinobu Mita82069372013-10-14 22:48:04 +09004505static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004506{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004507 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004508}
Akinobu Mita82069372013-10-14 22:48:04 +09004509static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004510
Akinobu Mita82069372013-10-14 22:48:04 +09004511static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004512{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004513 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004514}
Akinobu Mita82069372013-10-14 22:48:04 +09004515static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004516
Akinobu Mita82069372013-10-14 22:48:04 +09004517static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004518{
4519 ssize_t count;
4520
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004521 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004522 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4523 sdebug_store_sectors);
4524
Tejun Heoc7badc92015-02-13 14:37:51 -08004525 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4526 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004527 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004528 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004529
4530 return count;
4531}
Akinobu Mita82069372013-10-14 22:48:04 +09004532static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004533
Akinobu Mita82069372013-10-14 22:48:04 +09004534static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004535{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004536 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004537}
Akinobu Mita82069372013-10-14 22:48:04 +09004538static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4539 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004540{
4541 int n;
4542
4543 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004544 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004545 return count;
4546 }
4547 return -EINVAL;
4548}
Akinobu Mita82069372013-10-14 22:48:04 +09004549static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004550
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004551static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4552{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004553 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004554}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004555/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004556static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4557 size_t count)
4558{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004559 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004560
4561 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004562 sdebug_host_lock = (n > 0);
4563 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004564 }
4565 return -EINVAL;
4566}
4567static DRIVER_ATTR_RW(host_lock);
4568
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004569static ssize_t strict_show(struct device_driver *ddp, char *buf)
4570{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004571 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004572}
4573static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4574 size_t count)
4575{
4576 int n;
4577
4578 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004579 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004580 return count;
4581 }
4582 return -EINVAL;
4583}
4584static DRIVER_ATTR_RW(strict);
4585
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004586
Akinobu Mita82069372013-10-14 22:48:04 +09004587/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004588 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4589 files (over those found in the /sys/module/scsi_debug/parameters
4590 directory) is that auxiliary actions can be triggered when an attribute
4591 is changed. For example see: sdebug_add_host_store() above.
4592 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004593
Akinobu Mita82069372013-10-14 22:48:04 +09004594static struct attribute *sdebug_drv_attrs[] = {
4595 &driver_attr_delay.attr,
4596 &driver_attr_opts.attr,
4597 &driver_attr_ptype.attr,
4598 &driver_attr_dsense.attr,
4599 &driver_attr_fake_rw.attr,
4600 &driver_attr_no_lun_0.attr,
4601 &driver_attr_num_tgts.attr,
4602 &driver_attr_dev_size_mb.attr,
4603 &driver_attr_num_parts.attr,
4604 &driver_attr_every_nth.attr,
4605 &driver_attr_max_luns.attr,
4606 &driver_attr_max_queue.attr,
4607 &driver_attr_no_uld.attr,
4608 &driver_attr_scsi_level.attr,
4609 &driver_attr_virtual_gb.attr,
4610 &driver_attr_add_host.attr,
4611 &driver_attr_vpd_use_hostno.attr,
4612 &driver_attr_sector_size.attr,
4613 &driver_attr_dix.attr,
4614 &driver_attr_dif.attr,
4615 &driver_attr_guard.attr,
4616 &driver_attr_ato.attr,
4617 &driver_attr_map.attr,
4618 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004619 &driver_attr_host_lock.attr,
4620 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004621 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004622 NULL,
4623};
4624ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004626static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004627
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628static int __init scsi_debug_init(void)
4629{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004630 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 int host_to_add;
4632 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004633 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004635 atomic_set(&sdebug_cmnd_count, 0);
4636 atomic_set(&sdebug_completions, 0);
4637 atomic_set(&retired_max_queue, 0);
4638
Douglas Gilbert773642d2016-04-25 12:16:28 -04004639 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004640 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004641 sdebug_ndelay = 0;
4642 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04004643 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004644
Douglas Gilbert773642d2016-04-25 12:16:28 -04004645 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004646 case 512:
4647 case 1024:
4648 case 2048:
4649 case 4096:
4650 break;
4651 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004652 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04004653 return -EINVAL;
4654 }
4655
Douglas Gilbert773642d2016-04-25 12:16:28 -04004656 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004657
4658 case SD_DIF_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004659 break;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004660 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004661 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004662 case SD_DIF_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004663 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004664 break;
4665
4666 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004667 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004668 return -EINVAL;
4669 }
4670
Douglas Gilbert773642d2016-04-25 12:16:28 -04004671 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004672 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004673 return -EINVAL;
4674 }
4675
Douglas Gilbert773642d2016-04-25 12:16:28 -04004676 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004677 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004678 return -EINVAL;
4679 }
4680
Douglas Gilbert773642d2016-04-25 12:16:28 -04004681 if (sdebug_physblk_exp > 15) {
4682 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004683 return -EINVAL;
4684 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004685 if (sdebug_max_luns > 256) {
4686 pr_warn("max_luns can be no more than 256, use default\n");
4687 sdebug_max_luns = DEF_MAX_LUNS;
4688 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004689
Douglas Gilbert773642d2016-04-25 12:16:28 -04004690 if (sdebug_lowest_aligned > 0x3fff) {
4691 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004692 return -EINVAL;
4693 }
4694
Douglas Gilbert773642d2016-04-25 12:16:28 -04004695 if (sdebug_dev_size_mb < 1)
4696 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4697 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4698 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004699 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700
4701 /* play around with geometry, don't waste too much on track 0 */
4702 sdebug_heads = 8;
4703 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004704 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004706 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02004707 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4709 (sdebug_sectors_per * sdebug_heads);
4710 if (sdebug_cylinders_per >= 1024) {
4711 /* other LLDs do this; implies >= 1GB ram disk ... */
4712 sdebug_heads = 255;
4713 sdebug_sectors_per = 63;
4714 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4715 (sdebug_sectors_per * sdebug_heads);
4716 }
4717
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004718 if (sdebug_fake_rw == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004719 fake_storep = vmalloc(sz);
4720 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004721 pr_err("out of memory, 1\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004722 return -ENOMEM;
4723 }
4724 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004725 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004726 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728
Douglas Gilbert773642d2016-04-25 12:16:28 -04004729 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004730 int dif_size;
4731
4732 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4733 dif_storep = vmalloc(dif_size);
4734
Tomas Winklerc12879702015-07-28 16:54:20 +03004735 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004736
4737 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004738 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004739 ret = -ENOMEM;
4740 goto free_vm;
4741 }
4742
4743 memset(dif_storep, 0xff, dif_size);
4744 }
4745
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004746 /* Logical Block Provisioning */
4747 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004748 sdebug_unmap_max_blocks =
4749 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004750
Douglas Gilbert773642d2016-04-25 12:16:28 -04004751 sdebug_unmap_max_desc =
4752 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04004753
Douglas Gilbert773642d2016-04-25 12:16:28 -04004754 sdebug_unmap_granularity =
4755 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004756
Douglas Gilbert773642d2016-04-25 12:16:28 -04004757 if (sdebug_unmap_alignment &&
4758 sdebug_unmap_granularity <=
4759 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004760 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004761 return -EINVAL;
4762 }
4763
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004764 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4765 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004766
Tomas Winklerc12879702015-07-28 16:54:20 +03004767 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004768
4769 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004770 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004771 ret = -ENOMEM;
4772 goto free_vm;
4773 }
4774
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004775 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004776
4777 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004778 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004779 map_region(0, 2);
4780 }
4781
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004782 pseudo_primary = root_device_register("pseudo_0");
4783 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004784 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004785 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004786 goto free_vm;
4787 }
4788 ret = bus_register(&pseudo_lld_bus);
4789 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004790 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004791 goto dev_unreg;
4792 }
4793 ret = driver_register(&sdebug_driverfs_driver);
4794 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004795 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004796 goto bus_unreg;
4797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798
Douglas Gilbert773642d2016-04-25 12:16:28 -04004799 host_to_add = sdebug_add_host;
4800 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801
4802 for (k = 0; k < host_to_add; k++) {
4803 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004804 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 break;
4806 }
4807 }
4808
Douglas Gilbert773642d2016-04-25 12:16:28 -04004809 if (sdebug_verbose)
4810 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03004811
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004813
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004814bus_unreg:
4815 bus_unregister(&pseudo_lld_bus);
4816dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004817 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004818free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03004819 vfree(map_storep);
4820 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004821 vfree(fake_storep);
4822
4823 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824}
4825
4826static void __exit scsi_debug_exit(void)
4827{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004828 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829
4830 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004831 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 for (; k; k--)
4833 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 driver_unregister(&sdebug_driverfs_driver);
4835 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004836 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837
Tomas Winklerde232af2015-07-28 16:54:22 +03004838 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 vfree(fake_storep);
4840}
4841
4842device_initcall(scsi_debug_init);
4843module_exit(scsi_debug_exit);
4844
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845static void sdebug_release_adapter(struct device * dev)
4846{
4847 struct sdebug_host_info *sdbg_host;
4848
4849 sdbg_host = to_sdebug_host(dev);
4850 kfree(sdbg_host);
4851}
4852
4853static int sdebug_add_adapter(void)
4854{
4855 int k, devs_per_host;
4856 int error = 0;
4857 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004858 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004860 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004862 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 return -ENOMEM;
4864 }
4865
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4867
Douglas Gilbert773642d2016-04-25 12:16:28 -04004868 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004870 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4871 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004872 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 error = -ENOMEM;
4874 goto clean;
4875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 }
4877
4878 spin_lock(&sdebug_host_list_lock);
4879 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4880 spin_unlock(&sdebug_host_list_lock);
4881
4882 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004883 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004885 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886
4887 error = device_register(&sdbg_host->dev);
4888
4889 if (error)
4890 goto clean;
4891
Douglas Gilbert773642d2016-04-25 12:16:28 -04004892 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 return error;
4894
4895clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004896 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4897 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 list_del(&sdbg_devinfo->dev_list);
4899 kfree(sdbg_devinfo);
4900 }
4901
4902 kfree(sdbg_host);
4903 return error;
4904}
4905
4906static void sdebug_remove_adapter(void)
4907{
4908 struct sdebug_host_info * sdbg_host = NULL;
4909
4910 spin_lock(&sdebug_host_list_lock);
4911 if (!list_empty(&sdebug_host_list)) {
4912 sdbg_host = list_entry(sdebug_host_list.prev,
4913 struct sdebug_host_info, host_list);
4914 list_del(&sdbg_host->host_list);
4915 }
4916 spin_unlock(&sdebug_host_list_lock);
4917
4918 if (!sdbg_host)
4919 return;
4920
Douglas Gilbert773642d2016-04-25 12:16:28 -04004921 device_unregister(&sdbg_host->dev);
4922 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923}
4924
Douglas Gilbertfd321192016-04-25 12:16:33 -04004925static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004926{
4927 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004928 unsigned long iflags;
4929 struct sdebug_dev_info *devip;
4930
4931 spin_lock_irqsave(&queued_arr_lock, iflags);
4932 devip = (struct sdebug_dev_info *)sdev->hostdata;
4933 if (NULL == devip) {
4934 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4935 return -ENODEV;
4936 }
4937 num_in_q = atomic_read(&devip->num_in_q);
4938 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004939
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004940 if (qdepth < 1)
4941 qdepth = 1;
4942 /* allow to exceed max host queued_arr elements for testing */
4943 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4944 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004945 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004946
Douglas Gilbert773642d2016-04-25 12:16:28 -04004947 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004948 sdev_printk(KERN_INFO, sdev,
4949 "%s: qdepth=%d, num_in_q=%d\n",
4950 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004951 }
4952 return sdev->queue_depth;
4953}
4954
Douglas Gilbertfd321192016-04-25 12:16:33 -04004955static int check_inject(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004956{
4957 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4958
4959 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4960
Douglas Gilbert773642d2016-04-25 12:16:28 -04004961 if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
Douglas Gilbert817fd662014-11-24 20:18:02 -05004962 atomic_set(&sdebug_cmnd_count, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004963 if (sdebug_every_nth < -1)
4964 sdebug_every_nth = -1;
4965 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004966 return 1; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004967 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05004968 scsi_medium_access_command(scp))
4969 return 1; /* time out reads and writes */
4970 if (sdebug_any_injecting_opt) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004971 if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004972 ep->inj_recovered = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004973 if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004974 ep->inj_transport = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004975 if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004976 ep->inj_dif = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004977 if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004978 ep->inj_dix = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004979 if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004980 ep->inj_short = true;
4981 }
4982 }
4983 return 0;
4984}
4985
Douglas Gilbertfd321192016-04-25 12:16:33 -04004986static int scsi_debug_queuecommand(struct Scsi_Host *shost,
4987 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004988{
4989 u8 sdeb_i;
4990 struct scsi_device *sdp = scp->device;
4991 const struct opcode_info_t *oip;
4992 const struct opcode_info_t *r_oip;
4993 struct sdebug_dev_info *devip;
4994 u8 *cmd = scp->cmnd;
4995 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
4996 int k, na;
4997 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004998 u32 flags;
4999 u16 sa;
5000 u8 opcode = cmd[0];
5001 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005002
5003 scsi_set_resid(scp, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005004 if (unlikely(sdebug_verbose &&
5005 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005006 char b[120];
5007 int n, len, sb;
5008
5009 len = scp->cmd_len;
5010 sb = (int)sizeof(b);
5011 if (len > 32)
5012 strcpy(b, "too long, over 32 bytes");
5013 else {
5014 for (k = 0, n = 0; k < len && n < sb; ++k)
5015 n += scnprintf(b + n, sb - n, "%02x ",
5016 (u32)cmd[k]);
5017 }
5018 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
5019 }
Tomas Winkler34d55432015-07-28 16:54:21 +03005020 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005021 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5022 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005023
5024 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5025 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5026 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005027 if (unlikely(!devip)) {
5028 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005029 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005030 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005031 }
5032 na = oip->num_attached;
5033 r_pfp = oip->pfp;
5034 if (na) { /* multiple commands with this opcode */
5035 r_oip = oip;
5036 if (FF_SA & r_oip->flags) {
5037 if (F_SA_LOW & oip->flags)
5038 sa = 0x1f & cmd[1];
5039 else
5040 sa = get_unaligned_be16(cmd + 8);
5041 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5042 if (opcode == oip->opcode && sa == oip->sa)
5043 break;
5044 }
5045 } else { /* since no service action only check opcode */
5046 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5047 if (opcode == oip->opcode)
5048 break;
5049 }
5050 }
5051 if (k > na) {
5052 if (F_SA_LOW & r_oip->flags)
5053 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5054 else if (F_SA_HIGH & r_oip->flags)
5055 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5056 else
5057 mk_sense_invalid_opcode(scp);
5058 goto check_cond;
5059 }
5060 } /* else (when na==0) we assume the oip is a match */
5061 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005062 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005063 mk_sense_invalid_opcode(scp);
5064 goto check_cond;
5065 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005066 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005067 if (sdebug_verbose)
5068 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5069 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005070 mk_sense_invalid_opcode(scp);
5071 goto check_cond;
5072 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005073 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005074 u8 rem;
5075 int j;
5076
5077 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5078 rem = ~oip->len_mask[k] & cmd[k];
5079 if (rem) {
5080 for (j = 7; j >= 0; --j, rem <<= 1) {
5081 if (0x80 & rem)
5082 break;
5083 }
5084 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5085 goto check_cond;
5086 }
5087 }
5088 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005089 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005090 find_first_bit(devip->uas_bm,
5091 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005092 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005093 if (errsts)
5094 goto check_cond;
5095 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005096 if (unlikely((F_M_ACCESS & flags) && devip->stopped)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005097 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005098 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005099 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5100 "%s\n", my_name, "initializing command "
5101 "required");
5102 errsts = check_condition_result;
5103 goto fini;
5104 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005105 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005106 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005107 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005108 if (check_inject(scp))
5109 return 0; /* ignore command: make trouble */
5110 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005111 if (likely(oip->pfp))
5112 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005113 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5114 errsts = r_pfp(scp, devip);
5115
5116fini:
5117 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005118 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005119check_cond:
5120 return schedule_resp(scp, devip, check_condition_result, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005121err_out:
5122 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005123}
5124
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005125static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005126 .show_info = scsi_debug_show_info,
5127 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005128 .proc_name = sdebug_proc_name,
5129 .name = "SCSI DEBUG",
5130 .info = scsi_debug_info,
5131 .slave_alloc = scsi_debug_slave_alloc,
5132 .slave_configure = scsi_debug_slave_configure,
5133 .slave_destroy = scsi_debug_slave_destroy,
5134 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005135 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005136 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005137 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005138 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005139 .eh_target_reset_handler = scsi_debug_target_reset,
5140 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005141 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005142 .can_queue = SCSI_DEBUG_CANQUEUE,
5143 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005144 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005145 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005146 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005147 .use_clustering = DISABLE_CLUSTERING,
5148 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005149 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05005150 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005151};
5152
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153static int sdebug_driver_probe(struct device * dev)
5154{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005155 int error = 0;
5156 struct sdebug_host_info *sdbg_host;
5157 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005158 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159
5160 sdbg_host = to_sdebug_host(dev);
5161
Douglas Gilbert773642d2016-04-25 12:16:28 -04005162 sdebug_driver_template.can_queue = sdebug_max_queue;
5163 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005164 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005165 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5166 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005167 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005168 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171
5172 sdbg_host->shost = hpnt;
5173 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005174 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5175 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005177 hpnt->max_id = sdebug_num_tgts;
5178 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005179 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005181 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005182
Douglas Gilbert773642d2016-04-25 12:16:28 -04005183 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005184
5185 case SD_DIF_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005186 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005187 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005188 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005189 break;
5190
5191 case SD_DIF_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005192 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005193 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005194 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005195 break;
5196
5197 case SD_DIF_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005198 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005199 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005200 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005201 break;
5202
5203 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005204 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005205 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005206 break;
5207 }
5208
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005209 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005210
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005211 if (have_dif_prot || sdebug_dix)
5212 pr_info("host protection%s%s%s%s%s%s%s\n",
5213 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5214 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5215 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5216 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5217 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5218 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5219 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005220
Douglas Gilbert773642d2016-04-25 12:16:28 -04005221 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005222 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5223 else
5224 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5225
Douglas Gilbert773642d2016-04-25 12:16:28 -04005226 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5227 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 error = scsi_add_host(hpnt, &sdbg_host->dev);
5229 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005230 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 error = -ENODEV;
5232 scsi_host_put(hpnt);
5233 } else
5234 scsi_scan_host(hpnt);
5235
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005236 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237}
5238
5239static int sdebug_driver_remove(struct device * dev)
5240{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005242 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243
5244 sdbg_host = to_sdebug_host(dev);
5245
5246 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005247 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 return -ENODEV;
5249 }
5250
5251 scsi_remove_host(sdbg_host->shost);
5252
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005253 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5254 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 list_del(&sdbg_devinfo->dev_list);
5256 kfree(sdbg_devinfo);
5257 }
5258
5259 scsi_host_put(sdbg_host->shost);
5260 return 0;
5261}
5262
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005263static int pseudo_lld_bus_match(struct device *dev,
5264 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005266 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005268
5269static struct bus_type pseudo_lld_bus = {
5270 .name = "pseudo",
5271 .match = pseudo_lld_bus_match,
5272 .probe = sdebug_driver_probe,
5273 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005274 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005275};