blob: 6b2d00675ee267584b524cce08f40cf3ab5243fe [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 */
62#define SCSI_DEBUG_VERSION "1.86"
63static const char *sdebug_version_date = "20160422";
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
126#define DEF_PTYPE 0
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 Gilbert773642d2016-04-25 12:16:28 -0400140/* bit mask values for sdebug_opts */
141#define SDEBUG_OPT_NOISE 1
142#define SDEBUG_OPT_MEDIUM_ERR 2
143#define SDEBUG_OPT_TIMEOUT 4
144#define SDEBUG_OPT_RECOVERED_ERR 8
145#define SDEBUG_OPT_TRANSPORT_ERR 16
146#define SDEBUG_OPT_DIF_ERR 32
147#define SDEBUG_OPT_DIX_ERR 64
148#define SDEBUG_OPT_MAC_TIMEOUT 128
149#define SDEBUG_OPT_SHORT_TRANSFER 0x100
150#define SDEBUG_OPT_Q_NOISE 0x200
151#define SDEBUG_OPT_ALL_TSF 0x400
152#define SDEBUG_OPT_RARE_TSF 0x800
153#define SDEBUG_OPT_N_WCE 0x1000
154#define SDEBUG_OPT_RESET_NOISE 0x2000
155#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
156#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
157 SDEBUG_OPT_RESET_NOISE)
158#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
159 SDEBUG_OPT_TRANSPORT_ERR | \
160 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
161 SDEBUG_OPT_SHORT_TRANSFER)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400163 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400165 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500166 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400167 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 *
169 * When "every_nth" < 0 then after "- every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400170 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400172 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500173 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400174 * commands if _DEBUG_OPT_TRANSPORT_ERR is set.
175 * This will continue on every subsequent command until some other action
176 * occurs (e.g. the user * writing a new value (other than -1 or 1) to
177 * every_nth via sysfs).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 */
179
Douglas Gilbertfd321192016-04-25 12:16:33 -0400180/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400181 * priority order. In the subset implemented here lower numbers have higher
182 * priority. The UA numbers should be a sequence starting from 0 with
183 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
184#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
185#define SDEBUG_UA_BUS_RESET 1
186#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500187#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500188#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500189#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
190#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
191#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400192
Douglas Gilbert773642d2016-04-25 12:16:28 -0400193/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 * sector on read commands: */
195#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500196#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
199 * or "peripheral device" addressing (value 0) */
200#define SAM2_LUN_ADDRESS_METHOD 0
201
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400202/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
203 * (for response) at one time. Can be reduced by max_queue option. Command
Douglas Gilbertc2206092016-04-25 12:16:31 -0400204 * responses are not queued when jdelay=0 and ndelay=0. The per-device
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400205 * DEF_CMD_PER_LUN can be changed via sysfs:
206 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
207 * SCSI_DEBUG_CANQUEUE. */
208#define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */
209#define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
210#define DEF_CMD_PER_LUN 255
211
212#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
213#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
214#endif
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400215
Douglas Gilbertfd321192016-04-25 12:16:33 -0400216#define F_D_IN 1
217#define F_D_OUT 2
218#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
219#define F_D_UNKN 8
220#define F_RL_WLUN_OK 0x10
221#define F_SKIP_UA 0x20
222#define F_DELAY_OVERR 0x40
223#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
224#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
225#define F_INV_OP 0x200
226#define F_FAKE_RW 0x400
227#define F_M_ACCESS 0x800 /* media access */
228
229#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
230#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
231#define FF_SA (F_SA_HIGH | F_SA_LOW)
232
233#define SDEBUG_MAX_PARTS 4
234
235#define SCSI_DEBUG_MAX_CMD_LEN 32
236
237
238struct sdebug_dev_info {
239 struct list_head dev_list;
240 unsigned int channel;
241 unsigned int target;
242 u64 lun;
243 struct sdebug_host_info *sdbg_host;
244 unsigned long uas_bm[1];
245 atomic_t num_in_q;
246 char stopped; /* TODO: should be atomic */
247 bool used;
248};
249
250struct sdebug_host_info {
251 struct list_head host_list;
252 struct Scsi_Host *shost;
253 struct device dev;
254 struct list_head dev_info_list;
255};
256
257#define to_sdebug_host(d) \
258 container_of(d, struct sdebug_host_info, dev)
259
260struct sdebug_defer {
261 struct hrtimer hrt;
262 struct execute_work ew;
263 int qa_indx;
264};
265
266struct sdebug_queued_cmd {
267 /* in_use flagged by a bit in queued_in_use_bm[] */
268 struct sdebug_defer *sd_dp;
269 struct scsi_cmnd *a_cmnd;
270};
271
272struct sdebug_scmd_extra_t {
273 bool inj_recovered;
274 bool inj_transport;
275 bool inj_dif;
276 bool inj_dix;
277 bool inj_short;
278};
279
280struct opcode_info_t {
281 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff
282 * for terminating element */
283 u8 opcode; /* if num_attached > 0, preferred */
284 u16 sa; /* service action */
285 u32 flags; /* OR-ed set of SDEB_F_* */
286 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
287 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
288 u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
289 /* ignore cdb bytes after position 15 */
290};
291
292/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500293enum sdeb_opcode_index {
294 SDEB_I_INVALID_OPCODE = 0,
295 SDEB_I_INQUIRY = 1,
296 SDEB_I_REPORT_LUNS = 2,
297 SDEB_I_REQUEST_SENSE = 3,
298 SDEB_I_TEST_UNIT_READY = 4,
299 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
300 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
301 SDEB_I_LOG_SENSE = 7,
302 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
303 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
304 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
305 SDEB_I_START_STOP = 11,
306 SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
307 SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
308 SDEB_I_MAINT_IN = 14,
309 SDEB_I_MAINT_OUT = 15,
310 SDEB_I_VERIFY = 16, /* 10 only */
311 SDEB_I_VARIABLE_LEN = 17,
312 SDEB_I_RESERVE = 18, /* 6, 10 */
313 SDEB_I_RELEASE = 19, /* 6, 10 */
314 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
315 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
316 SDEB_I_ATA_PT = 22, /* 12, 16 */
317 SDEB_I_SEND_DIAG = 23,
318 SDEB_I_UNMAP = 24,
319 SDEB_I_XDWRITEREAD = 25, /* 10 only */
320 SDEB_I_WRITE_BUFFER = 26,
321 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
322 SDEB_I_SYNC_CACHE = 28, /* 10 only */
323 SDEB_I_COMP_WRITE = 29,
324 SDEB_I_LAST_ELEMENT = 30, /* keep this last */
325};
326
327static const unsigned char opcode_ind_arr[256] = {
328/* 0x0; 0x0->0x1f: 6 byte cdbs */
329 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
330 0, 0, 0, 0,
331 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
332 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
333 SDEB_I_RELEASE,
334 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
335 SDEB_I_ALLOW_REMOVAL, 0,
336/* 0x20; 0x20->0x3f: 10 byte cdbs */
337 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
338 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
339 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
340 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
341/* 0x40; 0x40->0x5f: 10 byte cdbs */
342 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
343 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
344 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
345 SDEB_I_RELEASE,
346 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400347/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 0, SDEB_I_VARIABLE_LEN,
351/* 0x80; 0x80->0x9f: 16 byte cdbs */
352 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
353 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
354 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
355 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
356/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
357 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
358 SDEB_I_MAINT_OUT, 0, 0, 0,
359 SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
360 0, 0, 0, 0,
361 0, 0, 0, 0, 0, 0, 0, 0,
362 0, 0, 0, 0, 0, 0, 0, 0,
363/* 0xc0; 0xc0->0xff: vendor specific */
364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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};
369
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500370static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
371static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
372static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
373static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
374static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
375static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
376static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
377static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
378static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
379static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
380static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
381static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
382static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
383static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500384static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
385static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500386static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
387static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
388static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500389static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500390static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500391
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500392static const struct opcode_info_t msense_iarr[1] = {
393 {0, 0x1a, 0, F_D_IN, NULL, NULL,
394 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
395};
396
397static const struct opcode_info_t mselect_iarr[1] = {
398 {0, 0x15, 0, F_D_OUT, NULL, NULL,
399 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
400};
401
402static const struct opcode_info_t read_iarr[3] = {
403 {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
404 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
405 0, 0, 0, 0} },
406 {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
407 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
408 {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
409 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
410 0xc7, 0, 0, 0, 0} },
411};
412
413static const struct opcode_info_t write_iarr[3] = {
414 {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
415 {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
416 0, 0, 0, 0} },
417 {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
418 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
419 {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
420 {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
421 0xc7, 0, 0, 0, 0} },
422};
423
424static const struct opcode_info_t sa_in_iarr[1] = {
425 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
426 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
427 0xff, 0xff, 0xff, 0, 0xc7} },
428};
429
430static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
431 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
432 NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
433 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
434};
435
436static const struct opcode_info_t maint_in_iarr[2] = {
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500437 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500438 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
439 0xc7, 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500440 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500441 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
442 0, 0} },
443};
444
445static const struct opcode_info_t write_same_iarr[1] = {
446 {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
447 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
448 0xff, 0xff, 0xff, 0x1f, 0xc7} },
449};
450
451static const struct opcode_info_t reserve_iarr[1] = {
452 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
453 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
454};
455
456static const struct opcode_info_t release_iarr[1] = {
457 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
458 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
459};
460
461
462/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
463 * plus the terminating elements for logic that scans this table such as
464 * REPORT SUPPORTED OPERATION CODES. */
465static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
466/* 0 */
467 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
468 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
469 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
470 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
471 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
472 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
473 0, 0} },
474 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
475 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
476 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
477 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
478 {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
479 {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
480 0} },
481 {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
482 {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
483 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
484 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
485 0, 0, 0} },
486 {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
487 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
488 0, 0} },
489 {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
490 {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
491 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */
492/* 10 */
493 {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
494 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
495 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */
496 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
497 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
498 {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
499 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
500 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
501 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
502 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
503 {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
504 {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
505 0} },
506 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
507 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500508 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
509 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
510 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500511 {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
512 vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
513 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
514 {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
515 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
516 0} },
517 {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
518 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
519 0} },
520/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500521 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
522 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500523 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
524 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
525 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
526 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
527 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
528 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
529 {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
530 {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
531 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
532 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
533 0, 0, 0, 0, 0, 0} },
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500534 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
535 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
536 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500537 {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
538 write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
539 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
540 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
541 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
542 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500543 {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500544 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
545 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
546
547/* 30 */
548 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
549 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
550};
551
Douglas Gilbert773642d2016-04-25 12:16:28 -0400552static int sdebug_add_host = DEF_NUM_HOST;
553static int sdebug_ato = DEF_ATO;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400554static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400555static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
556static int sdebug_dif = DEF_DIF;
557static int sdebug_dix = DEF_DIX;
558static int sdebug_dsense = DEF_D_SENSE;
559static int sdebug_every_nth = DEF_EVERY_NTH;
560static int sdebug_fake_rw = DEF_FAKE_RW;
561static unsigned int sdebug_guard = DEF_GUARD;
562static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
563static int sdebug_max_luns = DEF_MAX_LUNS;
564static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400565static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400566static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400567static int sdebug_no_lun_0 = DEF_NO_LUN_0;
568static int sdebug_no_uld;
569static int sdebug_num_parts = DEF_NUM_PARTS;
570static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
571static int sdebug_opt_blks = DEF_OPT_BLKS;
572static int sdebug_opts = DEF_OPTS;
573static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
574static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
575static int sdebug_scsi_level = DEF_SCSI_LEVEL;
576static int sdebug_sector_size = DEF_SECTOR_SIZE;
577static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
578static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
579static unsigned int sdebug_lbpu = DEF_LBPU;
580static unsigned int sdebug_lbpws = DEF_LBPWS;
581static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
582static unsigned int sdebug_lbprz = DEF_LBPRZ;
583static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
584static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
585static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
586static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
587static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
588static bool sdebug_removable = DEF_REMOVABLE;
589static bool sdebug_clustering;
590static bool sdebug_host_lock = DEF_HOST_LOCK;
591static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500592static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400593static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400594static bool have_dif_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400596static atomic_t sdebug_cmnd_count;
597static atomic_t sdebug_completions;
598static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400600static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601static sector_t sdebug_capacity; /* in sectors */
602
603/* old BIOS stuff, kernel may get rid of them but some mode sense pages
604 may still need them */
605static int sdebug_heads; /* heads per disk */
606static int sdebug_cylinders_per; /* cylinders per surface */
607static int sdebug_sectors_per; /* sectors per cylinder */
608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609static LIST_HEAD(sdebug_host_list);
610static DEFINE_SPINLOCK(sdebug_host_list_lock);
611
Douglas Gilbertfd321192016-04-25 12:16:33 -0400612static unsigned char *fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900613static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400614static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Martin K. Petersen44d92692009-10-15 14:45:27 -0400616static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400617static int num_aborts;
618static int num_dev_resets;
619static int num_target_resets;
620static int num_bus_resets;
621static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500622static int dix_writes;
623static int dix_reads;
624static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Douglas Gilbertfd321192016-04-25 12:16:33 -0400626static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
627static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629static DEFINE_SPINLOCK(queued_arr_lock);
630static DEFINE_RWLOCK(atomic_rw);
631
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400632static char sdebug_proc_name[] = MY_NAME;
633static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635static struct bus_type pseudo_lld_bus;
636
637static struct device_driver sdebug_driverfs_driver = {
638 .name = sdebug_proc_name,
639 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640};
641
642static const int check_condition_result =
643 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
644
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500645static const int illegal_condition_result =
646 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
647
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400648static const int device_qfull_result =
649 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
650
Douglas Gilbertfd321192016-04-25 12:16:33 -0400651
652static unsigned int scsi_debug_lbp(void)
653{
654 return 0 == sdebug_fake_rw &&
655 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
656}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400657
Akinobu Mita14faa942013-09-18 21:27:24 +0900658static void *fake_store(unsigned long long lba)
659{
660 lba = do_div(lba, sdebug_store_sectors);
661
Douglas Gilbert773642d2016-04-25 12:16:28 -0400662 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900663}
664
665static struct sd_dif_tuple *dif_store(sector_t sector)
666{
Arnd Bergmann49413112015-11-20 17:38:28 +0100667 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900668
669 return dif_storep + sector;
670}
671
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900672static void sdebug_max_tgts_luns(void)
673{
674 struct sdebug_host_info *sdbg_host;
675 struct Scsi_Host *hpnt;
676
677 spin_lock(&sdebug_host_list_lock);
678 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
679 hpnt = sdbg_host->shost;
680 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400681 (sdebug_num_tgts > hpnt->this_id))
682 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900683 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400684 hpnt->max_id = sdebug_num_tgts;
685 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300686 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900687 }
688 spin_unlock(&sdebug_host_list_lock);
689}
690
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500691enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
692
693/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400694static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
695 enum sdeb_cmd_data c_d,
696 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500697{
698 unsigned char *sbuff;
699 u8 sks[4];
700 int sl, asc;
701
702 sbuff = scp->sense_buffer;
703 if (!sbuff) {
704 sdev_printk(KERN_ERR, scp->device,
705 "%s: sense_buffer is NULL\n", __func__);
706 return;
707 }
708 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
709 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400710 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500711 memset(sks, 0, sizeof(sks));
712 sks[0] = 0x80;
713 if (c_d)
714 sks[0] |= 0x40;
715 if (in_bit >= 0) {
716 sks[0] |= 0x8;
717 sks[0] |= 0x7 & in_bit;
718 }
719 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400720 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500721 sl = sbuff[7] + 8;
722 sbuff[7] = sl;
723 sbuff[sl] = 0x2;
724 sbuff[sl + 1] = 0x6;
725 memcpy(sbuff + sl + 4, sks, 3);
726 } else
727 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400728 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500729 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
730 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
731 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
732}
733
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400734static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900735{
736 unsigned char *sbuff;
737
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400738 sbuff = scp->sense_buffer;
739 if (!sbuff) {
740 sdev_printk(KERN_ERR, scp->device,
741 "%s: sense_buffer is NULL\n", __func__);
742 return;
743 }
744 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900745
Douglas Gilbert773642d2016-04-25 12:16:28 -0400746 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900747
Douglas Gilbert773642d2016-04-25 12:16:28 -0400748 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400749 sdev_printk(KERN_INFO, scp->device,
750 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
751 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900752}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Douglas Gilbertfd321192016-04-25 12:16:33 -0400754static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500755{
756 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
757}
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
760{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400761 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400762 if (0x1261 == cmd)
763 sdev_printk(KERN_INFO, dev,
764 "%s: BLKFLSBUF [0x1261]\n", __func__);
765 else if (0x5331 == cmd)
766 sdev_printk(KERN_INFO, dev,
767 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
768 __func__);
769 else
770 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
771 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
773 return -EINVAL;
774 /* return -ENOTTY; // correct return but upsets fdisk */
775}
776
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500777static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
778{
779 struct sdebug_host_info *sdhp;
780 struct sdebug_dev_info *dp;
781
782 spin_lock(&sdebug_host_list_lock);
783 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
784 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
785 if ((devip->sdbg_host == dp->sdbg_host) &&
786 (devip->target == dp->target))
787 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
788 }
789 }
790 spin_unlock(&sdebug_host_list_lock);
791}
792
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400793static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400795 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400796
797 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
798 if (k != SDEBUG_NUM_UAS) {
799 const char *cp = NULL;
800
801 switch (k) {
802 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400803 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
804 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400805 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400806 cp = "power on reset";
807 break;
808 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400809 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
810 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400811 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400812 cp = "bus reset";
813 break;
814 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400815 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
816 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400817 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400818 cp = "mode parameters changed";
819 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500820 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400821 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
822 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400823 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500824 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500825 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500826 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400827 mk_sense_buffer(scp, UNIT_ATTENTION,
828 TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400829 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500830 cp = "microcode has been changed";
831 break;
832 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400833 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500834 TARGET_CHANGED_ASC,
835 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400836 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500837 cp = "microcode has been changed without reset";
838 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500839 case SDEBUG_UA_LUNS_CHANGED:
840 /*
841 * SPC-3 behavior is to report a UNIT ATTENTION with
842 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
843 * on the target, until a REPORT LUNS command is
844 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400845 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500846 * values as struct scsi_device->scsi_level.
847 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400848 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500849 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400850 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500851 TARGET_CHANGED_ASC,
852 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400853 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500854 cp = "reported luns data has changed";
855 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400856 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400857 pr_warn("unexpected unit attention code=%d\n", k);
858 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400859 cp = "unknown";
860 break;
861 }
862 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400863 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400864 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400865 "%s reports: Unit attention: %s\n",
866 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 return check_condition_result;
868 }
869 return 0;
870}
871
872/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900873static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 int arr_len)
875{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900876 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900877 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900879 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900881 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400882 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900883
884 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
885 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700886 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900887
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 return 0;
889}
890
891/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900892static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
893 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900895 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900897 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900899
900 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901}
902
903
904static const char * inq_vendor_id = "Linux ";
905static const char * inq_product_id = "scsi_debug ";
Douglas Gilbert773642d2016-04-25 12:16:28 -0400906static const char *inq_product_rev = "0186"; /* version less '.' */
907static const u64 naa5_comp_a = 0x5222222000000000ULL;
908static const u64 naa5_comp_b = 0x5333333000000000ULL;
909static const u64 naa5_comp_c = 0x5111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400911/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200912static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
913 int target_dev_id, int dev_id_num,
914 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400915 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400917 int num, port_a;
918 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400920 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 /* T10 vendor identifier field format (faked) */
922 arr[0] = 0x2; /* ASCII */
923 arr[1] = 0x1;
924 arr[2] = 0x0;
925 memcpy(&arr[4], inq_vendor_id, 8);
926 memcpy(&arr[12], inq_product_id, 16);
927 memcpy(&arr[28], dev_id_str, dev_id_str_len);
928 num = 8 + 16 + dev_id_str_len;
929 arr[3] = num;
930 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400931 if (dev_id_num >= 0) {
932 /* NAA-5, Logical unit identifier (binary) */
933 arr[num++] = 0x1; /* binary (not necessarily sas) */
934 arr[num++] = 0x3; /* PIV=0, lu, naa */
935 arr[num++] = 0x0;
936 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400937 put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
938 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400939 /* Target relative port number */
940 arr[num++] = 0x61; /* proto=sas, binary */
941 arr[num++] = 0x94; /* PIV=1, target port, rel port */
942 arr[num++] = 0x0; /* reserved */
943 arr[num++] = 0x4; /* length */
944 arr[num++] = 0x0; /* reserved */
945 arr[num++] = 0x0; /* reserved */
946 arr[num++] = 0x0;
947 arr[num++] = 0x1; /* relative port A */
948 }
949 /* NAA-5, Target port identifier */
950 arr[num++] = 0x61; /* proto=sas, binary */
951 arr[num++] = 0x93; /* piv=1, target port, naa */
952 arr[num++] = 0x0;
953 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400954 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
955 num += 8;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200956 /* NAA-5, Target port group identifier */
957 arr[num++] = 0x61; /* proto=sas, binary */
958 arr[num++] = 0x95; /* piv=1, target port group id */
959 arr[num++] = 0x0;
960 arr[num++] = 0x4;
961 arr[num++] = 0;
962 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400963 put_unaligned_be16(port_group_id, arr + num);
964 num += 2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400965 /* NAA-5, Target device identifier */
966 arr[num++] = 0x61; /* proto=sas, binary */
967 arr[num++] = 0xa3; /* piv=1, target device, naa */
968 arr[num++] = 0x0;
969 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400970 put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
971 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400972 /* SCSI name string: Target device identifier */
973 arr[num++] = 0x63; /* proto=sas, UTF-8 */
974 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
975 arr[num++] = 0x0;
976 arr[num++] = 24;
977 memcpy(arr + num, "naa.52222220", 12);
978 num += 12;
979 snprintf(b, sizeof(b), "%08X", target_dev_id);
980 memcpy(arr + num, b, 8);
981 num += 8;
982 memset(arr + num, 0, 4);
983 num += 4;
984 return num;
985}
986
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400987static unsigned char vpd84_data[] = {
988/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
989 0x22,0x22,0x22,0x0,0xbb,0x1,
990 0x22,0x22,0x22,0x0,0xbb,0x2,
991};
992
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400993/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400994static int inquiry_evpd_84(unsigned char * arr)
995{
996 memcpy(arr, vpd84_data, sizeof(vpd84_data));
997 return sizeof(vpd84_data);
998}
999
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001000/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001001static int inquiry_evpd_85(unsigned char * arr)
1002{
1003 int num = 0;
1004 const char * na1 = "https://www.kernel.org/config";
1005 const char * na2 = "http://www.kernel.org/log";
1006 int plen, olen;
1007
1008 arr[num++] = 0x1; /* lu, storage config */
1009 arr[num++] = 0x0; /* reserved */
1010 arr[num++] = 0x0;
1011 olen = strlen(na1);
1012 plen = olen + 1;
1013 if (plen % 4)
1014 plen = ((plen / 4) + 1) * 4;
1015 arr[num++] = plen; /* length, null termianted, padded */
1016 memcpy(arr + num, na1, olen);
1017 memset(arr + num + olen, 0, plen - olen);
1018 num += plen;
1019
1020 arr[num++] = 0x4; /* lu, logging */
1021 arr[num++] = 0x0; /* reserved */
1022 arr[num++] = 0x0;
1023 olen = strlen(na2);
1024 plen = olen + 1;
1025 if (plen % 4)
1026 plen = ((plen / 4) + 1) * 4;
1027 arr[num++] = plen; /* length, null terminated, padded */
1028 memcpy(arr + num, na2, olen);
1029 memset(arr + num + olen, 0, plen - olen);
1030 num += plen;
1031
1032 return num;
1033}
1034
1035/* SCSI ports VPD page */
1036static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1037{
1038 int num = 0;
1039 int port_a, port_b;
1040
1041 port_a = target_dev_id + 1;
1042 port_b = port_a + 1;
1043 arr[num++] = 0x0; /* reserved */
1044 arr[num++] = 0x0; /* reserved */
1045 arr[num++] = 0x0;
1046 arr[num++] = 0x1; /* relative port 1 (primary) */
1047 memset(arr + num, 0, 6);
1048 num += 6;
1049 arr[num++] = 0x0;
1050 arr[num++] = 12; /* length tp descriptor */
1051 /* naa-5 target port identifier (A) */
1052 arr[num++] = 0x61; /* proto=sas, binary */
1053 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1054 arr[num++] = 0x0; /* reserved */
1055 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001056 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1057 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001058 arr[num++] = 0x0; /* reserved */
1059 arr[num++] = 0x0; /* reserved */
1060 arr[num++] = 0x0;
1061 arr[num++] = 0x2; /* relative port 2 (secondary) */
1062 memset(arr + num, 0, 6);
1063 num += 6;
1064 arr[num++] = 0x0;
1065 arr[num++] = 12; /* length tp descriptor */
1066 /* naa-5 target port identifier (B) */
1067 arr[num++] = 0x61; /* proto=sas, binary */
1068 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1069 arr[num++] = 0x0; /* reserved */
1070 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001071 put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1072 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001073
1074 return num;
1075}
1076
1077
1078static unsigned char vpd89_data[] = {
1079/* from 4th byte */ 0,0,0,0,
1080'l','i','n','u','x',' ',' ',' ',
1081'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1082'1','2','3','4',
10830x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
10840xec,0,0,0,
10850x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
10860,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
10870x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
10880x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
10890x53,0x41,
10900x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
10910x20,0x20,
10920x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
10930x10,0x80,
10940,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
10950x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
10960x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
10970,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
10980x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
10990x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11000,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
11010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11020,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11030,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11040x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11050,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11060xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11070,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
11080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11090,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
1120};
1121
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001122/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001123static int inquiry_evpd_89(unsigned char * arr)
1124{
1125 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1126 return sizeof(vpd89_data);
1127}
1128
1129
1130static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001131 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1132 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1133 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1134 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001135};
1136
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001137/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001138static int inquiry_evpd_b0(unsigned char * arr)
1139{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001140 unsigned int gran;
1141
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001142 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001143
1144 /* Optimal transfer length granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001145 gran = 1 << sdebug_physblk_exp;
1146 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001147
1148 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001149 if (sdebug_store_sectors > 0x400)
1150 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001151
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001152 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001153 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001154
Douglas Gilbert773642d2016-04-25 12:16:28 -04001155 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001156 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001157 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001158
1159 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001160 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001161 }
1162
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001163 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001164 if (sdebug_unmap_alignment) {
1165 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001166 arr[28] |= 0x80; /* UGAVALID */
1167 }
1168
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001169 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001170 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001171
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001172 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001173 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001174
1175 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001176
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001177 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178}
1179
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001180/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001181static int inquiry_evpd_b1(unsigned char *arr)
1182{
1183 memset(arr, 0, 0x3c);
1184 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001185 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1186 arr[2] = 0;
1187 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001188
1189 return 0x3c;
1190}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001192/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001193static int inquiry_evpd_b2(unsigned char *arr)
1194{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001195 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001196 arr[0] = 0; /* threshold exponent */
1197
Douglas Gilbert773642d2016-04-25 12:16:28 -04001198 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001199 arr[1] = 1 << 7;
1200
Douglas Gilbert773642d2016-04-25 12:16:28 -04001201 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001202 arr[1] |= 1 << 6;
1203
Douglas Gilbert773642d2016-04-25 12:16:28 -04001204 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001205 arr[1] |= 1 << 5;
1206
Douglas Gilbert773642d2016-04-25 12:16:28 -04001207 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001208 arr[1] |= 1 << 2;
1209
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001210 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001211}
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001214#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001216static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217{
1218 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001219 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001220 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001221 int alloc_len, n, ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001222 bool have_wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
Douglas Gilbert773642d2016-04-25 12:16:28 -04001224 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001225 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1226 if (! arr)
1227 return DID_REQUEUE << 16;
Tomas Winkler34d55432015-07-28 16:54:21 +03001228 have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001229 if (have_wlun)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001230 pq_pdt = 0x1e; /* present, wlun */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001231 else if (sdebug_no_lun_0 && (0 == devip->lun))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001232 pq_pdt = 0x7f; /* not present, no device type */
1233 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001234 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 arr[0] = pq_pdt;
1236 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001237 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001238 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 return check_condition_result;
1240 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001241 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001242 char lu_id_str[6];
1243 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001245 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1246 (devip->channel & 0x7f);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001247 if (0 == sdebug_vpd_use_hostno)
Douglas Gilbert23183912006-09-16 20:30:47 -04001248 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001249 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001250 (devip->target * 1000) + devip->lun);
1251 target_dev_id = ((host_no + 1) * 2000) +
1252 (devip->target * 1000) - 3;
1253 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001255 arr[1] = cmd[2]; /*sanity */
1256 n = 4;
1257 arr[n++] = 0x0; /* this page */
1258 arr[n++] = 0x80; /* unit serial number */
1259 arr[n++] = 0x83; /* device identification */
1260 arr[n++] = 0x84; /* software interface ident. */
1261 arr[n++] = 0x85; /* management network addresses */
1262 arr[n++] = 0x86; /* extended inquiry */
1263 arr[n++] = 0x87; /* mode page policy */
1264 arr[n++] = 0x88; /* SCSI ports */
1265 arr[n++] = 0x89; /* ATA information */
1266 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001267 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001268 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
1269 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001270 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001272 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001274 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001276 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001277 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1278 target_dev_id, lu_id_num,
1279 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001280 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1281 arr[1] = cmd[2]; /*sanity */
1282 arr[3] = inquiry_evpd_84(&arr[4]);
1283 } else if (0x85 == cmd[2]) { /* Management network addresses */
1284 arr[1] = cmd[2]; /*sanity */
1285 arr[3] = inquiry_evpd_85(&arr[4]);
1286 } else if (0x86 == cmd[2]) { /* extended inquiry */
1287 arr[1] = cmd[2]; /*sanity */
1288 arr[3] = 0x3c; /* number of following entries */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001289 if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001290 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001291 else if (sdebug_dif)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001292 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1293 else
1294 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001295 arr[5] = 0x7; /* head of q, ordered + simple q's */
1296 } else if (0x87 == cmd[2]) { /* mode page policy */
1297 arr[1] = cmd[2]; /*sanity */
1298 arr[3] = 0x8; /* number of following entries */
1299 arr[4] = 0x2; /* disconnect-reconnect mp */
1300 arr[6] = 0x80; /* mlus, shared */
1301 arr[8] = 0x18; /* protocol specific lu */
1302 arr[10] = 0x82; /* mlus, per initiator port */
1303 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1304 arr[1] = cmd[2]; /*sanity */
1305 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1306 } else if (0x89 == cmd[2]) { /* ATA information */
1307 arr[1] = cmd[2]; /*sanity */
1308 n = inquiry_evpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001309 put_unaligned_be16(n, arr + 2);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001310 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1311 arr[1] = cmd[2]; /*sanity */
1312 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001313 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1314 arr[1] = cmd[2]; /*sanity */
1315 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001316 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001317 arr[1] = cmd[2]; /*sanity */
1318 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001320 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001321 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 return check_condition_result;
1323 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001324 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001325 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001326 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001327 kfree(arr);
1328 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 }
1330 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001331 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1332 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 arr[3] = 2; /* response_data_format==2 */
1334 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001335 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001336 if (0 == sdebug_vpd_use_hostno)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001337 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001338 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001340 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 memcpy(&arr[8], inq_vendor_id, 8);
1342 memcpy(&arr[16], inq_product_id, 16);
1343 memcpy(&arr[32], inq_product_rev, 4);
1344 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001345 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1346 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001347 n = 62;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001348 if (sdebug_ptype == 0) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001349 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001350 } else if (sdebug_ptype == 1) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001351 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001353 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001354 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001356 kfree(arr);
1357 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358}
1359
Douglas Gilbertfd321192016-04-25 12:16:33 -04001360static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1361 0, 0, 0x0, 0x0};
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363static int resp_requests(struct scsi_cmnd * scp,
1364 struct sdebug_dev_info * devip)
1365{
1366 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001367 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001368 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001369 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 int len = 18;
1371
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001372 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001373 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001374 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001375 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001376 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001377 arr[0] = 0x72;
1378 arr[1] = 0x0; /* NO_SENSE in sense_key */
1379 arr[2] = THRESHOLD_EXCEEDED;
1380 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001381 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001382 } else {
1383 arr[0] = 0x70;
1384 arr[2] = 0x0; /* NO_SENSE in sense_key */
1385 arr[7] = 0xa; /* 18 byte sense buffer */
1386 arr[12] = THRESHOLD_EXCEEDED;
1387 arr[13] = 0xff; /* TEST set and MRIE==6 */
1388 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001389 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001390 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001391 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001392 ; /* have sense and formats match */
1393 else if (arr[0] <= 0x70) {
1394 if (dsense) {
1395 memset(arr, 0, 8);
1396 arr[0] = 0x72;
1397 len = 8;
1398 } else {
1399 memset(arr, 0, 18);
1400 arr[0] = 0x70;
1401 arr[7] = 0xa;
1402 }
1403 } else if (dsense) {
1404 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001405 arr[0] = 0x72;
1406 arr[1] = sbuff[2]; /* sense key */
1407 arr[2] = sbuff[12]; /* asc */
1408 arr[3] = sbuff[13]; /* ascq */
1409 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001410 } else {
1411 memset(arr, 0, 18);
1412 arr[0] = 0x70;
1413 arr[2] = sbuff[1];
1414 arr[7] = 0xa;
1415 arr[12] = sbuff[1];
1416 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001417 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001418
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001419 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001420 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 return fill_from_dev_buffer(scp, arr, len);
1422}
1423
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001424static int resp_start_stop(struct scsi_cmnd * scp,
1425 struct sdebug_dev_info * devip)
1426{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001427 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001428 int power_cond, start;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001429
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001430 power_cond = (cmd[4] & 0xf0) >> 4;
1431 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001432 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001433 return check_condition_result;
1434 }
1435 start = cmd[4] & 1;
1436 if (start == devip->stopped)
1437 devip->stopped = !start;
1438 return 0;
1439}
1440
FUJITA Tomonori28898872008-03-30 00:59:55 +09001441static sector_t get_sdebug_capacity(void)
1442{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001443 static const unsigned int gibibyte = 1073741824;
1444
1445 if (sdebug_virtual_gb > 0)
1446 return (sector_t)sdebug_virtual_gb *
1447 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001448 else
1449 return sdebug_store_sectors;
1450}
1451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452#define SDEBUG_READCAP_ARR_SZ 8
1453static int resp_readcap(struct scsi_cmnd * scp,
1454 struct sdebug_dev_info * devip)
1455{
1456 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001457 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001459 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001460 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462 if (sdebug_capacity < 0xffffffff) {
1463 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001464 put_unaligned_be32(capac, arr + 0);
1465 } else
1466 put_unaligned_be32(0xffffffff, arr + 0);
1467 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1469}
1470
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001471#define SDEBUG_READCAP16_ARR_SZ 32
1472static int resp_readcap16(struct scsi_cmnd * scp,
1473 struct sdebug_dev_info * devip)
1474{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001475 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001476 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001477 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001478
Douglas Gilbert773642d2016-04-25 12:16:28 -04001479 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001480 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001481 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001482 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001483 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1484 put_unaligned_be32(sdebug_sector_size, arr + 8);
1485 arr[13] = sdebug_physblk_exp & 0xf;
1486 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001487
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001488 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001489 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001490 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001491 arr[14] |= 0x40; /* LBPRZ */
1492 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001493
Douglas Gilbert773642d2016-04-25 12:16:28 -04001494 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001495
Douglas Gilbert773642d2016-04-25 12:16:28 -04001496 if (sdebug_dif) {
1497 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001498 arr[12] |= 1; /* PROT_EN */
1499 }
1500
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001501 return fill_from_dev_buffer(scp, arr,
1502 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1503}
1504
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001505#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1506
1507static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1508 struct sdebug_dev_info * devip)
1509{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001510 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001511 unsigned char * arr;
1512 int host_no = devip->sdbg_host->shost->host_no;
1513 int n, ret, alen, rlen;
1514 int port_group_a, port_group_b, port_a, port_b;
1515
Douglas Gilbert773642d2016-04-25 12:16:28 -04001516 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001517 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1518 if (! arr)
1519 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001520 /*
1521 * EVPD page 0x88 states we have two ports, one
1522 * real and a fake port with no device connected.
1523 * So we create two port groups with one port each
1524 * and set the group with port B to unavailable.
1525 */
1526 port_a = 0x1; /* relative port A */
1527 port_b = 0x2; /* relative port B */
1528 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001529 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001530 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001531 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001532
1533 /*
1534 * The asymmetric access state is cycled according to the host_id.
1535 */
1536 n = 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001537 if (0 == sdebug_vpd_use_hostno) {
1538 arr[n++] = host_no % 3; /* Asymm access state */
1539 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001540 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001541 arr[n++] = 0x0; /* Active/Optimized path */
1542 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001543 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001544 put_unaligned_be16(port_group_a, arr + n);
1545 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001546 arr[n++] = 0; /* Reserved */
1547 arr[n++] = 0; /* Status code */
1548 arr[n++] = 0; /* Vendor unique */
1549 arr[n++] = 0x1; /* One port per group */
1550 arr[n++] = 0; /* Reserved */
1551 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001552 put_unaligned_be16(port_a, arr + n);
1553 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001554 arr[n++] = 3; /* Port unavailable */
1555 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001556 put_unaligned_be16(port_group_b, arr + n);
1557 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001558 arr[n++] = 0; /* Reserved */
1559 arr[n++] = 0; /* Status code */
1560 arr[n++] = 0; /* Vendor unique */
1561 arr[n++] = 0x1; /* One port per group */
1562 arr[n++] = 0; /* Reserved */
1563 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001564 put_unaligned_be16(port_b, arr + n);
1565 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001566
1567 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001568 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001569
1570 /*
1571 * Return the smallest value of either
1572 * - The allocated length
1573 * - The constructed command length
1574 * - The maximum array size
1575 */
1576 rlen = min(alen,n);
1577 ret = fill_from_dev_buffer(scp, arr,
1578 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1579 kfree(arr);
1580 return ret;
1581}
1582
Douglas Gilbertfd321192016-04-25 12:16:33 -04001583static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1584 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001585{
1586 bool rctd;
1587 u8 reporting_opts, req_opcode, sdeb_i, supp;
1588 u16 req_sa, u;
1589 u32 alloc_len, a_len;
1590 int k, offset, len, errsts, count, bump, na;
1591 const struct opcode_info_t *oip;
1592 const struct opcode_info_t *r_oip;
1593 u8 *arr;
1594 u8 *cmd = scp->cmnd;
1595
1596 rctd = !!(cmd[2] & 0x80);
1597 reporting_opts = cmd[2] & 0x7;
1598 req_opcode = cmd[3];
1599 req_sa = get_unaligned_be16(cmd + 4);
1600 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001601 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001602 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1603 return check_condition_result;
1604 }
1605 if (alloc_len > 8192)
1606 a_len = 8192;
1607 else
1608 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001609 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001610 if (NULL == arr) {
1611 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1612 INSUFF_RES_ASCQ);
1613 return check_condition_result;
1614 }
1615 switch (reporting_opts) {
1616 case 0: /* all commands */
1617 /* count number of commands */
1618 for (count = 0, oip = opcode_info_arr;
1619 oip->num_attached != 0xff; ++oip) {
1620 if (F_INV_OP & oip->flags)
1621 continue;
1622 count += (oip->num_attached + 1);
1623 }
1624 bump = rctd ? 20 : 8;
1625 put_unaligned_be32(count * bump, arr);
1626 for (offset = 4, oip = opcode_info_arr;
1627 oip->num_attached != 0xff && offset < a_len; ++oip) {
1628 if (F_INV_OP & oip->flags)
1629 continue;
1630 na = oip->num_attached;
1631 arr[offset] = oip->opcode;
1632 put_unaligned_be16(oip->sa, arr + offset + 2);
1633 if (rctd)
1634 arr[offset + 5] |= 0x2;
1635 if (FF_SA & oip->flags)
1636 arr[offset + 5] |= 0x1;
1637 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1638 if (rctd)
1639 put_unaligned_be16(0xa, arr + offset + 8);
1640 r_oip = oip;
1641 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1642 if (F_INV_OP & oip->flags)
1643 continue;
1644 offset += bump;
1645 arr[offset] = oip->opcode;
1646 put_unaligned_be16(oip->sa, arr + offset + 2);
1647 if (rctd)
1648 arr[offset + 5] |= 0x2;
1649 if (FF_SA & oip->flags)
1650 arr[offset + 5] |= 0x1;
1651 put_unaligned_be16(oip->len_mask[0],
1652 arr + offset + 6);
1653 if (rctd)
1654 put_unaligned_be16(0xa,
1655 arr + offset + 8);
1656 }
1657 oip = r_oip;
1658 offset += bump;
1659 }
1660 break;
1661 case 1: /* one command: opcode only */
1662 case 2: /* one command: opcode plus service action */
1663 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1664 sdeb_i = opcode_ind_arr[req_opcode];
1665 oip = &opcode_info_arr[sdeb_i];
1666 if (F_INV_OP & oip->flags) {
1667 supp = 1;
1668 offset = 4;
1669 } else {
1670 if (1 == reporting_opts) {
1671 if (FF_SA & oip->flags) {
1672 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1673 2, 2);
1674 kfree(arr);
1675 return check_condition_result;
1676 }
1677 req_sa = 0;
1678 } else if (2 == reporting_opts &&
1679 0 == (FF_SA & oip->flags)) {
1680 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1681 kfree(arr); /* point at requested sa */
1682 return check_condition_result;
1683 }
1684 if (0 == (FF_SA & oip->flags) &&
1685 req_opcode == oip->opcode)
1686 supp = 3;
1687 else if (0 == (FF_SA & oip->flags)) {
1688 na = oip->num_attached;
1689 for (k = 0, oip = oip->arrp; k < na;
1690 ++k, ++oip) {
1691 if (req_opcode == oip->opcode)
1692 break;
1693 }
1694 supp = (k >= na) ? 1 : 3;
1695 } else if (req_sa != oip->sa) {
1696 na = oip->num_attached;
1697 for (k = 0, oip = oip->arrp; k < na;
1698 ++k, ++oip) {
1699 if (req_sa == oip->sa)
1700 break;
1701 }
1702 supp = (k >= na) ? 1 : 3;
1703 } else
1704 supp = 3;
1705 if (3 == supp) {
1706 u = oip->len_mask[0];
1707 put_unaligned_be16(u, arr + 2);
1708 arr[4] = oip->opcode;
1709 for (k = 1; k < u; ++k)
1710 arr[4 + k] = (k < 16) ?
1711 oip->len_mask[k] : 0xff;
1712 offset = 4 + u;
1713 } else
1714 offset = 4;
1715 }
1716 arr[1] = (rctd ? 0x80 : 0) | supp;
1717 if (rctd) {
1718 put_unaligned_be16(0xa, arr + offset);
1719 offset += 12;
1720 }
1721 break;
1722 default:
1723 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1724 kfree(arr);
1725 return check_condition_result;
1726 }
1727 offset = (offset < a_len) ? offset : a_len;
1728 len = (offset < alloc_len) ? offset : alloc_len;
1729 errsts = fill_from_dev_buffer(scp, arr, len);
1730 kfree(arr);
1731 return errsts;
1732}
1733
Douglas Gilbertfd321192016-04-25 12:16:33 -04001734static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1735 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001736{
1737 bool repd;
1738 u32 alloc_len, len;
1739 u8 arr[16];
1740 u8 *cmd = scp->cmnd;
1741
1742 memset(arr, 0, sizeof(arr));
1743 repd = !!(cmd[2] & 0x80);
1744 alloc_len = get_unaligned_be32(cmd + 6);
1745 if (alloc_len < 4) {
1746 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1747 return check_condition_result;
1748 }
1749 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1750 arr[1] = 0x1; /* ITNRS */
1751 if (repd) {
1752 arr[3] = 0xc;
1753 len = 16;
1754 } else
1755 len = 4;
1756
1757 len = (len < alloc_len) ? len : alloc_len;
1758 return fill_from_dev_buffer(scp, arr, len);
1759}
1760
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761/* <<Following mode page info copied from ST318451LW>> */
1762
1763static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1764{ /* Read-Write Error Recovery page for mode_sense */
1765 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1766 5, 0, 0xff, 0xff};
1767
1768 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1769 if (1 == pcontrol)
1770 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1771 return sizeof(err_recov_pg);
1772}
1773
1774static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1775{ /* Disconnect-Reconnect page for mode_sense */
1776 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1777 0, 0, 0, 0, 0, 0, 0, 0};
1778
1779 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1780 if (1 == pcontrol)
1781 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1782 return sizeof(disconnect_pg);
1783}
1784
1785static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1786{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001787 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1788 0, 0, 0, 0, 0, 0, 0, 0,
1789 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Martin K. Petersen597136a2008-06-05 00:12:59 -04001791 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001792 put_unaligned_be16(sdebug_sectors_per, p + 10);
1793 put_unaligned_be16(sdebug_sector_size, p + 12);
1794 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001795 p[20] |= 0x20; /* should agree with INQUIRY */
1796 if (1 == pcontrol)
1797 memset(p + 2, 0, sizeof(format_pg) - 2);
1798 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799}
1800
Douglas Gilbertfd321192016-04-25 12:16:33 -04001801static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1802 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1803 0, 0, 0, 0};
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1806{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001807 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1808 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1809 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1811
Douglas Gilbert773642d2016-04-25 12:16:28 -04001812 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001813 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 memcpy(p, caching_pg, sizeof(caching_pg));
1815 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001816 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1817 else if (2 == pcontrol)
1818 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 return sizeof(caching_pg);
1820}
1821
Douglas Gilbertfd321192016-04-25 12:16:33 -04001822static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1823 0, 0, 0x2, 0x4b};
1824
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1826{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001827 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1828 0, 0, 0, 0};
1829 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 0, 0, 0x2, 0x4b};
1831
Douglas Gilbert773642d2016-04-25 12:16:28 -04001832 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001834 else
1835 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001836
Douglas Gilbert773642d2016-04-25 12:16:28 -04001837 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001838 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1841 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001842 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1843 else if (2 == pcontrol)
1844 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 return sizeof(ctrl_m_pg);
1846}
1847
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1850{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001851 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1852 0, 0, 0x0, 0x0};
1853 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1854 0, 0, 0x0, 0x0};
1855
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1857 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001858 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1859 else if (2 == pcontrol)
1860 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 return sizeof(iec_m_pg);
1862}
1863
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001864static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1865{ /* SAS SSP mode page - short format for mode_sense */
1866 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1867 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1868
1869 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1870 if (1 == pcontrol)
1871 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1872 return sizeof(sas_sf_m_pg);
1873}
1874
1875
1876static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1877 int target_dev_id)
1878{ /* SAS phy control and discover mode page for mode_sense */
1879 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1880 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001881 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1882 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001883 0x2, 0, 0, 0, 0, 0, 0, 0,
1884 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1885 0, 0, 0, 0, 0, 0, 0, 0,
1886 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001887 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1888 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001889 0x3, 0, 0, 0, 0, 0, 0, 0,
1890 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1891 0, 0, 0, 0, 0, 0, 0, 0,
1892 };
1893 int port_a, port_b;
1894
Douglas Gilbert773642d2016-04-25 12:16:28 -04001895 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1896 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1897 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1898 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001899 port_a = target_dev_id + 1;
1900 port_b = port_a + 1;
1901 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001902 put_unaligned_be32(port_a, p + 20);
1903 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001904 if (1 == pcontrol)
1905 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1906 return sizeof(sas_pcd_m_pg);
1907}
1908
1909static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1910{ /* SAS SSP shared protocol specific port mode subpage */
1911 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1912 0, 0, 0, 0, 0, 0, 0, 0,
1913 };
1914
1915 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1916 if (1 == pcontrol)
1917 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1918 return sizeof(sas_sha_m_pg);
1919}
1920
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921#define SDEBUG_MAX_MSENSE_SZ 256
1922
Douglas Gilbertfd321192016-04-25 12:16:33 -04001923static int resp_mode_sense(struct scsi_cmnd *scp,
1924 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925{
Douglas Gilbert23183912006-09-16 20:30:47 -04001926 unsigned char dbd, llbaa;
1927 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 unsigned char dev_spec;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001929 int alloc_len, msense_6, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001930 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 unsigned char * ap;
1932 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001933 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
Douglas Gilbert23183912006-09-16 20:30:47 -04001935 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 pcontrol = (cmd[2] & 0xc0) >> 6;
1937 pcode = cmd[2] & 0x3f;
1938 subpcode = cmd[3];
1939 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001940 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001941 if ((0 == sdebug_ptype) && (0 == dbd))
Douglas Gilbert23183912006-09-16 20:30:47 -04001942 bd_len = llbaa ? 16 : 8;
1943 else
1944 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001945 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1947 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001948 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 return check_condition_result;
1950 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001951 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1952 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001953 /* set DPOFUA bit for disks */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001954 if (0 == sdebug_ptype)
Douglas Gilbertfd321192016-04-25 12:16:33 -04001955 dev_spec = 0x10; /* would be 0x90 if read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04001956 else
1957 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 if (msense_6) {
1959 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001960 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 offset = 4;
1962 } else {
1963 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001964 if (16 == bd_len)
1965 arr[4] = 0x1; /* set LONGLBA bit */
1966 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 offset = 8;
1968 }
1969 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001970 if ((bd_len > 0) && (!sdebug_capacity))
1971 sdebug_capacity = get_sdebug_capacity();
1972
Douglas Gilbert23183912006-09-16 20:30:47 -04001973 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001974 if (sdebug_capacity > 0xfffffffe)
1975 put_unaligned_be32(0xffffffff, ap + 0);
1976 else
1977 put_unaligned_be32(sdebug_capacity, ap + 0);
1978 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04001979 offset += bd_len;
1980 ap = arr + offset;
1981 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001982 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
1983 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04001984 offset += bd_len;
1985 ap = arr + offset;
1986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001988 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1989 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001990 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 return check_condition_result;
1992 }
1993 switch (pcode) {
1994 case 0x1: /* Read-Write error recovery page, direct access */
1995 len = resp_err_recov_pg(ap, pcontrol, target);
1996 offset += len;
1997 break;
1998 case 0x2: /* Disconnect-Reconnect page, all devices */
1999 len = resp_disconnect_pg(ap, pcontrol, target);
2000 offset += len;
2001 break;
2002 case 0x3: /* Format device page, direct access */
2003 len = resp_format_pg(ap, pcontrol, target);
2004 offset += len;
2005 break;
2006 case 0x8: /* Caching page, direct access */
2007 len = resp_caching_pg(ap, pcontrol, target);
2008 offset += len;
2009 break;
2010 case 0xa: /* Control Mode page, all devices */
2011 len = resp_ctrl_m_pg(ap, pcontrol, target);
2012 offset += len;
2013 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002014 case 0x19: /* if spc==1 then sas phy, control+discover */
2015 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002016 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002017 return check_condition_result;
2018 }
2019 len = 0;
2020 if ((0x0 == subpcode) || (0xff == subpcode))
2021 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2022 if ((0x1 == subpcode) || (0xff == subpcode))
2023 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2024 target_dev_id);
2025 if ((0x2 == subpcode) || (0xff == subpcode))
2026 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2027 offset += len;
2028 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 case 0x1c: /* Informational Exceptions Mode page, all devices */
2030 len = resp_iec_m_pg(ap, pcontrol, target);
2031 offset += len;
2032 break;
2033 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002034 if ((0 == subpcode) || (0xff == subpcode)) {
2035 len = resp_err_recov_pg(ap, pcontrol, target);
2036 len += resp_disconnect_pg(ap + len, pcontrol, target);
2037 len += resp_format_pg(ap + len, pcontrol, target);
2038 len += resp_caching_pg(ap + len, pcontrol, target);
2039 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2040 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2041 if (0xff == subpcode) {
2042 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2043 target, target_dev_id);
2044 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2045 }
2046 len += resp_iec_m_pg(ap + len, pcontrol, target);
2047 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002048 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002049 return check_condition_result;
2050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 offset += len;
2052 break;
2053 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002054 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 return check_condition_result;
2056 }
2057 if (msense_6)
2058 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002059 else
2060 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2062}
2063
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002064#define SDEBUG_MAX_MSELECT_SZ 512
2065
Douglas Gilbertfd321192016-04-25 12:16:33 -04002066static int resp_mode_select(struct scsi_cmnd *scp,
2067 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002068{
2069 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002070 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002071 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002072 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002073 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002074
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002075 memset(arr, 0, sizeof(arr));
2076 pf = cmd[1] & 0x10;
2077 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002078 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002079 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002080 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002081 return check_condition_result;
2082 }
2083 res = fetch_to_dev_buffer(scp, arr, param_len);
2084 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002085 return DID_ERROR << 16;
2086 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002087 sdev_printk(KERN_INFO, scp->device,
2088 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2089 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002090 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2091 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002092 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002093 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002094 return check_condition_result;
2095 }
2096 off = bd_len + (mselect6 ? 4 : 8);
2097 mpage = arr[off] & 0x3f;
2098 ps = !!(arr[off] & 0x80);
2099 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002100 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002101 return check_condition_result;
2102 }
2103 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002104 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002105 (arr[off + 1] + 2);
2106 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002107 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002108 PARAMETER_LIST_LENGTH_ERR, 0);
2109 return check_condition_result;
2110 }
2111 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002112 case 0x8: /* Caching Mode page */
2113 if (caching_pg[1] == arr[off + 1]) {
2114 memcpy(caching_pg + 2, arr + off + 2,
2115 sizeof(caching_pg) - 2);
2116 goto set_mode_changed_ua;
2117 }
2118 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002119 case 0xa: /* Control Mode page */
2120 if (ctrl_m_pg[1] == arr[off + 1]) {
2121 memcpy(ctrl_m_pg + 2, arr + off + 2,
2122 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002123 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002124 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002125 }
2126 break;
2127 case 0x1c: /* Informational Exceptions Mode page */
2128 if (iec_m_pg[1] == arr[off + 1]) {
2129 memcpy(iec_m_pg + 2, arr + off + 2,
2130 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002131 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002132 }
2133 break;
2134 default:
2135 break;
2136 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002137 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002138 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002139set_mode_changed_ua:
2140 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2141 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002142}
2143
2144static int resp_temp_l_pg(unsigned char * arr)
2145{
2146 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2147 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2148 };
2149
2150 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2151 return sizeof(temp_l_pg);
2152}
2153
2154static int resp_ie_l_pg(unsigned char * arr)
2155{
2156 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2157 };
2158
2159 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2160 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2161 arr[4] = THRESHOLD_EXCEEDED;
2162 arr[5] = 0xff;
2163 }
2164 return sizeof(ie_l_pg);
2165}
2166
2167#define SDEBUG_MAX_LSENSE_SZ 512
2168
2169static int resp_log_sense(struct scsi_cmnd * scp,
2170 struct sdebug_dev_info * devip)
2171{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002172 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002173 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002174 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002175
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002176 memset(arr, 0, sizeof(arr));
2177 ppc = cmd[1] & 0x2;
2178 sp = cmd[1] & 0x1;
2179 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002180 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002181 return check_condition_result;
2182 }
2183 pcontrol = (cmd[2] & 0xc0) >> 6;
2184 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002185 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002186 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002187 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002188 if (0 == subpcode) {
2189 switch (pcode) {
2190 case 0x0: /* Supported log pages log page */
2191 n = 4;
2192 arr[n++] = 0x0; /* this page */
2193 arr[n++] = 0xd; /* Temperature */
2194 arr[n++] = 0x2f; /* Informational exceptions */
2195 arr[3] = n - 4;
2196 break;
2197 case 0xd: /* Temperature log page */
2198 arr[3] = resp_temp_l_pg(arr + 4);
2199 break;
2200 case 0x2f: /* Informational exceptions log page */
2201 arr[3] = resp_ie_l_pg(arr + 4);
2202 break;
2203 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002204 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002205 return check_condition_result;
2206 }
2207 } else if (0xff == subpcode) {
2208 arr[0] |= 0x40;
2209 arr[1] = subpcode;
2210 switch (pcode) {
2211 case 0x0: /* Supported log pages and subpages log page */
2212 n = 4;
2213 arr[n++] = 0x0;
2214 arr[n++] = 0x0; /* 0,0 page */
2215 arr[n++] = 0x0;
2216 arr[n++] = 0xff; /* this page */
2217 arr[n++] = 0xd;
2218 arr[n++] = 0x0; /* Temperature */
2219 arr[n++] = 0x2f;
2220 arr[n++] = 0x0; /* Informational exceptions */
2221 arr[3] = n - 4;
2222 break;
2223 case 0xd: /* Temperature subpages */
2224 n = 4;
2225 arr[n++] = 0xd;
2226 arr[n++] = 0x0; /* Temperature */
2227 arr[3] = n - 4;
2228 break;
2229 case 0x2f: /* Informational exceptions subpages */
2230 n = 4;
2231 arr[n++] = 0x2f;
2232 arr[n++] = 0x0; /* Informational exceptions */
2233 arr[3] = n - 4;
2234 break;
2235 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002236 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002237 return check_condition_result;
2238 }
2239 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002240 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002241 return check_condition_result;
2242 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002243 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002244 return fill_from_dev_buffer(scp, arr,
2245 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2246}
2247
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002248static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002249 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002251 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002252 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 return check_condition_result;
2254 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002255 /* transfer length excessive (tie in to block limits VPD page) */
2256 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002257 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002258 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002259 return check_condition_result;
2260 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002261 return 0;
2262}
2263
Akinobu Mitaa4517512013-07-08 16:01:57 -07002264/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002265static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2266 bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002267{
2268 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002269 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002270 struct scsi_data_buffer *sdb;
2271 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002272
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002273 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002274 sdb = scsi_out(scmd);
2275 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002276 } else {
2277 sdb = scsi_in(scmd);
2278 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002279 }
2280
2281 if (!sdb->length)
2282 return 0;
2283 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2284 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002285
2286 block = do_div(lba, sdebug_store_sectors);
2287 if (block + num > sdebug_store_sectors)
2288 rest = block + num - sdebug_store_sectors;
2289
Dave Gordon386ecb12015-06-30 14:58:57 -07002290 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002291 fake_storep + (block * sdebug_sector_size),
2292 (num - rest) * sdebug_sector_size, 0, do_write);
2293 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002294 return ret;
2295
2296 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002297 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002298 fake_storep, rest * sdebug_sector_size,
2299 (num - rest) * sdebug_sector_size, do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002300 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002301
2302 return ret;
2303}
2304
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002305/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2306 * arr into fake_store(lba,num) and return true. If comparison fails then
2307 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002308static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002309{
2310 bool res;
2311 u64 block, rest = 0;
2312 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002313 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002314
2315 block = do_div(lba, store_blks);
2316 if (block + num > store_blks)
2317 rest = block + num - store_blks;
2318
2319 res = !memcmp(fake_storep + (block * lb_size), arr,
2320 (num - rest) * lb_size);
2321 if (!res)
2322 return res;
2323 if (rest)
2324 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2325 rest * lb_size);
2326 if (!res)
2327 return res;
2328 arr += num * lb_size;
2329 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2330 if (rest)
2331 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2332 rest * lb_size);
2333 return res;
2334}
2335
Akinobu Mita51d648a2013-09-18 21:27:28 +09002336static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002337{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002338 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002339
Douglas Gilbert773642d2016-04-25 12:16:28 -04002340 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002341 csum = (__force __be16)ip_compute_csum(buf, len);
2342 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002343 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002344
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002345 return csum;
2346}
2347
2348static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2349 sector_t sector, u32 ei_lba)
2350{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002351 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002352
2353 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002354 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002355 (unsigned long)sector,
2356 be16_to_cpu(sdt->guard_tag),
2357 be16_to_cpu(csum));
2358 return 0x01;
2359 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002360 if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002361 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002362 pr_err("REF check failed on sector %lu\n",
2363 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002364 return 0x03;
2365 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002366 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002367 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002368 pr_err("REF check failed on sector %lu\n",
2369 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002370 return 0x03;
2371 }
2372 return 0;
2373}
2374
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002375static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002376 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002377{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002378 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002379 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002380 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002381 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002382
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002383 /* Bytes of protection data to copy into sgl */
2384 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002385
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002386 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2387 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2388 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2389
2390 while (sg_miter_next(&miter) && resid > 0) {
2391 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002392 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002393 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002394
2395 if (dif_store_end < start + len)
2396 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002397
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002398 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002399
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002400 if (read)
2401 memcpy(paddr, start, len - rest);
2402 else
2403 memcpy(start, paddr, len - rest);
2404
2405 if (rest) {
2406 if (read)
2407 memcpy(paddr + len - rest, dif_storep, rest);
2408 else
2409 memcpy(dif_storep, paddr + len - rest, rest);
2410 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002411
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002412 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002413 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002414 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002415 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002416}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002417
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002418static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2419 unsigned int sectors, u32 ei_lba)
2420{
2421 unsigned int i;
2422 struct sd_dif_tuple *sdt;
2423 sector_t sector;
2424
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002425 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002426 int ret;
2427
2428 sector = start_sec + i;
2429 sdt = dif_store(sector);
2430
Akinobu Mita51d648a2013-09-18 21:27:28 +09002431 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002432 continue;
2433
2434 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2435 if (ret) {
2436 dif_errors++;
2437 return ret;
2438 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002439 }
2440
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002441 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002442 dix_reads++;
2443
2444 return 0;
2445}
2446
Douglas Gilbertfd321192016-04-25 12:16:33 -04002447static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002448{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002449 u8 *cmd = scp->cmnd;
2450 u64 lba;
2451 u32 num;
2452 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002453 unsigned long iflags;
2454 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002455 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002456
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002457 switch (cmd[0]) {
2458 case READ_16:
2459 ei_lba = 0;
2460 lba = get_unaligned_be64(cmd + 2);
2461 num = get_unaligned_be32(cmd + 10);
2462 check_prot = true;
2463 break;
2464 case READ_10:
2465 ei_lba = 0;
2466 lba = get_unaligned_be32(cmd + 2);
2467 num = get_unaligned_be16(cmd + 7);
2468 check_prot = true;
2469 break;
2470 case READ_6:
2471 ei_lba = 0;
2472 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2473 (u32)(cmd[1] & 0x1f) << 16;
2474 num = (0 == cmd[4]) ? 256 : cmd[4];
2475 check_prot = true;
2476 break;
2477 case READ_12:
2478 ei_lba = 0;
2479 lba = get_unaligned_be32(cmd + 2);
2480 num = get_unaligned_be32(cmd + 6);
2481 check_prot = true;
2482 break;
2483 case XDWRITEREAD_10:
2484 ei_lba = 0;
2485 lba = get_unaligned_be32(cmd + 2);
2486 num = get_unaligned_be16(cmd + 7);
2487 check_prot = false;
2488 break;
2489 default: /* assume READ(32) */
2490 lba = get_unaligned_be64(cmd + 12);
2491 ei_lba = get_unaligned_be32(cmd + 20);
2492 num = get_unaligned_be32(cmd + 28);
2493 check_prot = false;
2494 break;
2495 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002496 if (unlikely(have_dif_prot && check_prot)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002497 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002498 (cmd[1] & 0xe0)) {
2499 mk_sense_invalid_opcode(scp);
2500 return check_condition_result;
2501 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002502 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2503 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002504 (cmd[1] & 0xe0) == 0)
2505 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2506 "to DIF device\n");
2507 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002508 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002509 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2510
2511 if (ep->inj_short)
2512 num /= 2;
2513 }
2514
2515 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002516 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002517 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2518 return check_condition_result;
2519 }
2520 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002521 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002522 /* needs work to find which cdb byte 'num' comes from */
2523 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2524 return check_condition_result;
2525 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002526
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002527 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
2528 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
2529 ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002530 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002531 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002532 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002533 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2534 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002535 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2536 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002537 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002538 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002539 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 return check_condition_result;
2541 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002542
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002543 read_lock_irqsave(&atomic_rw, iflags);
2544
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002545 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002546 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002547 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002548
2549 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002550 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002551 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002552 return illegal_condition_result;
2553 }
2554 }
2555
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002556 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002558 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002559 return DID_ERROR << 16;
2560
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002561 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002562
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002563 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002564 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2565
2566 if (ep->inj_recovered) {
2567 mk_sense_buffer(scp, RECOVERED_ERROR,
2568 THRESHOLD_EXCEEDED, 0);
2569 return check_condition_result;
2570 } else if (ep->inj_transport) {
2571 mk_sense_buffer(scp, ABORTED_COMMAND,
2572 TRANSPORT_PROBLEM, ACK_NAK_TO);
2573 return check_condition_result;
2574 } else if (ep->inj_dif) {
2575 /* Logical block guard check failed */
2576 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2577 return illegal_condition_result;
2578 } else if (ep->inj_dix) {
2579 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2580 return illegal_condition_result;
2581 }
2582 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002583 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584}
2585
Tomas Winkler58a86352015-07-28 16:54:23 +03002586static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002587{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002588 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002589
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002590 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002591 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002592 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002593
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002594 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002595 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002596
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002597 if (c >= 0x20 && c < 0x7e)
2598 n += scnprintf(b + n, sizeof(b) - n,
2599 " %c ", buf[i+j]);
2600 else
2601 n += scnprintf(b + n, sizeof(b) - n,
2602 "%02x ", buf[i+j]);
2603 }
2604 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002605 }
2606}
2607
2608static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002609 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002610{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002611 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002612 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002613 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002614 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002615 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002616 int dpage_offset;
2617 struct sg_mapping_iter diter;
2618 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002619
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002620 BUG_ON(scsi_sg_count(SCpnt) == 0);
2621 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2622
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002623 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2624 scsi_prot_sg_count(SCpnt),
2625 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2626 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2627 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002628
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002629 /* For each protection page */
2630 while (sg_miter_next(&piter)) {
2631 dpage_offset = 0;
2632 if (WARN_ON(!sg_miter_next(&diter))) {
2633 ret = 0x01;
2634 goto out;
2635 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002636
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002637 for (ppage_offset = 0; ppage_offset < piter.length;
2638 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002639 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002640 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002641 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002642 if (dpage_offset >= diter.length) {
2643 if (WARN_ON(!sg_miter_next(&diter))) {
2644 ret = 0x01;
2645 goto out;
2646 }
2647 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002648 }
2649
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002650 sdt = piter.addr + ppage_offset;
2651 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002652
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002653 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002654 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002655 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002656 goto out;
2657 }
2658
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002659 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002660 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002661 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002662 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002663 diter.consumed = dpage_offset;
2664 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002665 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002666 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002667
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002668 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002669 dix_writes++;
2670
2671 return 0;
2672
2673out:
2674 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002675 sg_miter_stop(&diter);
2676 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002677 return ret;
2678}
2679
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002680static unsigned long lba_to_map_index(sector_t lba)
2681{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002682 if (sdebug_unmap_alignment)
2683 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2684 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002685 return lba;
2686}
2687
2688static sector_t map_index_to_lba(unsigned long index)
2689{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002690 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002691
Douglas Gilbert773642d2016-04-25 12:16:28 -04002692 if (sdebug_unmap_alignment)
2693 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002694 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002695}
2696
Martin K. Petersen44d92692009-10-15 14:45:27 -04002697static unsigned int map_state(sector_t lba, unsigned int *num)
2698{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002699 sector_t end;
2700 unsigned int mapped;
2701 unsigned long index;
2702 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002703
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002704 index = lba_to_map_index(lba);
2705 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002706
2707 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002708 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002709 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002710 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002711
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002712 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002713 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002714 return mapped;
2715}
2716
2717static void map_region(sector_t lba, unsigned int len)
2718{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002719 sector_t end = lba + len;
2720
Martin K. Petersen44d92692009-10-15 14:45:27 -04002721 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002722 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002723
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002724 if (index < map_size)
2725 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002726
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002727 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002728 }
2729}
2730
2731static void unmap_region(sector_t lba, unsigned int len)
2732{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002733 sector_t end = lba + len;
2734
Martin K. Petersen44d92692009-10-15 14:45:27 -04002735 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002736 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002737
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002738 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002739 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002740 index < map_size) {
2741 clear_bit(index, map_storep);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002742 if (sdebug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002743 memset(fake_storep +
Douglas Gilbert773642d2016-04-25 12:16:28 -04002744 lba * sdebug_sector_size, 0,
2745 sdebug_sector_size *
2746 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002747 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002748 if (dif_storep) {
2749 memset(dif_storep + lba, 0xff,
2750 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002751 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002752 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002753 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002754 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002755 }
2756}
2757
Douglas Gilbertfd321192016-04-25 12:16:33 -04002758static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002760 u8 *cmd = scp->cmnd;
2761 u64 lba;
2762 u32 num;
2763 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002765 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002766 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002768 switch (cmd[0]) {
2769 case WRITE_16:
2770 ei_lba = 0;
2771 lba = get_unaligned_be64(cmd + 2);
2772 num = get_unaligned_be32(cmd + 10);
2773 check_prot = true;
2774 break;
2775 case WRITE_10:
2776 ei_lba = 0;
2777 lba = get_unaligned_be32(cmd + 2);
2778 num = get_unaligned_be16(cmd + 7);
2779 check_prot = true;
2780 break;
2781 case WRITE_6:
2782 ei_lba = 0;
2783 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2784 (u32)(cmd[1] & 0x1f) << 16;
2785 num = (0 == cmd[4]) ? 256 : cmd[4];
2786 check_prot = true;
2787 break;
2788 case WRITE_12:
2789 ei_lba = 0;
2790 lba = get_unaligned_be32(cmd + 2);
2791 num = get_unaligned_be32(cmd + 6);
2792 check_prot = true;
2793 break;
2794 case 0x53: /* XDWRITEREAD(10) */
2795 ei_lba = 0;
2796 lba = get_unaligned_be32(cmd + 2);
2797 num = get_unaligned_be16(cmd + 7);
2798 check_prot = false;
2799 break;
2800 default: /* assume WRITE(32) */
2801 lba = get_unaligned_be64(cmd + 12);
2802 ei_lba = get_unaligned_be32(cmd + 20);
2803 num = get_unaligned_be32(cmd + 28);
2804 check_prot = false;
2805 break;
2806 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002807 if (unlikely(have_dif_prot && check_prot)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002808 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002809 (cmd[1] & 0xe0)) {
2810 mk_sense_invalid_opcode(scp);
2811 return check_condition_result;
2812 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002813 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2814 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002815 (cmd[1] & 0xe0) == 0)
2816 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2817 "to DIF device\n");
2818 }
2819
2820 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002821 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002822 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2823 return check_condition_result;
2824 }
2825 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002826 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002827 /* needs work to find which cdb byte 'num' comes from */
2828 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2829 return check_condition_result;
2830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002832 write_lock_irqsave(&atomic_rw, iflags);
2833
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002834 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002835 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002836 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002837
2838 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002839 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002840 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002841 return illegal_condition_result;
2842 }
2843 }
2844
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002845 ret = do_device_access(scp, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002846 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04002847 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002849 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04002850 return DID_ERROR << 16;
2851 else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002852 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002853 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002854 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002855
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002856 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002857 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2858
2859 if (ep->inj_recovered) {
2860 mk_sense_buffer(scp, RECOVERED_ERROR,
2861 THRESHOLD_EXCEEDED, 0);
2862 return check_condition_result;
2863 } else if (ep->inj_dif) {
2864 /* Logical block guard check failed */
2865 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2866 return illegal_condition_result;
2867 } else if (ep->inj_dix) {
2868 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2869 return illegal_condition_result;
2870 }
2871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 return 0;
2873}
2874
Douglas Gilbertfd321192016-04-25 12:16:33 -04002875static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2876 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002877{
2878 unsigned long iflags;
2879 unsigned long long i;
2880 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002881 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002882
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002883 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002884 if (ret)
2885 return ret;
2886
2887 write_lock_irqsave(&atomic_rw, iflags);
2888
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002889 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002890 unmap_region(lba, num);
2891 goto out;
2892 }
2893
Douglas Gilbert773642d2016-04-25 12:16:28 -04002894 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002895 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2896 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002897 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002898 ret = 0;
2899 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04002900 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2901 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002902
2903 if (-1 == ret) {
2904 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002905 return DID_ERROR << 16;
2906 } else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002907 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002908 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2909 my_name, "write same",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002910 num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002911
2912 /* Copy first sector to remaining blocks */
2913 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002914 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2915 fake_storep + lba_off,
2916 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002917
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002918 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002919 map_region(lba, num);
2920out:
2921 write_unlock_irqrestore(&atomic_rw, iflags);
2922
2923 return 0;
2924}
2925
Douglas Gilbertfd321192016-04-25 12:16:33 -04002926static int resp_write_same_10(struct scsi_cmnd *scp,
2927 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002928{
2929 u8 *cmd = scp->cmnd;
2930 u32 lba;
2931 u16 num;
2932 u32 ei_lba = 0;
2933 bool unmap = false;
2934
2935 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002936 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002937 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2938 return check_condition_result;
2939 } else
2940 unmap = true;
2941 }
2942 lba = get_unaligned_be32(cmd + 2);
2943 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002944 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002945 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2946 return check_condition_result;
2947 }
2948 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2949}
2950
Douglas Gilbertfd321192016-04-25 12:16:33 -04002951static int resp_write_same_16(struct scsi_cmnd *scp,
2952 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002953{
2954 u8 *cmd = scp->cmnd;
2955 u64 lba;
2956 u32 num;
2957 u32 ei_lba = 0;
2958 bool unmap = false;
2959 bool ndob = false;
2960
2961 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002962 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002963 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2964 return check_condition_result;
2965 } else
2966 unmap = true;
2967 }
2968 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
2969 ndob = true;
2970 lba = get_unaligned_be64(cmd + 2);
2971 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002972 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002973 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2974 return check_condition_result;
2975 }
2976 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
2977}
2978
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05002979/* Note the mode field is in the same position as the (lower) service action
2980 * field. For the Report supported operation codes command, SPC-4 suggests
2981 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002982static int resp_write_buffer(struct scsi_cmnd *scp,
2983 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05002984{
2985 u8 *cmd = scp->cmnd;
2986 struct scsi_device *sdp = scp->device;
2987 struct sdebug_dev_info *dp;
2988 u8 mode;
2989
2990 mode = cmd[1] & 0x1f;
2991 switch (mode) {
2992 case 0x4: /* download microcode (MC) and activate (ACT) */
2993 /* set UAs on this device only */
2994 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2995 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
2996 break;
2997 case 0x5: /* download MC, save and ACT */
2998 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
2999 break;
3000 case 0x6: /* download MC with offsets and ACT */
3001 /* set UAs on most devices (LUs) in this target */
3002 list_for_each_entry(dp,
3003 &devip->sdbg_host->dev_info_list,
3004 dev_list)
3005 if (dp->target == sdp->id) {
3006 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3007 if (devip != dp)
3008 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3009 dp->uas_bm);
3010 }
3011 break;
3012 case 0x7: /* download MC with offsets, save, and ACT */
3013 /* set UA on all devices (LUs) in this target */
3014 list_for_each_entry(dp,
3015 &devip->sdbg_host->dev_info_list,
3016 dev_list)
3017 if (dp->target == sdp->id)
3018 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3019 dp->uas_bm);
3020 break;
3021 default:
3022 /* do nothing for this command for other mode values */
3023 break;
3024 }
3025 return 0;
3026}
3027
Douglas Gilbertfd321192016-04-25 12:16:33 -04003028static int resp_comp_write(struct scsi_cmnd *scp,
3029 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003030{
3031 u8 *cmd = scp->cmnd;
3032 u8 *arr;
3033 u8 *fake_storep_hold;
3034 u64 lba;
3035 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003036 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003037 u8 num;
3038 unsigned long iflags;
3039 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003040 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003041
Douglas Gilbertd467d312014-11-26 12:33:48 -05003042 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003043 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3044 if (0 == num)
3045 return 0; /* degenerate case, not an error */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003046 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003047 (cmd[1] & 0xe0)) {
3048 mk_sense_invalid_opcode(scp);
3049 return check_condition_result;
3050 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003051 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3052 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003053 (cmd[1] & 0xe0) == 0)
3054 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3055 "to DIF device\n");
3056
3057 /* inline check_device_access_params() */
3058 if (lba + num > sdebug_capacity) {
3059 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3060 return check_condition_result;
3061 }
3062 /* transfer length excessive (tie in to block limits VPD page) */
3063 if (num > sdebug_store_sectors) {
3064 /* needs work to find which cdb byte 'num' comes from */
3065 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3066 return check_condition_result;
3067 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003068 dnum = 2 * num;
3069 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3070 if (NULL == arr) {
3071 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3072 INSUFF_RES_ASCQ);
3073 return check_condition_result;
3074 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003075
3076 write_lock_irqsave(&atomic_rw, iflags);
3077
3078 /* trick do_device_access() to fetch both compare and write buffers
3079 * from data-in into arr. Safe (atomic) since write_lock held. */
3080 fake_storep_hold = fake_storep;
3081 fake_storep = arr;
3082 ret = do_device_access(scp, 0, dnum, true);
3083 fake_storep = fake_storep_hold;
3084 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003085 retval = DID_ERROR << 16;
3086 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003087 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003088 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3089 "indicated=%u, IO sent=%d bytes\n", my_name,
3090 dnum * lb_size, ret);
3091 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003092 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003093 retval = check_condition_result;
3094 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003095 }
3096 if (scsi_debug_lbp())
3097 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003098cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003099 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003100 kfree(arr);
3101 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003102}
3103
Martin K. Petersen44d92692009-10-15 14:45:27 -04003104struct unmap_block_desc {
3105 __be64 lba;
3106 __be32 blocks;
3107 __be32 __reserved;
3108};
3109
Douglas Gilbertfd321192016-04-25 12:16:33 -04003110static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003111{
3112 unsigned char *buf;
3113 struct unmap_block_desc *desc;
3114 unsigned int i, payload_len, descriptors;
3115 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003116 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003117
Martin K. Petersen44d92692009-10-15 14:45:27 -04003118
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003119 if (!scsi_debug_lbp())
3120 return 0; /* fib and say its done */
3121 payload_len = get_unaligned_be16(scp->cmnd + 7);
3122 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003123
3124 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003125 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003126 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003127 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003128 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003129
Douglas Gilbertb333a812016-04-25 12:16:30 -04003130 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003131 if (!buf) {
3132 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3133 INSUFF_RES_ASCQ);
3134 return check_condition_result;
3135 }
3136
3137 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003138
3139 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3140 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3141
3142 desc = (void *)&buf[8];
3143
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003144 write_lock_irqsave(&atomic_rw, iflags);
3145
Martin K. Petersen44d92692009-10-15 14:45:27 -04003146 for (i = 0 ; i < descriptors ; i++) {
3147 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3148 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3149
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003150 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003151 if (ret)
3152 goto out;
3153
3154 unmap_region(lba, num);
3155 }
3156
3157 ret = 0;
3158
3159out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003160 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003161 kfree(buf);
3162
3163 return ret;
3164}
3165
3166#define SDEBUG_GET_LBA_STATUS_LEN 32
3167
Douglas Gilbertfd321192016-04-25 12:16:33 -04003168static int resp_get_lba_status(struct scsi_cmnd *scp,
3169 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003170{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003171 u8 *cmd = scp->cmnd;
3172 u64 lba;
3173 u32 alloc_len, mapped, num;
3174 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003175 int ret;
3176
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003177 lba = get_unaligned_be64(cmd + 2);
3178 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003179
3180 if (alloc_len < 24)
3181 return 0;
3182
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003183 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003184 if (ret)
3185 return ret;
3186
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003187 if (scsi_debug_lbp())
3188 mapped = map_state(lba, &num);
3189 else {
3190 mapped = 1;
3191 /* following just in case virtual_gb changed */
3192 sdebug_capacity = get_sdebug_capacity();
3193 if (sdebug_capacity - lba <= 0xffffffff)
3194 num = sdebug_capacity - lba;
3195 else
3196 num = 0xffffffff;
3197 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003198
3199 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003200 put_unaligned_be32(20, arr); /* Parameter Data Length */
3201 put_unaligned_be64(lba, arr + 8); /* LBA */
3202 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3203 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003204
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003205 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003206}
3207
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003208#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
3210static int resp_report_luns(struct scsi_cmnd * scp,
3211 struct sdebug_dev_info * devip)
3212{
3213 unsigned int alloc_len;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003214 int lun_cnt, i, upper, num, n, want_wlun, shortish;
3215 u64 lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003216 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 int select_report = (int)cmd[2];
3218 struct scsi_lun *one_lun;
3219 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003220 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003222 clear_luns_changed_on_target(devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003224 shortish = (alloc_len < 4);
3225 if (shortish || (select_report > 2)) {
3226 mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 return check_condition_result;
3228 }
3229 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
3230 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003231 lun_cnt = sdebug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003232 if (1 == select_report)
3233 lun_cnt = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003234 else if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003235 --lun_cnt;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003236 want_wlun = (select_report > 0) ? 1 : 0;
3237 num = lun_cnt + want_wlun;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003238 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3239 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3240 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3241 sizeof(struct scsi_lun)), num);
3242 if (n < num) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003243 want_wlun = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003244 lun_cnt = n;
3245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003247 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003248 for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003249 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3250 i++, lun++) {
3251 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 if (upper)
3253 one_lun[i].scsi_lun[0] =
3254 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003255 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003257 if (want_wlun) {
Tomas Winkler34d55432015-07-28 16:54:21 +03003258 one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
3259 one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003260 i++;
3261 }
3262 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 return fill_from_dev_buffer(scp, arr,
3264 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
3265}
3266
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003267static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3268 unsigned int num, struct sdebug_dev_info *devip)
3269{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003270 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003271 unsigned char *kaddr, *buf;
3272 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003273 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003274 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003275
3276 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003277 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003278 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003279 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3280 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003281 return check_condition_result;
3282 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003283
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003284 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003285
3286 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003287 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3288 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003289
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003290 while (sg_miter_next(&miter)) {
3291 kaddr = miter.addr;
3292 for (j = 0; j < miter.length; j++)
3293 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003294
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003295 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003296 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003297 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003298 kfree(buf);
3299
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003300 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003301}
3302
Douglas Gilbertfd321192016-04-25 12:16:33 -04003303static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3304 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003305{
3306 u8 *cmd = scp->cmnd;
3307 u64 lba;
3308 u32 num;
3309 int errsts;
3310
3311 if (!scsi_bidi_cmnd(scp)) {
3312 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3313 INSUFF_RES_ASCQ);
3314 return check_condition_result;
3315 }
3316 errsts = resp_read_dt0(scp, devip);
3317 if (errsts)
3318 return errsts;
3319 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3320 errsts = resp_write_dt0(scp, devip);
3321 if (errsts)
3322 return errsts;
3323 }
3324 lba = get_unaligned_be32(cmd + 2);
3325 num = get_unaligned_be16(cmd + 7);
3326 return resp_xdwriteread(scp, lba, num, devip);
3327}
3328
Douglas Gilberta10bc122016-04-25 12:16:32 -04003329/* Queued command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003330static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003332 int qa_indx;
3333 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003335 struct sdebug_queued_cmd *sqcp;
3336 struct scsi_cmnd *scp;
3337 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003339 atomic_inc(&sdebug_completions);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003340 qa_indx = sd_dp->qa_indx;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003341 if (unlikely((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE))) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003342 pr_err("wild qa_indx=%d\n", qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 return;
3344 }
3345 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003346 sqcp = &queued_arr[qa_indx];
3347 scp = sqcp->a_cmnd;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003348 if (unlikely(NULL == scp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003350 pr_err("scp is NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 return;
3352 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003353 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003354 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003355 atomic_dec(&devip->num_in_q);
3356 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003357 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003358 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003359 retiring = 1;
3360
3361 sqcp->a_cmnd = NULL;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003362 if (unlikely(!test_and_clear_bit(qa_indx, queued_in_use_bm))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003363 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003364 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003365 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003367
3368 if (unlikely(retiring)) { /* user has reduced max_queue */
3369 int k, retval;
3370
3371 retval = atomic_read(&retired_max_queue);
3372 if (qa_indx >= retval) {
3373 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003374 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003375 return;
3376 }
3377 k = find_last_bit(queued_in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003378 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003379 atomic_set(&retired_max_queue, 0);
3380 else
3381 atomic_set(&retired_max_queue, k + 1);
3382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003384 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385}
3386
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003387/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003388static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003389{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003390 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3391 hrt);
3392 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003393 return HRTIMER_NORESTART;
3394}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
Douglas Gilberta10bc122016-04-25 12:16:32 -04003396/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003397static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003398{
3399 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3400 ew.work);
3401 sdebug_q_cmd_complete(sd_dp);
3402}
3403
Douglas Gilbertfd321192016-04-25 12:16:33 -04003404static struct sdebug_dev_info *sdebug_device_create(
3405 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003406{
3407 struct sdebug_dev_info *devip;
3408
3409 devip = kzalloc(sizeof(*devip), flags);
3410 if (devip) {
3411 devip->sdbg_host = sdbg_host;
3412 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3413 }
3414 return devip;
3415}
3416
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003417static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003419 struct sdebug_host_info *sdbg_host;
3420 struct sdebug_dev_info *open_devip = NULL;
3421 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003423 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3424 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003425 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 return NULL;
3427 }
3428 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3429 if ((devip->used) && (devip->channel == sdev->channel) &&
3430 (devip->target == sdev->id) &&
3431 (devip->lun == sdev->lun))
3432 return devip;
3433 else {
3434 if ((!devip->used) && (!open_devip))
3435 open_devip = devip;
3436 }
3437 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003438 if (!open_devip) { /* try and make a new one */
3439 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3440 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003441 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 return NULL;
3443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003445
3446 open_devip->channel = sdev->channel;
3447 open_devip->target = sdev->id;
3448 open_devip->lun = sdev->lun;
3449 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003450 atomic_set(&open_devip->num_in_q, 0);
3451 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003452 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003453 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454}
3455
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003456static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003458 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003459 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003460 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003461 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003462 return 0;
3463}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003465static int scsi_debug_slave_configure(struct scsi_device *sdp)
3466{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003467 struct sdebug_dev_info *devip =
3468 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003469
Douglas Gilbert773642d2016-04-25 12:16:28 -04003470 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003471 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003472 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3473 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
3474 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003475 if (NULL == devip) {
3476 devip = find_build_dev_info(sdp);
3477 if (NULL == devip)
3478 return 1; /* no resources, will be marked offline */
3479 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003480 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003481 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003482 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003483 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003484 return 0;
3485}
3486
3487static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3488{
3489 struct sdebug_dev_info *devip =
3490 (struct sdebug_dev_info *)sdp->hostdata;
3491
Douglas Gilbert773642d2016-04-25 12:16:28 -04003492 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003493 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003494 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3495 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003496 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003497 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003498 sdp->hostdata = NULL;
3499 }
3500}
3501
Douglas Gilberta10bc122016-04-25 12:16:32 -04003502/* If @cmnd found deletes its timer or work queue and returns true; else
3503 returns false */
3504static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003505{
3506 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003507 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003508 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003509 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003510 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003511
3512 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003513 qmax = sdebug_max_queue;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003514 r_qmax = atomic_read(&retired_max_queue);
3515 if (r_qmax > qmax)
3516 qmax = r_qmax;
3517 for (k = 0; k < qmax; ++k) {
3518 if (test_bit(k, queued_in_use_bm)) {
3519 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003520 if (cmnd != sqcp->a_cmnd)
3521 continue;
3522 /* found command */
3523 devip = (struct sdebug_dev_info *)
3524 cmnd->device->hostdata;
3525 if (devip)
3526 atomic_dec(&devip->num_in_q);
3527 sqcp->a_cmnd = NULL;
3528 sd_dp = sqcp->sd_dp;
3529 spin_unlock_irqrestore(&queued_arr_lock,
3530 iflags);
3531 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
3532 if (sd_dp)
3533 hrtimer_cancel(&sd_dp->hrt);
3534 } else if (sdebug_jdelay < 0) {
3535 if (sd_dp)
3536 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003537 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003538 clear_bit(k, queued_in_use_bm);
3539 return true;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003540 }
3541 }
3542 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003543 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003544}
3545
Douglas Gilberta10bc122016-04-25 12:16:32 -04003546/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003547static void stop_all_queued(void)
3548{
3549 unsigned long iflags;
3550 int k;
3551 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003552 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003553 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003554
3555 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003556 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3557 if (test_bit(k, queued_in_use_bm)) {
3558 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003559 if (NULL == sqcp->a_cmnd)
3560 continue;
3561 devip = (struct sdebug_dev_info *)
3562 sqcp->a_cmnd->device->hostdata;
3563 if (devip)
3564 atomic_dec(&devip->num_in_q);
3565 sqcp->a_cmnd = NULL;
3566 sd_dp = sqcp->sd_dp;
3567 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3568 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
3569 if (sd_dp)
3570 hrtimer_cancel(&sd_dp->hrt);
3571 } else if (sdebug_jdelay < 0) {
3572 if (sd_dp)
3573 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003574 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003575 clear_bit(k, queued_in_use_bm);
3576 spin_lock_irqsave(&queued_arr_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003577 }
3578 }
3579 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580}
3581
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003582/* Free queued command memory on heap */
3583static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003585 int k;
3586 struct sdebug_queued_cmd *sqcp;
3587
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003588 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3589 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003590 kfree(sqcp->sd_dp);
3591 sqcp->sd_dp = NULL;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593}
3594
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003595static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003597 bool ok;
3598
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003599 ++num_aborts;
3600 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003601 ok = stop_queued_cmnd(SCpnt);
3602 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3603 sdev_printk(KERN_INFO, SCpnt->device,
3604 "%s: command%s found\n", __func__,
3605 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003607 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608}
3609
3610static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3611{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003613 if (SCpnt && SCpnt->device) {
3614 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003615 struct sdebug_dev_info *devip =
3616 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003617
Douglas Gilbert773642d2016-04-25 12:16:28 -04003618 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003619 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003621 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 }
3623 return SUCCESS;
3624}
3625
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003626static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3627{
3628 struct sdebug_host_info *sdbg_host;
3629 struct sdebug_dev_info *devip;
3630 struct scsi_device *sdp;
3631 struct Scsi_Host *hp;
3632 int k = 0;
3633
3634 ++num_target_resets;
3635 if (!SCpnt)
3636 goto lie;
3637 sdp = SCpnt->device;
3638 if (!sdp)
3639 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003640 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003641 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3642 hp = sdp->host;
3643 if (!hp)
3644 goto lie;
3645 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3646 if (sdbg_host) {
3647 list_for_each_entry(devip,
3648 &sdbg_host->dev_info_list,
3649 dev_list)
3650 if (devip->target == sdp->id) {
3651 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3652 ++k;
3653 }
3654 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003655 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003656 sdev_printk(KERN_INFO, sdp,
3657 "%s: %d device(s) found in target\n", __func__, k);
3658lie:
3659 return SUCCESS;
3660}
3661
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3663{
3664 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003665 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 struct scsi_device * sdp;
3667 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003668 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003671 if (!(SCpnt && SCpnt->device))
3672 goto lie;
3673 sdp = SCpnt->device;
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) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003678 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003680 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003682 dev_list) {
3683 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3684 ++k;
3685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 }
3687 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003688 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003689 sdev_printk(KERN_INFO, sdp,
3690 "%s: %d device(s) found in host\n", __func__, k);
3691lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 return SUCCESS;
3693}
3694
3695static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3696{
3697 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003698 struct sdebug_dev_info *devip;
3699 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003702 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003703 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 spin_lock(&sdebug_host_list_lock);
3705 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003706 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3707 dev_list) {
3708 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3709 ++k;
3710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 }
3712 spin_unlock(&sdebug_host_list_lock);
3713 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003714 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003715 sdev_printk(KERN_INFO, SCpnt->device,
3716 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 return SUCCESS;
3718}
3719
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003720static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003721 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722{
3723 struct partition * pp;
3724 int starts[SDEBUG_MAX_PARTS + 2];
3725 int sectors_per_part, num_sectors, k;
3726 int heads_by_sects, start_sec, end_sec;
3727
3728 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003729 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003731 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3732 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003733 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003735 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003737 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3739 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003740 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3742 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003743 starts[sdebug_num_parts] = num_sectors;
3744 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745
3746 ramp[510] = 0x55; /* magic partition markings */
3747 ramp[511] = 0xAA;
3748 pp = (struct partition *)(ramp + 0x1be);
3749 for (k = 0; starts[k + 1]; ++k, ++pp) {
3750 start_sec = starts[k];
3751 end_sec = starts[k + 1] - 1;
3752 pp->boot_ind = 0;
3753
3754 pp->cyl = start_sec / heads_by_sects;
3755 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3756 / sdebug_sectors_per;
3757 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3758
3759 pp->end_cyl = end_sec / heads_by_sects;
3760 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3761 / sdebug_sectors_per;
3762 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3763
Akinobu Mita150c3542013-08-26 22:08:40 +09003764 pp->start_sect = cpu_to_le32(start_sec);
3765 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 pp->sys_ind = 0x83; /* plain Linux partition */
3767 }
3768}
3769
Douglas Gilbertfd321192016-04-25 12:16:33 -04003770static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3771 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003773 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003774 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003775 struct sdebug_queued_cmd *sqcp = NULL;
Tomas Winkler299b6c02015-07-28 16:54:24 +03003776 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003777 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003779 if (unlikely(WARN_ON(!cmnd)))
Tomas Winkler299b6c02015-07-28 16:54:24 +03003780 return SCSI_MLQUEUE_HOST_BUSY;
3781
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003782 if (unlikely(NULL == devip)) {
3783 if (0 == scsi_result)
3784 scsi_result = DID_NO_CONNECT << 16;
3785 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03003787
3788 sdp = cmnd->device;
3789
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003790 if (unlikely(sdebug_verbose && scsi_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003791 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3792 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003793 if (delta_jiff == 0)
3794 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003796 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003797 spin_lock_irqsave(&queued_arr_lock, iflags);
3798 num_in_q = atomic_read(&devip->num_in_q);
3799 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003800 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003801 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003802 if (scsi_result) {
3803 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3804 goto respond_in_thread;
3805 } else
3806 scsi_result = device_qfull_result;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003807 } else if (unlikely((sdebug_every_nth != 0) &&
3808 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
3809 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003810 if ((num_in_q == (qdepth - 1)) &&
3811 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04003812 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003813 atomic_set(&sdebug_a_tsf, 0);
3814 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003815 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003817 }
3818
Douglas Gilbert773642d2016-04-25 12:16:28 -04003819 k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003820 if (unlikely(k >= sdebug_max_queue)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003822 if (scsi_result)
3823 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003824 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003825 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003826 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003827 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003828 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003829 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003830 (scsi_result ? "status: TASK SET FULL" :
3831 "report: host busy"));
3832 if (scsi_result)
3833 goto respond_in_thread;
3834 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003835 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003837 __set_bit(k, queued_in_use_bm);
3838 atomic_inc(&devip->num_in_q);
3839 sqcp = &queued_arr[k];
3840 sqcp->a_cmnd = cmnd;
3841 cmnd->result = scsi_result;
3842 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003843 sd_dp = sqcp->sd_dp;
Douglas Gilbertb333a812016-04-25 12:16:30 -04003844 if ((delta_jiff > 0) || (sdebug_ndelay > 0)) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04003845 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003846
Douglas Gilbertb333a812016-04-25 12:16:30 -04003847 if (delta_jiff > 0) {
3848 struct timespec ts;
3849
3850 jiffies_to_timespec(delta_jiff, &ts);
3851 kt = ktime_set(ts.tv_sec, ts.tv_nsec);
3852 } else
3853 kt = ktime_set(0, sdebug_ndelay);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003854 if (NULL == sd_dp) {
3855 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
3856 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003857 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003858 sqcp->sd_dp = sd_dp;
3859 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003860 HRTIMER_MODE_REL);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003861 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
3862 sd_dp->qa_indx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003863 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003864 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003865 } else { /* jdelay < 0 */
Douglas Gilberta10bc122016-04-25 12:16:32 -04003866 if (NULL == sd_dp) {
3867 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
3868 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003869 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003870 sqcp->sd_dp = sd_dp;
3871 sd_dp->qa_indx = k;
3872 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003873 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003874 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003875 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003876 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
3877 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003878 sdev_printk(KERN_INFO, sdp,
3879 "%s: num_in_q=%d +1, %s%s\n", __func__,
3880 num_in_q, (inject ? "<inject> " : ""),
3881 "status: TASK SET FULL");
3882 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003883
3884respond_in_thread: /* call back to mid-layer using invocation thread */
3885 cmnd->result = scsi_result;
3886 cmnd->scsi_done(cmnd);
3887 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003889
Douglas Gilbert23183912006-09-16 20:30:47 -04003890/* Note: The following macros create attribute files in the
3891 /sys/module/scsi_debug/parameters directory. Unfortunately this
3892 driver is unaware of a change and cannot trigger auxiliary actions
3893 as it can when the corresponding attribute in the
3894 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3895 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003896module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3897module_param_named(ato, sdebug_ato, int, S_IRUGO);
3898module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003899module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003900module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3901module_param_named(dif, sdebug_dif, int, S_IRUGO);
3902module_param_named(dix, sdebug_dix, int, S_IRUGO);
3903module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3904module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3905module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3906module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3907module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3908module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3909module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3910module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
3911module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
3912module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
3913module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
3914module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
3915module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
3916module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
3917module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
3918module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
3919module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
3920module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
3921module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
3922module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
3923module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
3924module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
3925module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
3926module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
3927module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
3928module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
3929module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
3930module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
3931module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
3932module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
3933module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04003934 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003935module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003936 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937
3938MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
3939MODULE_DESCRIPTION("SCSI debug adapter driver");
3940MODULE_LICENSE("GPL");
3941MODULE_VERSION(SCSI_DEBUG_VERSION);
3942
3943MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003944MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09003945MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003946MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003947MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003948MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
3949MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003950MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07003951MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04003952MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003953MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04003954MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003955MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
3956MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
3957MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003958MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003959MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003960MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003961MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3962MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003963MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003964MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003966MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05003967MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05003968MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003969MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02003971MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02003972MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003973MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003974MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003975MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
3976MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04003977MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
3978MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003979MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003980MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
3981MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982
3983static char sdebug_info[256];
3984
3985static const char * scsi_debug_info(struct Scsi_Host * shp)
3986{
3987 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
3988 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
Douglas Gilbert773642d2016-04-25 12:16:28 -04003989 sdebug_version_date, sdebug_dev_size_mb, sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 return sdebug_info;
3991}
3992
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003993/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003994static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
3995 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996{
Al Viroc8ed5552013-03-31 01:46:06 -04003997 char arr[16];
3998 int opts;
3999 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000
Al Viroc8ed5552013-03-31 01:46:06 -04004001 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4002 return -EACCES;
4003 memcpy(arr, buffer, minLen);
4004 arr[minLen] = '\0';
4005 if (1 != sscanf(arr, "%d", &opts))
4006 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004007 sdebug_opts = opts;
4008 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4009 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4010 if (sdebug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004011 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04004012 return length;
4013}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004015/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4016 * same for each scsi_debug host (if more than one). Some of the counters
4017 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004018static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4019{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004020 int f, l;
4021 char b[32];
4022
Douglas Gilbert773642d2016-04-25 12:16:28 -04004023 if (sdebug_every_nth > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004024 snprintf(b, sizeof(b), " (curr:%d)",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004025 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004026 atomic_read(&sdebug_a_tsf) :
4027 atomic_read(&sdebug_cmnd_count)));
4028 else
4029 b[0] = '\0';
4030
4031 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
4032 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4033 "every_nth=%d%s\n"
4034 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
4035 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4036 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4037 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4038 "usec_in_jiffy=%lu\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004039 SCSI_DEBUG_VERSION, sdebug_version_date,
4040 sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04004041 sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004042 sdebug_max_luns, atomic_read(&sdebug_completions),
4043 sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004044 sdebug_sectors_per, num_aborts, num_dev_resets,
4045 num_target_resets, num_bus_resets, num_host_resets,
4046 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4047
Douglas Gilbert773642d2016-04-25 12:16:28 -04004048 f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4049 if (f != sdebug_max_queue) {
4050 l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004051 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
4052 "queued_in_use_bm", f, l);
4053 }
Al Viroc8ed5552013-03-31 01:46:06 -04004054 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055}
4056
Akinobu Mita82069372013-10-14 22:48:04 +09004057static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004059 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060}
Douglas Gilbertc2206092016-04-25 12:16:31 -04004061/* Returns -EBUSY if jdelay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09004062static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4063 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004065 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066
Douglas Gilbertc2206092016-04-25 12:16:31 -04004067 if ((count > 0) && (1 == sscanf(buf, "%d", &jdelay))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004068 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004069 if (sdebug_jdelay != jdelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004070 unsigned long iflags;
4071 int k;
4072
4073 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004074 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4075 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004076 res = -EBUSY; /* have queued commands */
4077 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004078 /* make sure sdebug_defer instances get
4079 * re-allocated for new delay variant */
4080 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004081 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004082 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004083 }
4084 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004086 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 }
4088 return -EINVAL;
4089}
Akinobu Mita82069372013-10-14 22:48:04 +09004090static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004092static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4093{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004094 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004095}
4096/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004097/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004098static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004099 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004100{
4101 unsigned long iflags;
4102 int ndelay, res, k;
4103
4104 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4105 (ndelay >= 0) && (ndelay < 1000000000)) {
4106 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004107 if (sdebug_ndelay != ndelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004108 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 Gilbert773642d2016-04-25 12:16:28 -04004116 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004117 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4118 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004119 }
4120 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4121 }
4122 return res;
4123 }
4124 return -EINVAL;
4125}
4126static DRIVER_ATTR_RW(ndelay);
4127
Akinobu Mita82069372013-10-14 22:48:04 +09004128static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004130 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131}
4132
Akinobu Mita82069372013-10-14 22:48:04 +09004133static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4134 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135{
4136 int opts;
4137 char work[20];
4138
4139 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004140 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 if (1 == sscanf(&work[2], "%x", &opts))
4142 goto opts_done;
4143 } else {
4144 if (1 == sscanf(work, "%d", &opts))
4145 goto opts_done;
4146 }
4147 }
4148 return -EINVAL;
4149opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004150 sdebug_opts = opts;
4151 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4152 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004153 atomic_set(&sdebug_cmnd_count, 0);
4154 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 return count;
4156}
Akinobu Mita82069372013-10-14 22:48:04 +09004157static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158
Akinobu Mita82069372013-10-14 22:48:04 +09004159static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004161 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162}
Akinobu Mita82069372013-10-14 22:48:04 +09004163static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4164 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165{
4166 int n;
4167
4168 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004169 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 return count;
4171 }
4172 return -EINVAL;
4173}
Akinobu Mita82069372013-10-14 22:48:04 +09004174static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Akinobu Mita82069372013-10-14 22:48:04 +09004176static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004178 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179}
Akinobu Mita82069372013-10-14 22:48:04 +09004180static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4181 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182{
4183 int n;
4184
4185 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004186 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 return count;
4188 }
4189 return -EINVAL;
4190}
Akinobu Mita82069372013-10-14 22:48:04 +09004191static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
Akinobu Mita82069372013-10-14 22:48:04 +09004193static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004194{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004195 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004196}
Akinobu Mita82069372013-10-14 22:48:04 +09004197static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4198 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004199{
4200 int n;
4201
4202 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004203 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004204 sdebug_fake_rw = (sdebug_fake_rw > 0);
4205 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004206 if ((0 == n) && (NULL == fake_storep)) {
4207 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004208 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004209 1048576;
4210
4211 fake_storep = vmalloc(sz);
4212 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004213 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004214 return -ENOMEM;
4215 }
4216 memset(fake_storep, 0, sz);
4217 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004218 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004219 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004220 return count;
4221 }
4222 return -EINVAL;
4223}
Akinobu Mita82069372013-10-14 22:48:04 +09004224static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004225
Akinobu Mita82069372013-10-14 22:48:04 +09004226static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004227{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004228 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004229}
Akinobu Mita82069372013-10-14 22:48:04 +09004230static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4231 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004232{
4233 int n;
4234
4235 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004236 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004237 return count;
4238 }
4239 return -EINVAL;
4240}
Akinobu Mita82069372013-10-14 22:48:04 +09004241static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004242
Akinobu Mita82069372013-10-14 22:48:04 +09004243static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004245 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246}
Akinobu Mita82069372013-10-14 22:48:04 +09004247static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4248 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249{
4250 int n;
4251
4252 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004253 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 sdebug_max_tgts_luns();
4255 return count;
4256 }
4257 return -EINVAL;
4258}
Akinobu Mita82069372013-10-14 22:48:04 +09004259static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
Akinobu Mita82069372013-10-14 22:48:04 +09004261static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004263 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264}
Akinobu Mita82069372013-10-14 22:48:04 +09004265static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266
Akinobu Mita82069372013-10-14 22:48:04 +09004267static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004269 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270}
Akinobu Mita82069372013-10-14 22:48:04 +09004271static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272
Akinobu Mita82069372013-10-14 22:48:04 +09004273static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004275 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276}
Akinobu Mita82069372013-10-14 22:48:04 +09004277static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4278 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279{
4280 int nth;
4281
4282 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004283 sdebug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004284 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 return count;
4286 }
4287 return -EINVAL;
4288}
Akinobu Mita82069372013-10-14 22:48:04 +09004289static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290
Akinobu Mita82069372013-10-14 22:48:04 +09004291static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004293 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294}
Akinobu Mita82069372013-10-14 22:48:04 +09004295static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4296 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297{
4298 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004299 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300
4301 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004302 changed = (sdebug_max_luns != n);
4303 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004305 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004306 struct sdebug_host_info *sdhp;
4307 struct sdebug_dev_info *dp;
4308
4309 spin_lock(&sdebug_host_list_lock);
4310 list_for_each_entry(sdhp, &sdebug_host_list,
4311 host_list) {
4312 list_for_each_entry(dp, &sdhp->dev_info_list,
4313 dev_list) {
4314 set_bit(SDEBUG_UA_LUNS_CHANGED,
4315 dp->uas_bm);
4316 }
4317 }
4318 spin_unlock(&sdebug_host_list_lock);
4319 }
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(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325
Akinobu Mita82069372013-10-14 22:48:04 +09004326static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004327{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004328 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004329}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004330/* N.B. max_queue can be changed while there are queued commands. In flight
4331 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004332static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4333 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004334{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004335 unsigned long iflags;
4336 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004337
4338 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4339 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004340 spin_lock_irqsave(&queued_arr_lock, iflags);
4341 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004342 sdebug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004343 if (SCSI_DEBUG_CANQUEUE == k)
4344 atomic_set(&retired_max_queue, 0);
4345 else if (k >= n)
4346 atomic_set(&retired_max_queue, k + 1);
4347 else
4348 atomic_set(&retired_max_queue, 0);
4349 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004350 return count;
4351 }
4352 return -EINVAL;
4353}
Akinobu Mita82069372013-10-14 22:48:04 +09004354static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004355
Akinobu Mita82069372013-10-14 22:48:04 +09004356static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004357{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004358 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004359}
Akinobu Mita82069372013-10-14 22:48:04 +09004360static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004361
Akinobu Mita82069372013-10-14 22:48:04 +09004362static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004364 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365}
Akinobu Mita82069372013-10-14 22:48:04 +09004366static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367
Akinobu Mita82069372013-10-14 22:48:04 +09004368static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004369{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004370 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004371}
Akinobu Mita82069372013-10-14 22:48:04 +09004372static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4373 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004374{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004375 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004376 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004377
4378 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004379 changed = (sdebug_virtual_gb != n);
4380 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004381 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004382 if (changed) {
4383 struct sdebug_host_info *sdhp;
4384 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004385
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004386 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004387 list_for_each_entry(sdhp, &sdebug_host_list,
4388 host_list) {
4389 list_for_each_entry(dp, &sdhp->dev_info_list,
4390 dev_list) {
4391 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4392 dp->uas_bm);
4393 }
4394 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004395 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004396 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004397 return count;
4398 }
4399 return -EINVAL;
4400}
Akinobu Mita82069372013-10-14 22:48:04 +09004401static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004402
Akinobu Mita82069372013-10-14 22:48:04 +09004403static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004405 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406}
4407
Douglas Gilbertfd321192016-04-25 12:16:33 -04004408static int sdebug_add_adapter(void);
4409static void sdebug_remove_adapter(void);
4410
Akinobu Mita82069372013-10-14 22:48:04 +09004411static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4412 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004414 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004416 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 if (delta_hosts > 0) {
4419 do {
4420 sdebug_add_adapter();
4421 } while (--delta_hosts);
4422 } else if (delta_hosts < 0) {
4423 do {
4424 sdebug_remove_adapter();
4425 } while (++delta_hosts);
4426 }
4427 return count;
4428}
Akinobu Mita82069372013-10-14 22:48:04 +09004429static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430
Akinobu Mita82069372013-10-14 22:48:04 +09004431static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004432{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004433 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004434}
Akinobu Mita82069372013-10-14 22:48:04 +09004435static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4436 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004437{
4438 int n;
4439
4440 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004441 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004442 return count;
4443 }
4444 return -EINVAL;
4445}
Akinobu Mita82069372013-10-14 22:48:04 +09004446static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004447
Akinobu Mita82069372013-10-14 22:48:04 +09004448static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004449{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004450 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004451}
Akinobu Mita82069372013-10-14 22:48:04 +09004452static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004453
Akinobu Mita82069372013-10-14 22:48:04 +09004454static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004455{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004456 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004457}
Akinobu Mita82069372013-10-14 22:48:04 +09004458static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004459
Akinobu Mita82069372013-10-14 22:48:04 +09004460static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004461{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004462 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004463}
Akinobu Mita82069372013-10-14 22:48:04 +09004464static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004465
Akinobu Mita82069372013-10-14 22:48:04 +09004466static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004467{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004468 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004469}
Akinobu Mita82069372013-10-14 22:48:04 +09004470static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004471
Akinobu Mita82069372013-10-14 22:48:04 +09004472static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004473{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004474 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004475}
Akinobu Mita82069372013-10-14 22:48:04 +09004476static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004477
Akinobu Mita82069372013-10-14 22:48:04 +09004478static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004479{
4480 ssize_t count;
4481
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004482 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004483 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4484 sdebug_store_sectors);
4485
Tejun Heoc7badc92015-02-13 14:37:51 -08004486 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4487 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004488 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004489 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004490
4491 return count;
4492}
Akinobu Mita82069372013-10-14 22:48:04 +09004493static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004494
Akinobu Mita82069372013-10-14 22:48:04 +09004495static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004496{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004497 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004498}
Akinobu Mita82069372013-10-14 22:48:04 +09004499static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4500 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004501{
4502 int n;
4503
4504 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004505 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004506 return count;
4507 }
4508 return -EINVAL;
4509}
Akinobu Mita82069372013-10-14 22:48:04 +09004510static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004511
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004512static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4513{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004514 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004515}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004516/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004517static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4518 size_t count)
4519{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004520 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004521
4522 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004523 sdebug_host_lock = (n > 0);
4524 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004525 }
4526 return -EINVAL;
4527}
4528static DRIVER_ATTR_RW(host_lock);
4529
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004530static ssize_t strict_show(struct device_driver *ddp, char *buf)
4531{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004532 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004533}
4534static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4535 size_t count)
4536{
4537 int n;
4538
4539 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004540 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004541 return count;
4542 }
4543 return -EINVAL;
4544}
4545static DRIVER_ATTR_RW(strict);
4546
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004547
Akinobu Mita82069372013-10-14 22:48:04 +09004548/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004549 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4550 files (over those found in the /sys/module/scsi_debug/parameters
4551 directory) is that auxiliary actions can be triggered when an attribute
4552 is changed. For example see: sdebug_add_host_store() above.
4553 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004554
Akinobu Mita82069372013-10-14 22:48:04 +09004555static struct attribute *sdebug_drv_attrs[] = {
4556 &driver_attr_delay.attr,
4557 &driver_attr_opts.attr,
4558 &driver_attr_ptype.attr,
4559 &driver_attr_dsense.attr,
4560 &driver_attr_fake_rw.attr,
4561 &driver_attr_no_lun_0.attr,
4562 &driver_attr_num_tgts.attr,
4563 &driver_attr_dev_size_mb.attr,
4564 &driver_attr_num_parts.attr,
4565 &driver_attr_every_nth.attr,
4566 &driver_attr_max_luns.attr,
4567 &driver_attr_max_queue.attr,
4568 &driver_attr_no_uld.attr,
4569 &driver_attr_scsi_level.attr,
4570 &driver_attr_virtual_gb.attr,
4571 &driver_attr_add_host.attr,
4572 &driver_attr_vpd_use_hostno.attr,
4573 &driver_attr_sector_size.attr,
4574 &driver_attr_dix.attr,
4575 &driver_attr_dif.attr,
4576 &driver_attr_guard.attr,
4577 &driver_attr_ato.attr,
4578 &driver_attr_map.attr,
4579 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004580 &driver_attr_host_lock.attr,
4581 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004582 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004583 NULL,
4584};
4585ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004587static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589static int __init scsi_debug_init(void)
4590{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004591 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 int host_to_add;
4593 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004594 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004596 atomic_set(&sdebug_cmnd_count, 0);
4597 atomic_set(&sdebug_completions, 0);
4598 atomic_set(&retired_max_queue, 0);
4599
Douglas Gilbert773642d2016-04-25 12:16:28 -04004600 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004601 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004602 sdebug_ndelay = 0;
4603 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04004604 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004605
Douglas Gilbert773642d2016-04-25 12:16:28 -04004606 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04004607 case 512:
4608 case 1024:
4609 case 2048:
4610 case 4096:
4611 break;
4612 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004613 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004614 return -EINVAL;
4615 }
4616
Douglas Gilbert773642d2016-04-25 12:16:28 -04004617 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004618
4619 case SD_DIF_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004620 break;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004621 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004622 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004623 case SD_DIF_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004624 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004625 break;
4626
4627 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004628 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004629 return -EINVAL;
4630 }
4631
Douglas Gilbert773642d2016-04-25 12:16:28 -04004632 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004633 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004634 return -EINVAL;
4635 }
4636
Douglas Gilbert773642d2016-04-25 12:16:28 -04004637 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004638 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004639 return -EINVAL;
4640 }
4641
Douglas Gilbert773642d2016-04-25 12:16:28 -04004642 if (sdebug_physblk_exp > 15) {
4643 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004644 return -EINVAL;
4645 }
4646
Douglas Gilbert773642d2016-04-25 12:16:28 -04004647 if (sdebug_lowest_aligned > 0x3fff) {
4648 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004649 return -EINVAL;
4650 }
4651
Douglas Gilbert773642d2016-04-25 12:16:28 -04004652 if (sdebug_dev_size_mb < 1)
4653 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4654 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4655 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004656 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657
4658 /* play around with geometry, don't waste too much on track 0 */
4659 sdebug_heads = 8;
4660 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004661 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004663 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02004664 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4666 (sdebug_sectors_per * sdebug_heads);
4667 if (sdebug_cylinders_per >= 1024) {
4668 /* other LLDs do this; implies >= 1GB ram disk ... */
4669 sdebug_heads = 255;
4670 sdebug_sectors_per = 63;
4671 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4672 (sdebug_sectors_per * sdebug_heads);
4673 }
4674
Douglas Gilbert773642d2016-04-25 12:16:28 -04004675 if (0 == sdebug_fake_rw) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004676 fake_storep = vmalloc(sz);
4677 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004678 pr_err("out of memory, 1\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004679 return -ENOMEM;
4680 }
4681 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004682 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004683 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685
Douglas Gilbert773642d2016-04-25 12:16:28 -04004686 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004687 int dif_size;
4688
4689 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4690 dif_storep = vmalloc(dif_size);
4691
Tomas Winklerc12879702015-07-28 16:54:20 +03004692 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004693
4694 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004695 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004696 ret = -ENOMEM;
4697 goto free_vm;
4698 }
4699
4700 memset(dif_storep, 0xff, dif_size);
4701 }
4702
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004703 /* Logical Block Provisioning */
4704 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004705 sdebug_unmap_max_blocks =
4706 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004707
Douglas Gilbert773642d2016-04-25 12:16:28 -04004708 sdebug_unmap_max_desc =
4709 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04004710
Douglas Gilbert773642d2016-04-25 12:16:28 -04004711 sdebug_unmap_granularity =
4712 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004713
Douglas Gilbert773642d2016-04-25 12:16:28 -04004714 if (sdebug_unmap_alignment &&
4715 sdebug_unmap_granularity <=
4716 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004717 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004718 return -EINVAL;
4719 }
4720
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004721 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4722 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004723
Tomas Winklerc12879702015-07-28 16:54:20 +03004724 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004725
4726 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004727 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004728 ret = -ENOMEM;
4729 goto free_vm;
4730 }
4731
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004732 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004733
4734 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004735 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004736 map_region(0, 2);
4737 }
4738
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004739 pseudo_primary = root_device_register("pseudo_0");
4740 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004741 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004742 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004743 goto free_vm;
4744 }
4745 ret = bus_register(&pseudo_lld_bus);
4746 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004747 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004748 goto dev_unreg;
4749 }
4750 ret = driver_register(&sdebug_driverfs_driver);
4751 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004752 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004753 goto bus_unreg;
4754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755
Douglas Gilbert773642d2016-04-25 12:16:28 -04004756 host_to_add = sdebug_add_host;
4757 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
4759 for (k = 0; k < host_to_add; k++) {
4760 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004761 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 break;
4763 }
4764 }
4765
Douglas Gilbert773642d2016-04-25 12:16:28 -04004766 if (sdebug_verbose)
4767 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03004768
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004770
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004771bus_unreg:
4772 bus_unregister(&pseudo_lld_bus);
4773dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004774 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004775free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03004776 vfree(map_storep);
4777 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004778 vfree(fake_storep);
4779
4780 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781}
4782
4783static void __exit scsi_debug_exit(void)
4784{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004785 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786
4787 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004788 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 for (; k; k--)
4790 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 driver_unregister(&sdebug_driverfs_driver);
4792 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004793 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794
Tomas Winklerde232af2015-07-28 16:54:22 +03004795 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 vfree(fake_storep);
4797}
4798
4799device_initcall(scsi_debug_init);
4800module_exit(scsi_debug_exit);
4801
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802static void sdebug_release_adapter(struct device * dev)
4803{
4804 struct sdebug_host_info *sdbg_host;
4805
4806 sdbg_host = to_sdebug_host(dev);
4807 kfree(sdbg_host);
4808}
4809
4810static int sdebug_add_adapter(void)
4811{
4812 int k, devs_per_host;
4813 int error = 0;
4814 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004815 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004817 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004819 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 return -ENOMEM;
4821 }
4822
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4824
Douglas Gilbert773642d2016-04-25 12:16:28 -04004825 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004827 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4828 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004829 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 error = -ENOMEM;
4831 goto clean;
4832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 }
4834
4835 spin_lock(&sdebug_host_list_lock);
4836 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4837 spin_unlock(&sdebug_host_list_lock);
4838
4839 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004840 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004842 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843
4844 error = device_register(&sdbg_host->dev);
4845
4846 if (error)
4847 goto clean;
4848
Douglas Gilbert773642d2016-04-25 12:16:28 -04004849 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 return error;
4851
4852clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09004853 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4854 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 list_del(&sdbg_devinfo->dev_list);
4856 kfree(sdbg_devinfo);
4857 }
4858
4859 kfree(sdbg_host);
4860 return error;
4861}
4862
4863static void sdebug_remove_adapter(void)
4864{
4865 struct sdebug_host_info * sdbg_host = NULL;
4866
4867 spin_lock(&sdebug_host_list_lock);
4868 if (!list_empty(&sdebug_host_list)) {
4869 sdbg_host = list_entry(sdebug_host_list.prev,
4870 struct sdebug_host_info, host_list);
4871 list_del(&sdbg_host->host_list);
4872 }
4873 spin_unlock(&sdebug_host_list_lock);
4874
4875 if (!sdbg_host)
4876 return;
4877
Douglas Gilbert773642d2016-04-25 12:16:28 -04004878 device_unregister(&sdbg_host->dev);
4879 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880}
4881
Douglas Gilbertfd321192016-04-25 12:16:33 -04004882static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004883{
4884 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004885 unsigned long iflags;
4886 struct sdebug_dev_info *devip;
4887
4888 spin_lock_irqsave(&queued_arr_lock, iflags);
4889 devip = (struct sdebug_dev_info *)sdev->hostdata;
4890 if (NULL == devip) {
4891 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4892 return -ENODEV;
4893 }
4894 num_in_q = atomic_read(&devip->num_in_q);
4895 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004896
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004897 if (qdepth < 1)
4898 qdepth = 1;
4899 /* allow to exceed max host queued_arr elements for testing */
4900 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4901 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004902 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004903
Douglas Gilbert773642d2016-04-25 12:16:28 -04004904 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004905 sdev_printk(KERN_INFO, sdev,
4906 "%s: qdepth=%d, num_in_q=%d\n",
4907 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004908 }
4909 return sdev->queue_depth;
4910}
4911
Douglas Gilbertfd321192016-04-25 12:16:33 -04004912static int check_inject(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004913{
4914 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4915
4916 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4917
Douglas Gilbert773642d2016-04-25 12:16:28 -04004918 if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
Douglas Gilbert817fd662014-11-24 20:18:02 -05004919 atomic_set(&sdebug_cmnd_count, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004920 if (sdebug_every_nth < -1)
4921 sdebug_every_nth = -1;
4922 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004923 return 1; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004924 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05004925 scsi_medium_access_command(scp))
4926 return 1; /* time out reads and writes */
4927 if (sdebug_any_injecting_opt) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004928 if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004929 ep->inj_recovered = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004930 if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004931 ep->inj_transport = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004932 if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004933 ep->inj_dif = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004934 if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004935 ep->inj_dix = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004936 if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004937 ep->inj_short = true;
4938 }
4939 }
4940 return 0;
4941}
4942
Douglas Gilbertfd321192016-04-25 12:16:33 -04004943static int scsi_debug_queuecommand(struct Scsi_Host *shost,
4944 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004945{
4946 u8 sdeb_i;
4947 struct scsi_device *sdp = scp->device;
4948 const struct opcode_info_t *oip;
4949 const struct opcode_info_t *r_oip;
4950 struct sdebug_dev_info *devip;
4951 u8 *cmd = scp->cmnd;
4952 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
4953 int k, na;
4954 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004955 u32 flags;
4956 u16 sa;
4957 u8 opcode = cmd[0];
4958 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004959
4960 scsi_set_resid(scp, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004961 if (unlikely(sdebug_verbose &&
4962 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004963 char b[120];
4964 int n, len, sb;
4965
4966 len = scp->cmd_len;
4967 sb = (int)sizeof(b);
4968 if (len > 32)
4969 strcpy(b, "too long, over 32 bytes");
4970 else {
4971 for (k = 0, n = 0; k < len && n < sb; ++k)
4972 n += scnprintf(b + n, sb - n, "%02x ",
4973 (u32)cmd[k]);
4974 }
4975 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
4976 }
Tomas Winkler34d55432015-07-28 16:54:21 +03004977 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004978 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
4979 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004980
4981 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
4982 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
4983 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004984 if (unlikely(!devip)) {
4985 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004986 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004987 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004988 }
4989 na = oip->num_attached;
4990 r_pfp = oip->pfp;
4991 if (na) { /* multiple commands with this opcode */
4992 r_oip = oip;
4993 if (FF_SA & r_oip->flags) {
4994 if (F_SA_LOW & oip->flags)
4995 sa = 0x1f & cmd[1];
4996 else
4997 sa = get_unaligned_be16(cmd + 8);
4998 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
4999 if (opcode == oip->opcode && sa == oip->sa)
5000 break;
5001 }
5002 } else { /* since no service action only check opcode */
5003 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5004 if (opcode == oip->opcode)
5005 break;
5006 }
5007 }
5008 if (k > na) {
5009 if (F_SA_LOW & r_oip->flags)
5010 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5011 else if (F_SA_HIGH & r_oip->flags)
5012 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5013 else
5014 mk_sense_invalid_opcode(scp);
5015 goto check_cond;
5016 }
5017 } /* else (when na==0) we assume the oip is a match */
5018 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005019 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005020 mk_sense_invalid_opcode(scp);
5021 goto check_cond;
5022 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005023 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005024 if (sdebug_verbose)
5025 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5026 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005027 mk_sense_invalid_opcode(scp);
5028 goto check_cond;
5029 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005030 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005031 u8 rem;
5032 int j;
5033
5034 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5035 rem = ~oip->len_mask[k] & cmd[k];
5036 if (rem) {
5037 for (j = 7; j >= 0; --j, rem <<= 1) {
5038 if (0x80 & rem)
5039 break;
5040 }
5041 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5042 goto check_cond;
5043 }
5044 }
5045 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005046 if (unlikely(!(F_SKIP_UA & flags) &&
5047 SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm,
5048 SDEBUG_NUM_UAS))) {
5049 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005050 if (errsts)
5051 goto check_cond;
5052 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005053 if (unlikely((F_M_ACCESS & flags) && devip->stopped)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005054 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005055 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005056 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5057 "%s\n", my_name, "initializing command "
5058 "required");
5059 errsts = check_condition_result;
5060 goto fini;
5061 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005062 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005063 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005064 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005065 if (check_inject(scp))
5066 return 0; /* ignore command: make trouble */
5067 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005068 if (likely(oip->pfp))
5069 errsts = oip->pfp(scp, devip); /* calls a resp_* function */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005070 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5071 errsts = r_pfp(scp, devip);
5072
5073fini:
5074 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005075 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005076check_cond:
5077 return schedule_resp(scp, devip, check_condition_result, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005078err_out:
5079 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005080}
5081
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005082static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005083 .show_info = scsi_debug_show_info,
5084 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005085 .proc_name = sdebug_proc_name,
5086 .name = "SCSI DEBUG",
5087 .info = scsi_debug_info,
5088 .slave_alloc = scsi_debug_slave_alloc,
5089 .slave_configure = scsi_debug_slave_configure,
5090 .slave_destroy = scsi_debug_slave_destroy,
5091 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005092 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005093 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005094 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005095 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005096 .eh_target_reset_handler = scsi_debug_target_reset,
5097 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005098 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005099 .can_queue = SCSI_DEBUG_CANQUEUE,
5100 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005101 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005102 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005103 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005104 .use_clustering = DISABLE_CLUSTERING,
5105 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005106 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05005107 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005108};
5109
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110static int sdebug_driver_probe(struct device * dev)
5111{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005112 int error = 0;
5113 struct sdebug_host_info *sdbg_host;
5114 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005115 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116
5117 sdbg_host = to_sdebug_host(dev);
5118
Douglas Gilbert773642d2016-04-25 12:16:28 -04005119 sdebug_driver_template.can_queue = sdebug_max_queue;
5120 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005121 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005122 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5123 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005124 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005125 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128
5129 sdbg_host->shost = hpnt;
5130 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005131 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5132 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005134 hpnt->max_id = sdebug_num_tgts;
5135 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005136 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005138 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005139
Douglas Gilbert773642d2016-04-25 12:16:28 -04005140 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005141
5142 case SD_DIF_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005143 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005144 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005145 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005146 break;
5147
5148 case SD_DIF_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005149 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005150 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005151 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005152 break;
5153
5154 case SD_DIF_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005155 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005156 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005157 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005158 break;
5159
5160 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005161 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005162 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005163 break;
5164 }
5165
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005166 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005167
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005168 if (have_dif_prot || sdebug_dix)
5169 pr_info("host protection%s%s%s%s%s%s%s\n",
5170 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5171 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5172 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5173 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5174 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5175 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5176 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005177
Douglas Gilbert773642d2016-04-25 12:16:28 -04005178 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005179 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5180 else
5181 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5182
Douglas Gilbert773642d2016-04-25 12:16:28 -04005183 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5184 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 error = scsi_add_host(hpnt, &sdbg_host->dev);
5186 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005187 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 error = -ENODEV;
5189 scsi_host_put(hpnt);
5190 } else
5191 scsi_scan_host(hpnt);
5192
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005193 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194}
5195
5196static int sdebug_driver_remove(struct device * dev)
5197{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005199 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200
5201 sdbg_host = to_sdebug_host(dev);
5202
5203 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005204 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 return -ENODEV;
5206 }
5207
5208 scsi_remove_host(sdbg_host->shost);
5209
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005210 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5211 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 list_del(&sdbg_devinfo->dev_list);
5213 kfree(sdbg_devinfo);
5214 }
5215
5216 scsi_host_put(sdbg_host->shost);
5217 return 0;
5218}
5219
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005220static int pseudo_lld_bus_match(struct device *dev,
5221 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005223 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005225
5226static struct bus_type pseudo_lld_bus = {
5227 .name = "pseudo",
5228 .match = pseudo_lld_bus_match,
5229 .probe = sdebug_driver_probe,
5230 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005231 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005232};