blob: f952803ea9668455a8285c7b7bc8d942523754ba [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
193/* for check_readiness() */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500194#define UAS_ONLY 1 /* check for UAs only */
195#define UAS_TUR 0 /* if no UAs then check if media access possible */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400196
Douglas Gilbert773642d2016-04-25 12:16:28 -0400197/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 * sector on read commands: */
199#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500200#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
203 * or "peripheral device" addressing (value 0) */
204#define SAM2_LUN_ADDRESS_METHOD 0
205
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400206/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
207 * (for response) at one time. Can be reduced by max_queue option. Command
Douglas Gilbertc2206092016-04-25 12:16:31 -0400208 * responses are not queued when jdelay=0 and ndelay=0. The per-device
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400209 * DEF_CMD_PER_LUN can be changed via sysfs:
210 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
211 * SCSI_DEBUG_CANQUEUE. */
212#define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */
213#define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
214#define DEF_CMD_PER_LUN 255
215
216#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
217#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
218#endif
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400219
Douglas Gilbertfd321192016-04-25 12:16:33 -0400220#define F_D_IN 1
221#define F_D_OUT 2
222#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
223#define F_D_UNKN 8
224#define F_RL_WLUN_OK 0x10
225#define F_SKIP_UA 0x20
226#define F_DELAY_OVERR 0x40
227#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
228#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
229#define F_INV_OP 0x200
230#define F_FAKE_RW 0x400
231#define F_M_ACCESS 0x800 /* media access */
232
233#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
234#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
235#define FF_SA (F_SA_HIGH | F_SA_LOW)
236
237#define SDEBUG_MAX_PARTS 4
238
239#define SCSI_DEBUG_MAX_CMD_LEN 32
240
241
242struct sdebug_dev_info {
243 struct list_head dev_list;
244 unsigned int channel;
245 unsigned int target;
246 u64 lun;
247 struct sdebug_host_info *sdbg_host;
248 unsigned long uas_bm[1];
249 atomic_t num_in_q;
250 char stopped; /* TODO: should be atomic */
251 bool used;
252};
253
254struct sdebug_host_info {
255 struct list_head host_list;
256 struct Scsi_Host *shost;
257 struct device dev;
258 struct list_head dev_info_list;
259};
260
261#define to_sdebug_host(d) \
262 container_of(d, struct sdebug_host_info, dev)
263
264struct sdebug_defer {
265 struct hrtimer hrt;
266 struct execute_work ew;
267 int qa_indx;
268};
269
270struct sdebug_queued_cmd {
271 /* in_use flagged by a bit in queued_in_use_bm[] */
272 struct sdebug_defer *sd_dp;
273 struct scsi_cmnd *a_cmnd;
274};
275
276struct sdebug_scmd_extra_t {
277 bool inj_recovered;
278 bool inj_transport;
279 bool inj_dif;
280 bool inj_dix;
281 bool inj_short;
282};
283
284struct opcode_info_t {
285 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff
286 * for terminating element */
287 u8 opcode; /* if num_attached > 0, preferred */
288 u16 sa; /* service action */
289 u32 flags; /* OR-ed set of SDEB_F_* */
290 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
291 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
292 u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
293 /* ignore cdb bytes after position 15 */
294};
295
296/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500297enum sdeb_opcode_index {
298 SDEB_I_INVALID_OPCODE = 0,
299 SDEB_I_INQUIRY = 1,
300 SDEB_I_REPORT_LUNS = 2,
301 SDEB_I_REQUEST_SENSE = 3,
302 SDEB_I_TEST_UNIT_READY = 4,
303 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
304 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
305 SDEB_I_LOG_SENSE = 7,
306 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
307 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
308 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
309 SDEB_I_START_STOP = 11,
310 SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
311 SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
312 SDEB_I_MAINT_IN = 14,
313 SDEB_I_MAINT_OUT = 15,
314 SDEB_I_VERIFY = 16, /* 10 only */
315 SDEB_I_VARIABLE_LEN = 17,
316 SDEB_I_RESERVE = 18, /* 6, 10 */
317 SDEB_I_RELEASE = 19, /* 6, 10 */
318 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
319 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
320 SDEB_I_ATA_PT = 22, /* 12, 16 */
321 SDEB_I_SEND_DIAG = 23,
322 SDEB_I_UNMAP = 24,
323 SDEB_I_XDWRITEREAD = 25, /* 10 only */
324 SDEB_I_WRITE_BUFFER = 26,
325 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
326 SDEB_I_SYNC_CACHE = 28, /* 10 only */
327 SDEB_I_COMP_WRITE = 29,
328 SDEB_I_LAST_ELEMENT = 30, /* keep this last */
329};
330
331static const unsigned char opcode_ind_arr[256] = {
332/* 0x0; 0x0->0x1f: 6 byte cdbs */
333 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
334 0, 0, 0, 0,
335 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
336 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
337 SDEB_I_RELEASE,
338 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
339 SDEB_I_ALLOW_REMOVAL, 0,
340/* 0x20; 0x20->0x3f: 10 byte cdbs */
341 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
342 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
343 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
344 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
345/* 0x40; 0x40->0x5f: 10 byte cdbs */
346 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
347 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
348 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
349 SDEB_I_RELEASE,
350 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400351/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
354 0, SDEB_I_VARIABLE_LEN,
355/* 0x80; 0x80->0x9f: 16 byte cdbs */
356 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
357 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
358 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
359 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
360/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
361 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
362 SDEB_I_MAINT_OUT, 0, 0, 0,
363 SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
364 0, 0, 0, 0,
365 0, 0, 0, 0, 0, 0, 0, 0,
366 0, 0, 0, 0, 0, 0, 0, 0,
367/* 0xc0; 0xc0->0xff: vendor specific */
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
372};
373
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500374static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
375static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
376static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
377static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
378static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
379static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
380static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
381static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
382static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
383static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
384static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
385static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
386static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
387static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500388static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
389static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500390static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
391static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
392static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500393static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500394static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500395
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500396static const struct opcode_info_t msense_iarr[1] = {
397 {0, 0x1a, 0, F_D_IN, NULL, NULL,
398 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
399};
400
401static const struct opcode_info_t mselect_iarr[1] = {
402 {0, 0x15, 0, F_D_OUT, NULL, NULL,
403 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
404};
405
406static const struct opcode_info_t read_iarr[3] = {
407 {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
408 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
409 0, 0, 0, 0} },
410 {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
411 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
412 {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
413 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
414 0xc7, 0, 0, 0, 0} },
415};
416
417static const struct opcode_info_t write_iarr[3] = {
418 {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
419 {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
420 0, 0, 0, 0} },
421 {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
422 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
423 {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
424 {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
425 0xc7, 0, 0, 0, 0} },
426};
427
428static const struct opcode_info_t sa_in_iarr[1] = {
429 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
430 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
431 0xff, 0xff, 0xff, 0, 0xc7} },
432};
433
434static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
435 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
436 NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
437 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
438};
439
440static const struct opcode_info_t maint_in_iarr[2] = {
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500441 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500442 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
443 0xc7, 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500444 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500445 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
446 0, 0} },
447};
448
449static const struct opcode_info_t write_same_iarr[1] = {
450 {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
451 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
452 0xff, 0xff, 0xff, 0x1f, 0xc7} },
453};
454
455static const struct opcode_info_t reserve_iarr[1] = {
456 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
457 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
458};
459
460static const struct opcode_info_t release_iarr[1] = {
461 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
462 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
463};
464
465
466/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
467 * plus the terminating elements for logic that scans this table such as
468 * REPORT SUPPORTED OPERATION CODES. */
469static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
470/* 0 */
471 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
472 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
473 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
474 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
475 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
476 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
477 0, 0} },
478 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
479 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
480 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
481 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
482 {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
483 {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
484 0} },
485 {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
486 {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
487 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
488 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
489 0, 0, 0} },
490 {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
491 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
492 0, 0} },
493 {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
494 {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
495 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */
496/* 10 */
497 {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
498 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
499 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */
500 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
501 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
502 {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
503 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
504 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
505 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
506 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
507 {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
508 {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
509 0} },
510 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
511 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500512 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
513 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
514 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500515 {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
516 vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
517 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
518 {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
519 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
520 0} },
521 {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
522 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
523 0} },
524/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500525 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
526 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500527 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
528 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
529 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
530 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
531 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
532 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
533 {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
534 {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
535 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
536 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
537 0, 0, 0, 0, 0, 0} },
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500538 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
539 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
540 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500541 {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
542 write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
543 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
544 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
545 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
546 0, 0, 0, 0} },
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500547 {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500548 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
549 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
550
551/* 30 */
552 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
553 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
554};
555
Douglas Gilbert773642d2016-04-25 12:16:28 -0400556static int sdebug_add_host = DEF_NUM_HOST;
557static int sdebug_ato = DEF_ATO;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400558static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400559static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
560static int sdebug_dif = DEF_DIF;
561static int sdebug_dix = DEF_DIX;
562static int sdebug_dsense = DEF_D_SENSE;
563static int sdebug_every_nth = DEF_EVERY_NTH;
564static int sdebug_fake_rw = DEF_FAKE_RW;
565static unsigned int sdebug_guard = DEF_GUARD;
566static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
567static int sdebug_max_luns = DEF_MAX_LUNS;
568static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400569static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400570static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400571static int sdebug_no_lun_0 = DEF_NO_LUN_0;
572static int sdebug_no_uld;
573static int sdebug_num_parts = DEF_NUM_PARTS;
574static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
575static int sdebug_opt_blks = DEF_OPT_BLKS;
576static int sdebug_opts = DEF_OPTS;
577static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
578static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
579static int sdebug_scsi_level = DEF_SCSI_LEVEL;
580static int sdebug_sector_size = DEF_SECTOR_SIZE;
581static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
582static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
583static unsigned int sdebug_lbpu = DEF_LBPU;
584static unsigned int sdebug_lbpws = DEF_LBPWS;
585static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
586static unsigned int sdebug_lbprz = DEF_LBPRZ;
587static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
588static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
589static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
590static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
591static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
592static bool sdebug_removable = DEF_REMOVABLE;
593static bool sdebug_clustering;
594static bool sdebug_host_lock = DEF_HOST_LOCK;
595static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500596static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400597static bool sdebug_verbose;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400599static atomic_t sdebug_cmnd_count;
600static atomic_t sdebug_completions;
601static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400603static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604static sector_t sdebug_capacity; /* in sectors */
605
606/* old BIOS stuff, kernel may get rid of them but some mode sense pages
607 may still need them */
608static int sdebug_heads; /* heads per disk */
609static int sdebug_cylinders_per; /* cylinders per surface */
610static int sdebug_sectors_per; /* sectors per cylinder */
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612static LIST_HEAD(sdebug_host_list);
613static DEFINE_SPINLOCK(sdebug_host_list_lock);
614
Douglas Gilbertfd321192016-04-25 12:16:33 -0400615static unsigned char *fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900616static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400617static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Martin K. Petersen44d92692009-10-15 14:45:27 -0400619static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400620static int num_aborts;
621static int num_dev_resets;
622static int num_target_resets;
623static int num_bus_resets;
624static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500625static int dix_writes;
626static int dix_reads;
627static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
Douglas Gilbertfd321192016-04-25 12:16:33 -0400629static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
630static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632static DEFINE_SPINLOCK(queued_arr_lock);
633static DEFINE_RWLOCK(atomic_rw);
634
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400635static char sdebug_proc_name[] = MY_NAME;
636static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638static struct bus_type pseudo_lld_bus;
639
640static struct device_driver sdebug_driverfs_driver = {
641 .name = sdebug_proc_name,
642 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643};
644
645static const int check_condition_result =
646 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
647
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500648static const int illegal_condition_result =
649 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
650
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400651static const int device_qfull_result =
652 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
653
Douglas Gilbertfd321192016-04-25 12:16:33 -0400654
655static unsigned int scsi_debug_lbp(void)
656{
657 return 0 == sdebug_fake_rw &&
658 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
659}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400660
Akinobu Mita14faa942013-09-18 21:27:24 +0900661static void *fake_store(unsigned long long lba)
662{
663 lba = do_div(lba, sdebug_store_sectors);
664
Douglas Gilbert773642d2016-04-25 12:16:28 -0400665 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900666}
667
668static struct sd_dif_tuple *dif_store(sector_t sector)
669{
Arnd Bergmann49413112015-11-20 17:38:28 +0100670 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900671
672 return dif_storep + sector;
673}
674
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900675static void sdebug_max_tgts_luns(void)
676{
677 struct sdebug_host_info *sdbg_host;
678 struct Scsi_Host *hpnt;
679
680 spin_lock(&sdebug_host_list_lock);
681 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
682 hpnt = sdbg_host->shost;
683 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400684 (sdebug_num_tgts > hpnt->this_id))
685 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900686 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400687 hpnt->max_id = sdebug_num_tgts;
688 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300689 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900690 }
691 spin_unlock(&sdebug_host_list_lock);
692}
693
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500694enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
695
696/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400697static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
698 enum sdeb_cmd_data c_d,
699 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500700{
701 unsigned char *sbuff;
702 u8 sks[4];
703 int sl, asc;
704
705 sbuff = scp->sense_buffer;
706 if (!sbuff) {
707 sdev_printk(KERN_ERR, scp->device,
708 "%s: sense_buffer is NULL\n", __func__);
709 return;
710 }
711 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
712 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400713 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500714 memset(sks, 0, sizeof(sks));
715 sks[0] = 0x80;
716 if (c_d)
717 sks[0] |= 0x40;
718 if (in_bit >= 0) {
719 sks[0] |= 0x8;
720 sks[0] |= 0x7 & in_bit;
721 }
722 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400723 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500724 sl = sbuff[7] + 8;
725 sbuff[7] = sl;
726 sbuff[sl] = 0x2;
727 sbuff[sl + 1] = 0x6;
728 memcpy(sbuff + sl + 4, sks, 3);
729 } else
730 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400731 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500732 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
733 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
734 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
735}
736
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400737static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900738{
739 unsigned char *sbuff;
740
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400741 sbuff = scp->sense_buffer;
742 if (!sbuff) {
743 sdev_printk(KERN_ERR, scp->device,
744 "%s: sense_buffer is NULL\n", __func__);
745 return;
746 }
747 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900748
Douglas Gilbert773642d2016-04-25 12:16:28 -0400749 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900750
Douglas Gilbert773642d2016-04-25 12:16:28 -0400751 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400752 sdev_printk(KERN_INFO, scp->device,
753 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
754 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900755}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Douglas Gilbertfd321192016-04-25 12:16:33 -0400757static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500758{
759 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
760}
761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
763{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400764 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400765 if (0x1261 == cmd)
766 sdev_printk(KERN_INFO, dev,
767 "%s: BLKFLSBUF [0x1261]\n", __func__);
768 else if (0x5331 == cmd)
769 sdev_printk(KERN_INFO, dev,
770 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
771 __func__);
772 else
773 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
774 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776 return -EINVAL;
777 /* return -ENOTTY; // correct return but upsets fdisk */
778}
779
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500780static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
781{
782 struct sdebug_host_info *sdhp;
783 struct sdebug_dev_info *dp;
784
785 spin_lock(&sdebug_host_list_lock);
786 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
787 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
788 if ((devip->sdbg_host == dp->sdbg_host) &&
789 (devip->target == dp->target))
790 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
791 }
792 }
793 spin_unlock(&sdebug_host_list_lock);
794}
795
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400796static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400797 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400799 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400800
801 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
802 if (k != SDEBUG_NUM_UAS) {
803 const char *cp = NULL;
804
805 switch (k) {
806 case SDEBUG_UA_POR:
807 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
808 UA_RESET_ASC, POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400809 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400810 cp = "power on reset";
811 break;
812 case SDEBUG_UA_BUS_RESET:
813 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
814 UA_RESET_ASC, BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400815 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400816 cp = "bus reset";
817 break;
818 case SDEBUG_UA_MODE_CHANGED:
819 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
820 UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400821 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400822 cp = "mode parameters changed";
823 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500824 case SDEBUG_UA_CAPACITY_CHANGED:
825 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
826 UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400827 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500828 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500829 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500830 case SDEBUG_UA_MICROCODE_CHANGED:
831 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
832 TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400833 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500834 cp = "microcode has been changed";
835 break;
836 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
837 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
838 TARGET_CHANGED_ASC,
839 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400840 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500841 cp = "microcode has been changed without reset";
842 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500843 case SDEBUG_UA_LUNS_CHANGED:
844 /*
845 * SPC-3 behavior is to report a UNIT ATTENTION with
846 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
847 * on the target, until a REPORT LUNS command is
848 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400849 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500850 * values as struct scsi_device->scsi_level.
851 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400852 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500853 clear_luns_changed_on_target(devip);
854 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
855 TARGET_CHANGED_ASC,
856 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400857 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500858 cp = "reported luns data has changed";
859 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400860 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400861 pr_warn("unexpected unit attention code=%d\n", k);
862 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400863 cp = "unknown";
864 break;
865 }
866 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400867 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400868 sdev_printk(KERN_INFO, SCpnt->device,
869 "%s reports: Unit attention: %s\n",
870 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 return check_condition_result;
872 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400873 if ((UAS_TUR == uas_only) && devip->stopped) {
874 mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400875 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400876 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400877 sdev_printk(KERN_INFO, SCpnt->device,
878 "%s reports: Not ready: %s\n", my_name,
879 "initializing command required");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400880 return check_condition_result;
881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return 0;
883}
884
885/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900886static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 int arr_len)
888{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900889 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900890 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900892 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900894 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Douglas Gilbert773642d2016-04-25 12:16:28 -0400895 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900896
897 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
898 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700899 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return 0;
902}
903
904/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900905static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
906 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900908 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900910 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900912
913 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914}
915
916
917static const char * inq_vendor_id = "Linux ";
918static const char * inq_product_id = "scsi_debug ";
Douglas Gilbert773642d2016-04-25 12:16:28 -0400919static const char *inq_product_rev = "0186"; /* version less '.' */
920static const u64 naa5_comp_a = 0x5222222000000000ULL;
921static const u64 naa5_comp_b = 0x5333333000000000ULL;
922static const u64 naa5_comp_c = 0x5111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400924/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200925static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
926 int target_dev_id, int dev_id_num,
927 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400928 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400930 int num, port_a;
931 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400933 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 /* T10 vendor identifier field format (faked) */
935 arr[0] = 0x2; /* ASCII */
936 arr[1] = 0x1;
937 arr[2] = 0x0;
938 memcpy(&arr[4], inq_vendor_id, 8);
939 memcpy(&arr[12], inq_product_id, 16);
940 memcpy(&arr[28], dev_id_str, dev_id_str_len);
941 num = 8 + 16 + dev_id_str_len;
942 arr[3] = num;
943 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400944 if (dev_id_num >= 0) {
945 /* NAA-5, Logical unit identifier (binary) */
946 arr[num++] = 0x1; /* binary (not necessarily sas) */
947 arr[num++] = 0x3; /* PIV=0, lu, naa */
948 arr[num++] = 0x0;
949 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400950 put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num);
951 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400952 /* Target relative port number */
953 arr[num++] = 0x61; /* proto=sas, binary */
954 arr[num++] = 0x94; /* PIV=1, target port, rel port */
955 arr[num++] = 0x0; /* reserved */
956 arr[num++] = 0x4; /* length */
957 arr[num++] = 0x0; /* reserved */
958 arr[num++] = 0x0; /* reserved */
959 arr[num++] = 0x0;
960 arr[num++] = 0x1; /* relative port A */
961 }
962 /* NAA-5, Target port identifier */
963 arr[num++] = 0x61; /* proto=sas, binary */
964 arr[num++] = 0x93; /* piv=1, target port, naa */
965 arr[num++] = 0x0;
966 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400967 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
968 num += 8;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200969 /* NAA-5, Target port group identifier */
970 arr[num++] = 0x61; /* proto=sas, binary */
971 arr[num++] = 0x95; /* piv=1, target port group id */
972 arr[num++] = 0x0;
973 arr[num++] = 0x4;
974 arr[num++] = 0;
975 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400976 put_unaligned_be16(port_group_id, arr + num);
977 num += 2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400978 /* NAA-5, Target device identifier */
979 arr[num++] = 0x61; /* proto=sas, binary */
980 arr[num++] = 0xa3; /* piv=1, target device, naa */
981 arr[num++] = 0x0;
982 arr[num++] = 0x8;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400983 put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num);
984 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400985 /* SCSI name string: Target device identifier */
986 arr[num++] = 0x63; /* proto=sas, UTF-8 */
987 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
988 arr[num++] = 0x0;
989 arr[num++] = 24;
990 memcpy(arr + num, "naa.52222220", 12);
991 num += 12;
992 snprintf(b, sizeof(b), "%08X", target_dev_id);
993 memcpy(arr + num, b, 8);
994 num += 8;
995 memset(arr + num, 0, 4);
996 num += 4;
997 return num;
998}
999
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001000static unsigned char vpd84_data[] = {
1001/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1002 0x22,0x22,0x22,0x0,0xbb,0x1,
1003 0x22,0x22,0x22,0x0,0xbb,0x2,
1004};
1005
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001006/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001007static int inquiry_evpd_84(unsigned char * arr)
1008{
1009 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1010 return sizeof(vpd84_data);
1011}
1012
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001013/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001014static int inquiry_evpd_85(unsigned char * arr)
1015{
1016 int num = 0;
1017 const char * na1 = "https://www.kernel.org/config";
1018 const char * na2 = "http://www.kernel.org/log";
1019 int plen, olen;
1020
1021 arr[num++] = 0x1; /* lu, storage config */
1022 arr[num++] = 0x0; /* reserved */
1023 arr[num++] = 0x0;
1024 olen = strlen(na1);
1025 plen = olen + 1;
1026 if (plen % 4)
1027 plen = ((plen / 4) + 1) * 4;
1028 arr[num++] = plen; /* length, null termianted, padded */
1029 memcpy(arr + num, na1, olen);
1030 memset(arr + num + olen, 0, plen - olen);
1031 num += plen;
1032
1033 arr[num++] = 0x4; /* lu, logging */
1034 arr[num++] = 0x0; /* reserved */
1035 arr[num++] = 0x0;
1036 olen = strlen(na2);
1037 plen = olen + 1;
1038 if (plen % 4)
1039 plen = ((plen / 4) + 1) * 4;
1040 arr[num++] = plen; /* length, null terminated, padded */
1041 memcpy(arr + num, na2, olen);
1042 memset(arr + num + olen, 0, plen - olen);
1043 num += plen;
1044
1045 return num;
1046}
1047
1048/* SCSI ports VPD page */
1049static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1050{
1051 int num = 0;
1052 int port_a, port_b;
1053
1054 port_a = target_dev_id + 1;
1055 port_b = port_a + 1;
1056 arr[num++] = 0x0; /* reserved */
1057 arr[num++] = 0x0; /* reserved */
1058 arr[num++] = 0x0;
1059 arr[num++] = 0x1; /* relative port 1 (primary) */
1060 memset(arr + num, 0, 6);
1061 num += 6;
1062 arr[num++] = 0x0;
1063 arr[num++] = 12; /* length tp descriptor */
1064 /* naa-5 target port identifier (A) */
1065 arr[num++] = 0x61; /* proto=sas, binary */
1066 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1067 arr[num++] = 0x0; /* reserved */
1068 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001069 put_unaligned_be64(naa5_comp_a + port_a, arr + num);
1070 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001071 arr[num++] = 0x0; /* reserved */
1072 arr[num++] = 0x0; /* reserved */
1073 arr[num++] = 0x0;
1074 arr[num++] = 0x2; /* relative port 2 (secondary) */
1075 memset(arr + num, 0, 6);
1076 num += 6;
1077 arr[num++] = 0x0;
1078 arr[num++] = 12; /* length tp descriptor */
1079 /* naa-5 target port identifier (B) */
1080 arr[num++] = 0x61; /* proto=sas, binary */
1081 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1082 arr[num++] = 0x0; /* reserved */
1083 arr[num++] = 0x8; /* length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001084 put_unaligned_be64(naa5_comp_a + port_b, arr + num);
1085 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001086
1087 return num;
1088}
1089
1090
1091static unsigned char vpd89_data[] = {
1092/* from 4th byte */ 0,0,0,0,
1093'l','i','n','u','x',' ',' ',' ',
1094'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1095'1','2','3','4',
10960x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
10970xec,0,0,0,
10980x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
10990,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
11000x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
11010x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
11020x53,0x41,
11030x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11040x20,0x20,
11050x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
11060x10,0x80,
11070,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
11080x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
11090x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
11100,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
11110x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
11120x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11130,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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,
11170x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11180,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11190xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11200,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
11210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11270,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11320,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1133};
1134
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001135/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001136static int inquiry_evpd_89(unsigned char * arr)
1137{
1138 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1139 return sizeof(vpd89_data);
1140}
1141
1142
1143static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001144 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1145 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1146 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1147 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001148};
1149
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001150/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001151static int inquiry_evpd_b0(unsigned char * arr)
1152{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001153 unsigned int gran;
1154
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001155 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001156
1157 /* Optimal transfer length granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001158 gran = 1 << sdebug_physblk_exp;
1159 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001160
1161 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001162 if (sdebug_store_sectors > 0x400)
1163 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001164
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001165 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001166 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001167
Douglas Gilbert773642d2016-04-25 12:16:28 -04001168 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001169 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001170 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001171
1172 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001173 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001174 }
1175
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001176 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001177 if (sdebug_unmap_alignment) {
1178 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001179 arr[28] |= 0x80; /* UGAVALID */
1180 }
1181
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001182 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001183 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001184
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001185 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001186 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001187
1188 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001189
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001190 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191}
1192
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001193/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001194static int inquiry_evpd_b1(unsigned char *arr)
1195{
1196 memset(arr, 0, 0x3c);
1197 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001198 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1199 arr[2] = 0;
1200 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001201
1202 return 0x3c;
1203}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001205/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001206static int inquiry_evpd_b2(unsigned char *arr)
1207{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001208 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001209 arr[0] = 0; /* threshold exponent */
1210
Douglas Gilbert773642d2016-04-25 12:16:28 -04001211 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001212 arr[1] = 1 << 7;
1213
Douglas Gilbert773642d2016-04-25 12:16:28 -04001214 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001215 arr[1] |= 1 << 6;
1216
Douglas Gilbert773642d2016-04-25 12:16:28 -04001217 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001218 arr[1] |= 1 << 5;
1219
Douglas Gilbert773642d2016-04-25 12:16:28 -04001220 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001221 arr[1] |= 1 << 2;
1222
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001223 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001224}
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001227#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001229static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230{
1231 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001232 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001233 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001234 int alloc_len, n, ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001235 bool have_wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Douglas Gilbert773642d2016-04-25 12:16:28 -04001237 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001238 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1239 if (! arr)
1240 return DID_REQUEUE << 16;
Tomas Winkler34d55432015-07-28 16:54:21 +03001241 have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001242 if (have_wlun)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001243 pq_pdt = 0x1e; /* present, wlun */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001244 else if (sdebug_no_lun_0 && (0 == devip->lun))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001245 pq_pdt = 0x7f; /* not present, no device type */
1246 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001247 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 arr[0] = pq_pdt;
1249 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001250 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001251 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 return check_condition_result;
1253 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001254 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001255 char lu_id_str[6];
1256 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001258 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1259 (devip->channel & 0x7f);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001260 if (0 == sdebug_vpd_use_hostno)
Douglas Gilbert23183912006-09-16 20:30:47 -04001261 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001262 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001263 (devip->target * 1000) + devip->lun);
1264 target_dev_id = ((host_no + 1) * 2000) +
1265 (devip->target * 1000) - 3;
1266 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001268 arr[1] = cmd[2]; /*sanity */
1269 n = 4;
1270 arr[n++] = 0x0; /* this page */
1271 arr[n++] = 0x80; /* unit serial number */
1272 arr[n++] = 0x83; /* device identification */
1273 arr[n++] = 0x84; /* software interface ident. */
1274 arr[n++] = 0x85; /* management network addresses */
1275 arr[n++] = 0x86; /* extended inquiry */
1276 arr[n++] = 0x87; /* mode page policy */
1277 arr[n++] = 0x88; /* SCSI ports */
1278 arr[n++] = 0x89; /* ATA information */
1279 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001280 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001281 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
1282 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001283 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001285 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001287 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001289 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001290 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1291 target_dev_id, lu_id_num,
1292 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001293 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1294 arr[1] = cmd[2]; /*sanity */
1295 arr[3] = inquiry_evpd_84(&arr[4]);
1296 } else if (0x85 == cmd[2]) { /* Management network addresses */
1297 arr[1] = cmd[2]; /*sanity */
1298 arr[3] = inquiry_evpd_85(&arr[4]);
1299 } else if (0x86 == cmd[2]) { /* extended inquiry */
1300 arr[1] = cmd[2]; /*sanity */
1301 arr[3] = 0x3c; /* number of following entries */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001302 if (sdebug_dif == SD_DIF_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001303 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001304 else if (sdebug_dif)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001305 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1306 else
1307 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001308 arr[5] = 0x7; /* head of q, ordered + simple q's */
1309 } else if (0x87 == cmd[2]) { /* mode page policy */
1310 arr[1] = cmd[2]; /*sanity */
1311 arr[3] = 0x8; /* number of following entries */
1312 arr[4] = 0x2; /* disconnect-reconnect mp */
1313 arr[6] = 0x80; /* mlus, shared */
1314 arr[8] = 0x18; /* protocol specific lu */
1315 arr[10] = 0x82; /* mlus, per initiator port */
1316 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1317 arr[1] = cmd[2]; /*sanity */
1318 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1319 } else if (0x89 == cmd[2]) { /* ATA information */
1320 arr[1] = cmd[2]; /*sanity */
1321 n = inquiry_evpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001322 put_unaligned_be16(n, arr + 2);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001323 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1324 arr[1] = cmd[2]; /*sanity */
1325 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001326 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1327 arr[1] = cmd[2]; /*sanity */
1328 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001329 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001330 arr[1] = cmd[2]; /*sanity */
1331 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001333 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001334 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 return check_condition_result;
1336 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001337 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001338 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001339 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001340 kfree(arr);
1341 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 }
1343 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001344 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1345 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 arr[3] = 2; /* response_data_format==2 */
1347 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001348 arr[5] = sdebug_dif ? 1 : 0; /* PROTECT bit */
1349 if (0 == sdebug_vpd_use_hostno)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001350 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001351 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001353 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 memcpy(&arr[8], inq_vendor_id, 8);
1355 memcpy(&arr[16], inq_product_id, 16);
1356 memcpy(&arr[32], inq_product_rev, 4);
1357 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001358 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1359 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001360 n = 62;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001361 if (sdebug_ptype == 0) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001362 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001363 } else if (sdebug_ptype == 1) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001364 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001366 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001367 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001369 kfree(arr);
1370 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371}
1372
Douglas Gilbertfd321192016-04-25 12:16:33 -04001373static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1374 0, 0, 0x0, 0x0};
1375
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376static int resp_requests(struct scsi_cmnd * scp,
1377 struct sdebug_dev_info * devip)
1378{
1379 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001380 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001381 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001382 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 int len = 18;
1384
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001385 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001386 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001387 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001388 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001389 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001390 arr[0] = 0x72;
1391 arr[1] = 0x0; /* NO_SENSE in sense_key */
1392 arr[2] = THRESHOLD_EXCEEDED;
1393 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001394 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001395 } else {
1396 arr[0] = 0x70;
1397 arr[2] = 0x0; /* NO_SENSE in sense_key */
1398 arr[7] = 0xa; /* 18 byte sense buffer */
1399 arr[12] = THRESHOLD_EXCEEDED;
1400 arr[13] = 0xff; /* TEST set and MRIE==6 */
1401 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001402 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001403 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001404 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001405 ; /* have sense and formats match */
1406 else if (arr[0] <= 0x70) {
1407 if (dsense) {
1408 memset(arr, 0, 8);
1409 arr[0] = 0x72;
1410 len = 8;
1411 } else {
1412 memset(arr, 0, 18);
1413 arr[0] = 0x70;
1414 arr[7] = 0xa;
1415 }
1416 } else if (dsense) {
1417 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001418 arr[0] = 0x72;
1419 arr[1] = sbuff[2]; /* sense key */
1420 arr[2] = sbuff[12]; /* asc */
1421 arr[3] = sbuff[13]; /* ascq */
1422 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001423 } else {
1424 memset(arr, 0, 18);
1425 arr[0] = 0x70;
1426 arr[2] = sbuff[1];
1427 arr[7] = 0xa;
1428 arr[12] = sbuff[1];
1429 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001430 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001431
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001432 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001433 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 return fill_from_dev_buffer(scp, arr, len);
1435}
1436
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001437static int resp_start_stop(struct scsi_cmnd * scp,
1438 struct sdebug_dev_info * devip)
1439{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001440 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001441 int power_cond, start;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001442
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001443 power_cond = (cmd[4] & 0xf0) >> 4;
1444 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001445 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001446 return check_condition_result;
1447 }
1448 start = cmd[4] & 1;
1449 if (start == devip->stopped)
1450 devip->stopped = !start;
1451 return 0;
1452}
1453
FUJITA Tomonori28898872008-03-30 00:59:55 +09001454static sector_t get_sdebug_capacity(void)
1455{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001456 static const unsigned int gibibyte = 1073741824;
1457
1458 if (sdebug_virtual_gb > 0)
1459 return (sector_t)sdebug_virtual_gb *
1460 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001461 else
1462 return sdebug_store_sectors;
1463}
1464
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465#define SDEBUG_READCAP_ARR_SZ 8
1466static int resp_readcap(struct scsi_cmnd * scp,
1467 struct sdebug_dev_info * devip)
1468{
1469 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001470 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001472 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001473 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001475 if (sdebug_capacity < 0xffffffff) {
1476 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001477 put_unaligned_be32(capac, arr + 0);
1478 } else
1479 put_unaligned_be32(0xffffffff, arr + 0);
1480 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1482}
1483
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484#define SDEBUG_READCAP16_ARR_SZ 32
1485static int resp_readcap16(struct scsi_cmnd * scp,
1486 struct sdebug_dev_info * devip)
1487{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001488 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001489 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001490 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001491
Douglas Gilbert773642d2016-04-25 12:16:28 -04001492 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001493 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001494 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001495 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001496 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1497 put_unaligned_be32(sdebug_sector_size, arr + 8);
1498 arr[13] = sdebug_physblk_exp & 0xf;
1499 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001500
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001501 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001502 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001503 if (sdebug_lbprz)
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001504 arr[14] |= 0x40; /* LBPRZ */
1505 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001506
Douglas Gilbert773642d2016-04-25 12:16:28 -04001507 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001508
Douglas Gilbert773642d2016-04-25 12:16:28 -04001509 if (sdebug_dif) {
1510 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001511 arr[12] |= 1; /* PROT_EN */
1512 }
1513
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001514 return fill_from_dev_buffer(scp, arr,
1515 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1516}
1517
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001518#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1519
1520static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1521 struct sdebug_dev_info * devip)
1522{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001523 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001524 unsigned char * arr;
1525 int host_no = devip->sdbg_host->shost->host_no;
1526 int n, ret, alen, rlen;
1527 int port_group_a, port_group_b, port_a, port_b;
1528
Douglas Gilbert773642d2016-04-25 12:16:28 -04001529 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001530 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1531 if (! arr)
1532 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001533 /*
1534 * EVPD page 0x88 states we have two ports, one
1535 * real and a fake port with no device connected.
1536 * So we create two port groups with one port each
1537 * and set the group with port B to unavailable.
1538 */
1539 port_a = 0x1; /* relative port A */
1540 port_b = 0x2; /* relative port B */
1541 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001542 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001543 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001544 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001545
1546 /*
1547 * The asymmetric access state is cycled according to the host_id.
1548 */
1549 n = 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001550 if (0 == sdebug_vpd_use_hostno) {
1551 arr[n++] = host_no % 3; /* Asymm access state */
1552 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001553 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001554 arr[n++] = 0x0; /* Active/Optimized path */
1555 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001556 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001557 put_unaligned_be16(port_group_a, arr + n);
1558 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001559 arr[n++] = 0; /* Reserved */
1560 arr[n++] = 0; /* Status code */
1561 arr[n++] = 0; /* Vendor unique */
1562 arr[n++] = 0x1; /* One port per group */
1563 arr[n++] = 0; /* Reserved */
1564 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001565 put_unaligned_be16(port_a, arr + n);
1566 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001567 arr[n++] = 3; /* Port unavailable */
1568 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001569 put_unaligned_be16(port_group_b, arr + n);
1570 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001571 arr[n++] = 0; /* Reserved */
1572 arr[n++] = 0; /* Status code */
1573 arr[n++] = 0; /* Vendor unique */
1574 arr[n++] = 0x1; /* One port per group */
1575 arr[n++] = 0; /* Reserved */
1576 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001577 put_unaligned_be16(port_b, arr + n);
1578 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001579
1580 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001581 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001582
1583 /*
1584 * Return the smallest value of either
1585 * - The allocated length
1586 * - The constructed command length
1587 * - The maximum array size
1588 */
1589 rlen = min(alen,n);
1590 ret = fill_from_dev_buffer(scp, arr,
1591 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1592 kfree(arr);
1593 return ret;
1594}
1595
Douglas Gilbertfd321192016-04-25 12:16:33 -04001596static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1597 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001598{
1599 bool rctd;
1600 u8 reporting_opts, req_opcode, sdeb_i, supp;
1601 u16 req_sa, u;
1602 u32 alloc_len, a_len;
1603 int k, offset, len, errsts, count, bump, na;
1604 const struct opcode_info_t *oip;
1605 const struct opcode_info_t *r_oip;
1606 u8 *arr;
1607 u8 *cmd = scp->cmnd;
1608
1609 rctd = !!(cmd[2] & 0x80);
1610 reporting_opts = cmd[2] & 0x7;
1611 req_opcode = cmd[3];
1612 req_sa = get_unaligned_be16(cmd + 4);
1613 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001614 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001615 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1616 return check_condition_result;
1617 }
1618 if (alloc_len > 8192)
1619 a_len = 8192;
1620 else
1621 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001622 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001623 if (NULL == arr) {
1624 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1625 INSUFF_RES_ASCQ);
1626 return check_condition_result;
1627 }
1628 switch (reporting_opts) {
1629 case 0: /* all commands */
1630 /* count number of commands */
1631 for (count = 0, oip = opcode_info_arr;
1632 oip->num_attached != 0xff; ++oip) {
1633 if (F_INV_OP & oip->flags)
1634 continue;
1635 count += (oip->num_attached + 1);
1636 }
1637 bump = rctd ? 20 : 8;
1638 put_unaligned_be32(count * bump, arr);
1639 for (offset = 4, oip = opcode_info_arr;
1640 oip->num_attached != 0xff && offset < a_len; ++oip) {
1641 if (F_INV_OP & oip->flags)
1642 continue;
1643 na = oip->num_attached;
1644 arr[offset] = oip->opcode;
1645 put_unaligned_be16(oip->sa, arr + offset + 2);
1646 if (rctd)
1647 arr[offset + 5] |= 0x2;
1648 if (FF_SA & oip->flags)
1649 arr[offset + 5] |= 0x1;
1650 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1651 if (rctd)
1652 put_unaligned_be16(0xa, arr + offset + 8);
1653 r_oip = oip;
1654 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1655 if (F_INV_OP & oip->flags)
1656 continue;
1657 offset += bump;
1658 arr[offset] = oip->opcode;
1659 put_unaligned_be16(oip->sa, arr + offset + 2);
1660 if (rctd)
1661 arr[offset + 5] |= 0x2;
1662 if (FF_SA & oip->flags)
1663 arr[offset + 5] |= 0x1;
1664 put_unaligned_be16(oip->len_mask[0],
1665 arr + offset + 6);
1666 if (rctd)
1667 put_unaligned_be16(0xa,
1668 arr + offset + 8);
1669 }
1670 oip = r_oip;
1671 offset += bump;
1672 }
1673 break;
1674 case 1: /* one command: opcode only */
1675 case 2: /* one command: opcode plus service action */
1676 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1677 sdeb_i = opcode_ind_arr[req_opcode];
1678 oip = &opcode_info_arr[sdeb_i];
1679 if (F_INV_OP & oip->flags) {
1680 supp = 1;
1681 offset = 4;
1682 } else {
1683 if (1 == reporting_opts) {
1684 if (FF_SA & oip->flags) {
1685 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1686 2, 2);
1687 kfree(arr);
1688 return check_condition_result;
1689 }
1690 req_sa = 0;
1691 } else if (2 == reporting_opts &&
1692 0 == (FF_SA & oip->flags)) {
1693 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1694 kfree(arr); /* point at requested sa */
1695 return check_condition_result;
1696 }
1697 if (0 == (FF_SA & oip->flags) &&
1698 req_opcode == oip->opcode)
1699 supp = 3;
1700 else if (0 == (FF_SA & oip->flags)) {
1701 na = oip->num_attached;
1702 for (k = 0, oip = oip->arrp; k < na;
1703 ++k, ++oip) {
1704 if (req_opcode == oip->opcode)
1705 break;
1706 }
1707 supp = (k >= na) ? 1 : 3;
1708 } else if (req_sa != oip->sa) {
1709 na = oip->num_attached;
1710 for (k = 0, oip = oip->arrp; k < na;
1711 ++k, ++oip) {
1712 if (req_sa == oip->sa)
1713 break;
1714 }
1715 supp = (k >= na) ? 1 : 3;
1716 } else
1717 supp = 3;
1718 if (3 == supp) {
1719 u = oip->len_mask[0];
1720 put_unaligned_be16(u, arr + 2);
1721 arr[4] = oip->opcode;
1722 for (k = 1; k < u; ++k)
1723 arr[4 + k] = (k < 16) ?
1724 oip->len_mask[k] : 0xff;
1725 offset = 4 + u;
1726 } else
1727 offset = 4;
1728 }
1729 arr[1] = (rctd ? 0x80 : 0) | supp;
1730 if (rctd) {
1731 put_unaligned_be16(0xa, arr + offset);
1732 offset += 12;
1733 }
1734 break;
1735 default:
1736 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1737 kfree(arr);
1738 return check_condition_result;
1739 }
1740 offset = (offset < a_len) ? offset : a_len;
1741 len = (offset < alloc_len) ? offset : alloc_len;
1742 errsts = fill_from_dev_buffer(scp, arr, len);
1743 kfree(arr);
1744 return errsts;
1745}
1746
Douglas Gilbertfd321192016-04-25 12:16:33 -04001747static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1748 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001749{
1750 bool repd;
1751 u32 alloc_len, len;
1752 u8 arr[16];
1753 u8 *cmd = scp->cmnd;
1754
1755 memset(arr, 0, sizeof(arr));
1756 repd = !!(cmd[2] & 0x80);
1757 alloc_len = get_unaligned_be32(cmd + 6);
1758 if (alloc_len < 4) {
1759 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1760 return check_condition_result;
1761 }
1762 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1763 arr[1] = 0x1; /* ITNRS */
1764 if (repd) {
1765 arr[3] = 0xc;
1766 len = 16;
1767 } else
1768 len = 4;
1769
1770 len = (len < alloc_len) ? len : alloc_len;
1771 return fill_from_dev_buffer(scp, arr, len);
1772}
1773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774/* <<Following mode page info copied from ST318451LW>> */
1775
1776static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1777{ /* Read-Write Error Recovery page for mode_sense */
1778 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1779 5, 0, 0xff, 0xff};
1780
1781 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1782 if (1 == pcontrol)
1783 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1784 return sizeof(err_recov_pg);
1785}
1786
1787static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1788{ /* Disconnect-Reconnect page for mode_sense */
1789 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1790 0, 0, 0, 0, 0, 0, 0, 0};
1791
1792 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1793 if (1 == pcontrol)
1794 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1795 return sizeof(disconnect_pg);
1796}
1797
1798static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1799{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001800 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1801 0, 0, 0, 0, 0, 0, 0, 0,
1802 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Martin K. Petersen597136a2008-06-05 00:12:59 -04001804 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001805 put_unaligned_be16(sdebug_sectors_per, p + 10);
1806 put_unaligned_be16(sdebug_sector_size, p + 12);
1807 if (sdebug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001808 p[20] |= 0x20; /* should agree with INQUIRY */
1809 if (1 == pcontrol)
1810 memset(p + 2, 0, sizeof(format_pg) - 2);
1811 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812}
1813
Douglas Gilbertfd321192016-04-25 12:16:33 -04001814static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1815 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1816 0, 0, 0, 0};
1817
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1819{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001820 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1821 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1822 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1824
Douglas Gilbert773642d2016-04-25 12:16:28 -04001825 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001826 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 memcpy(p, caching_pg, sizeof(caching_pg));
1828 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001829 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1830 else if (2 == pcontrol)
1831 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 return sizeof(caching_pg);
1833}
1834
Douglas Gilbertfd321192016-04-25 12:16:33 -04001835static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
1836 0, 0, 0x2, 0x4b};
1837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1839{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001840 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1841 0, 0, 0, 0};
1842 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 0, 0, 0x2, 0x4b};
1844
Douglas Gilbert773642d2016-04-25 12:16:28 -04001845 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001847 else
1848 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001849
Douglas Gilbert773642d2016-04-25 12:16:28 -04001850 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001851 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1854 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001855 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1856 else if (2 == pcontrol)
1857 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 return sizeof(ctrl_m_pg);
1859}
1860
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1863{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001864 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1865 0, 0, 0x0, 0x0};
1866 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1867 0, 0, 0x0, 0x0};
1868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1870 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001871 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1872 else if (2 == pcontrol)
1873 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 return sizeof(iec_m_pg);
1875}
1876
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001877static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1878{ /* SAS SSP mode page - short format for mode_sense */
1879 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1880 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1881
1882 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1883 if (1 == pcontrol)
1884 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1885 return sizeof(sas_sf_m_pg);
1886}
1887
1888
1889static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1890 int target_dev_id)
1891{ /* SAS phy control and discover mode page for mode_sense */
1892 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1893 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001894 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1895 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001896 0x2, 0, 0, 0, 0, 0, 0, 0,
1897 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1898 0, 0, 0, 0, 0, 0, 0, 0,
1899 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04001900 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
1901 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001902 0x3, 0, 0, 0, 0, 0, 0, 0,
1903 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1904 0, 0, 0, 0, 0, 0, 0, 0,
1905 };
1906 int port_a, port_b;
1907
Douglas Gilbert773642d2016-04-25 12:16:28 -04001908 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16);
1909 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24);
1910 put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64);
1911 put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001912 port_a = target_dev_id + 1;
1913 port_b = port_a + 1;
1914 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001915 put_unaligned_be32(port_a, p + 20);
1916 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001917 if (1 == pcontrol)
1918 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1919 return sizeof(sas_pcd_m_pg);
1920}
1921
1922static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1923{ /* SAS SSP shared protocol specific port mode subpage */
1924 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1925 0, 0, 0, 0, 0, 0, 0, 0,
1926 };
1927
1928 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1929 if (1 == pcontrol)
1930 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1931 return sizeof(sas_sha_m_pg);
1932}
1933
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934#define SDEBUG_MAX_MSENSE_SZ 256
1935
Douglas Gilbertfd321192016-04-25 12:16:33 -04001936static int resp_mode_sense(struct scsi_cmnd *scp,
1937 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938{
Douglas Gilbert23183912006-09-16 20:30:47 -04001939 unsigned char dbd, llbaa;
1940 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 unsigned char dev_spec;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001942 int alloc_len, msense_6, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001943 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 unsigned char * ap;
1945 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001946 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
Douglas Gilbert23183912006-09-16 20:30:47 -04001948 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 pcontrol = (cmd[2] & 0xc0) >> 6;
1950 pcode = cmd[2] & 0x3f;
1951 subpcode = cmd[3];
1952 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001953 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001954 if ((0 == sdebug_ptype) && (0 == dbd))
Douglas Gilbert23183912006-09-16 20:30:47 -04001955 bd_len = llbaa ? 16 : 8;
1956 else
1957 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001958 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1960 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001961 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 return check_condition_result;
1963 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001964 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1965 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001966 /* set DPOFUA bit for disks */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001967 if (0 == sdebug_ptype)
Douglas Gilbertfd321192016-04-25 12:16:33 -04001968 dev_spec = 0x10; /* would be 0x90 if read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04001969 else
1970 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 if (msense_6) {
1972 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001973 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 offset = 4;
1975 } else {
1976 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001977 if (16 == bd_len)
1978 arr[4] = 0x1; /* set LONGLBA bit */
1979 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 offset = 8;
1981 }
1982 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001983 if ((bd_len > 0) && (!sdebug_capacity))
1984 sdebug_capacity = get_sdebug_capacity();
1985
Douglas Gilbert23183912006-09-16 20:30:47 -04001986 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001987 if (sdebug_capacity > 0xfffffffe)
1988 put_unaligned_be32(0xffffffff, ap + 0);
1989 else
1990 put_unaligned_be32(sdebug_capacity, ap + 0);
1991 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04001992 offset += bd_len;
1993 ap = arr + offset;
1994 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001995 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
1996 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04001997 offset += bd_len;
1998 ap = arr + offset;
1999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002001 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2002 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002003 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 return check_condition_result;
2005 }
2006 switch (pcode) {
2007 case 0x1: /* Read-Write error recovery page, direct access */
2008 len = resp_err_recov_pg(ap, pcontrol, target);
2009 offset += len;
2010 break;
2011 case 0x2: /* Disconnect-Reconnect page, all devices */
2012 len = resp_disconnect_pg(ap, pcontrol, target);
2013 offset += len;
2014 break;
2015 case 0x3: /* Format device page, direct access */
2016 len = resp_format_pg(ap, pcontrol, target);
2017 offset += len;
2018 break;
2019 case 0x8: /* Caching page, direct access */
2020 len = resp_caching_pg(ap, pcontrol, target);
2021 offset += len;
2022 break;
2023 case 0xa: /* Control Mode page, all devices */
2024 len = resp_ctrl_m_pg(ap, pcontrol, target);
2025 offset += len;
2026 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002027 case 0x19: /* if spc==1 then sas phy, control+discover */
2028 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002029 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002030 return check_condition_result;
2031 }
2032 len = 0;
2033 if ((0x0 == subpcode) || (0xff == subpcode))
2034 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2035 if ((0x1 == subpcode) || (0xff == subpcode))
2036 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2037 target_dev_id);
2038 if ((0x2 == subpcode) || (0xff == subpcode))
2039 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2040 offset += len;
2041 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 case 0x1c: /* Informational Exceptions Mode page, all devices */
2043 len = resp_iec_m_pg(ap, pcontrol, target);
2044 offset += len;
2045 break;
2046 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002047 if ((0 == subpcode) || (0xff == subpcode)) {
2048 len = resp_err_recov_pg(ap, pcontrol, target);
2049 len += resp_disconnect_pg(ap + len, pcontrol, target);
2050 len += resp_format_pg(ap + len, pcontrol, target);
2051 len += resp_caching_pg(ap + len, pcontrol, target);
2052 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2053 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2054 if (0xff == subpcode) {
2055 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2056 target, target_dev_id);
2057 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2058 }
2059 len += resp_iec_m_pg(ap + len, pcontrol, target);
2060 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002061 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002062 return check_condition_result;
2063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 offset += len;
2065 break;
2066 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002067 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 return check_condition_result;
2069 }
2070 if (msense_6)
2071 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002072 else
2073 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2075}
2076
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002077#define SDEBUG_MAX_MSELECT_SZ 512
2078
Douglas Gilbertfd321192016-04-25 12:16:33 -04002079static int resp_mode_select(struct scsi_cmnd *scp,
2080 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002081{
2082 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002083 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002084 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002085 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002086 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002087
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002088 memset(arr, 0, sizeof(arr));
2089 pf = cmd[1] & 0x10;
2090 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002091 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002092 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002093 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002094 return check_condition_result;
2095 }
2096 res = fetch_to_dev_buffer(scp, arr, param_len);
2097 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002098 return DID_ERROR << 16;
2099 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002100 sdev_printk(KERN_INFO, scp->device,
2101 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2102 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002103 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2104 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002105 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002106 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002107 return check_condition_result;
2108 }
2109 off = bd_len + (mselect6 ? 4 : 8);
2110 mpage = arr[off] & 0x3f;
2111 ps = !!(arr[off] & 0x80);
2112 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002113 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002114 return check_condition_result;
2115 }
2116 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002117 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002118 (arr[off + 1] + 2);
2119 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002120 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002121 PARAMETER_LIST_LENGTH_ERR, 0);
2122 return check_condition_result;
2123 }
2124 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002125 case 0x8: /* Caching Mode page */
2126 if (caching_pg[1] == arr[off + 1]) {
2127 memcpy(caching_pg + 2, arr + off + 2,
2128 sizeof(caching_pg) - 2);
2129 goto set_mode_changed_ua;
2130 }
2131 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002132 case 0xa: /* Control Mode page */
2133 if (ctrl_m_pg[1] == arr[off + 1]) {
2134 memcpy(ctrl_m_pg + 2, arr + off + 2,
2135 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002136 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002137 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002138 }
2139 break;
2140 case 0x1c: /* Informational Exceptions Mode page */
2141 if (iec_m_pg[1] == arr[off + 1]) {
2142 memcpy(iec_m_pg + 2, arr + off + 2,
2143 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002144 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002145 }
2146 break;
2147 default:
2148 break;
2149 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002150 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002151 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002152set_mode_changed_ua:
2153 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2154 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002155}
2156
2157static int resp_temp_l_pg(unsigned char * arr)
2158{
2159 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2160 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2161 };
2162
2163 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2164 return sizeof(temp_l_pg);
2165}
2166
2167static int resp_ie_l_pg(unsigned char * arr)
2168{
2169 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2170 };
2171
2172 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2173 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2174 arr[4] = THRESHOLD_EXCEEDED;
2175 arr[5] = 0xff;
2176 }
2177 return sizeof(ie_l_pg);
2178}
2179
2180#define SDEBUG_MAX_LSENSE_SZ 512
2181
2182static int resp_log_sense(struct scsi_cmnd * scp,
2183 struct sdebug_dev_info * devip)
2184{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002185 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002186 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002187 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002188
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002189 memset(arr, 0, sizeof(arr));
2190 ppc = cmd[1] & 0x2;
2191 sp = cmd[1] & 0x1;
2192 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002193 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002194 return check_condition_result;
2195 }
2196 pcontrol = (cmd[2] & 0xc0) >> 6;
2197 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002198 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002199 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002200 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002201 if (0 == subpcode) {
2202 switch (pcode) {
2203 case 0x0: /* Supported log pages log page */
2204 n = 4;
2205 arr[n++] = 0x0; /* this page */
2206 arr[n++] = 0xd; /* Temperature */
2207 arr[n++] = 0x2f; /* Informational exceptions */
2208 arr[3] = n - 4;
2209 break;
2210 case 0xd: /* Temperature log page */
2211 arr[3] = resp_temp_l_pg(arr + 4);
2212 break;
2213 case 0x2f: /* Informational exceptions log page */
2214 arr[3] = resp_ie_l_pg(arr + 4);
2215 break;
2216 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002217 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002218 return check_condition_result;
2219 }
2220 } else if (0xff == subpcode) {
2221 arr[0] |= 0x40;
2222 arr[1] = subpcode;
2223 switch (pcode) {
2224 case 0x0: /* Supported log pages and subpages log page */
2225 n = 4;
2226 arr[n++] = 0x0;
2227 arr[n++] = 0x0; /* 0,0 page */
2228 arr[n++] = 0x0;
2229 arr[n++] = 0xff; /* this page */
2230 arr[n++] = 0xd;
2231 arr[n++] = 0x0; /* Temperature */
2232 arr[n++] = 0x2f;
2233 arr[n++] = 0x0; /* Informational exceptions */
2234 arr[3] = n - 4;
2235 break;
2236 case 0xd: /* Temperature subpages */
2237 n = 4;
2238 arr[n++] = 0xd;
2239 arr[n++] = 0x0; /* Temperature */
2240 arr[3] = n - 4;
2241 break;
2242 case 0x2f: /* Informational exceptions subpages */
2243 n = 4;
2244 arr[n++] = 0x2f;
2245 arr[n++] = 0x0; /* Informational exceptions */
2246 arr[3] = n - 4;
2247 break;
2248 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002249 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002250 return check_condition_result;
2251 }
2252 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002253 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002254 return check_condition_result;
2255 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002256 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002257 return fill_from_dev_buffer(scp, arr,
2258 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2259}
2260
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002261static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002262 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002264 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002265 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 return check_condition_result;
2267 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002268 /* transfer length excessive (tie in to block limits VPD page) */
2269 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002270 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002271 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002272 return check_condition_result;
2273 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002274 return 0;
2275}
2276
Akinobu Mitaa4517512013-07-08 16:01:57 -07002277/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002278static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num,
2279 bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002280{
2281 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002282 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002283 struct scsi_data_buffer *sdb;
2284 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002285
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002286 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002287 sdb = scsi_out(scmd);
2288 dir = DMA_TO_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002289 } else {
2290 sdb = scsi_in(scmd);
2291 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002292 }
2293
2294 if (!sdb->length)
2295 return 0;
2296 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2297 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002298
2299 block = do_div(lba, sdebug_store_sectors);
2300 if (block + num > sdebug_store_sectors)
2301 rest = block + num - sdebug_store_sectors;
2302
Dave Gordon386ecb12015-06-30 14:58:57 -07002303 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002304 fake_storep + (block * sdebug_sector_size),
2305 (num - rest) * sdebug_sector_size, 0, do_write);
2306 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002307 return ret;
2308
2309 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002310 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002311 fake_storep, rest * sdebug_sector_size,
2312 (num - rest) * sdebug_sector_size, do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002313 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002314
2315 return ret;
2316}
2317
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002318/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2319 * arr into fake_store(lba,num) and return true. If comparison fails then
2320 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002321static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002322{
2323 bool res;
2324 u64 block, rest = 0;
2325 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002326 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002327
2328 block = do_div(lba, store_blks);
2329 if (block + num > store_blks)
2330 rest = block + num - store_blks;
2331
2332 res = !memcmp(fake_storep + (block * lb_size), arr,
2333 (num - rest) * lb_size);
2334 if (!res)
2335 return res;
2336 if (rest)
2337 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2338 rest * lb_size);
2339 if (!res)
2340 return res;
2341 arr += num * lb_size;
2342 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2343 if (rest)
2344 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2345 rest * lb_size);
2346 return res;
2347}
2348
Akinobu Mita51d648a2013-09-18 21:27:28 +09002349static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002350{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002351 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002352
Douglas Gilbert773642d2016-04-25 12:16:28 -04002353 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002354 csum = (__force __be16)ip_compute_csum(buf, len);
2355 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002356 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002357
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002358 return csum;
2359}
2360
2361static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2362 sector_t sector, u32 ei_lba)
2363{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002364 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002365
2366 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002367 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002368 (unsigned long)sector,
2369 be16_to_cpu(sdt->guard_tag),
2370 be16_to_cpu(csum));
2371 return 0x01;
2372 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002373 if (sdebug_dif == SD_DIF_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002374 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002375 pr_err("REF check failed on sector %lu\n",
2376 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002377 return 0x03;
2378 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002379 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002380 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002381 pr_err("REF check failed on sector %lu\n",
2382 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002383 return 0x03;
2384 }
2385 return 0;
2386}
2387
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002388static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002389 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002390{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002391 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002392 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002393 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002394 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002395
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002396 /* Bytes of protection data to copy into sgl */
2397 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002398
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002399 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2400 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2401 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2402
2403 while (sg_miter_next(&miter) && resid > 0) {
2404 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002405 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002406 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002407
2408 if (dif_store_end < start + len)
2409 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002410
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002411 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002412
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002413 if (read)
2414 memcpy(paddr, start, len - rest);
2415 else
2416 memcpy(start, paddr, len - rest);
2417
2418 if (rest) {
2419 if (read)
2420 memcpy(paddr + len - rest, dif_storep, rest);
2421 else
2422 memcpy(dif_storep, paddr + len - rest, rest);
2423 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002424
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002425 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002426 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002427 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002428 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002429}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002430
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002431static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2432 unsigned int sectors, u32 ei_lba)
2433{
2434 unsigned int i;
2435 struct sd_dif_tuple *sdt;
2436 sector_t sector;
2437
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002438 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002439 int ret;
2440
2441 sector = start_sec + i;
2442 sdt = dif_store(sector);
2443
Akinobu Mita51d648a2013-09-18 21:27:28 +09002444 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002445 continue;
2446
2447 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2448 if (ret) {
2449 dif_errors++;
2450 return ret;
2451 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002452 }
2453
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002454 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002455 dix_reads++;
2456
2457 return 0;
2458}
2459
Douglas Gilbertfd321192016-04-25 12:16:33 -04002460static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002461{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002462 u8 *cmd = scp->cmnd;
2463 u64 lba;
2464 u32 num;
2465 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002466 unsigned long iflags;
2467 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002468 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002469
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002470 switch (cmd[0]) {
2471 case READ_16:
2472 ei_lba = 0;
2473 lba = get_unaligned_be64(cmd + 2);
2474 num = get_unaligned_be32(cmd + 10);
2475 check_prot = true;
2476 break;
2477 case READ_10:
2478 ei_lba = 0;
2479 lba = get_unaligned_be32(cmd + 2);
2480 num = get_unaligned_be16(cmd + 7);
2481 check_prot = true;
2482 break;
2483 case READ_6:
2484 ei_lba = 0;
2485 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2486 (u32)(cmd[1] & 0x1f) << 16;
2487 num = (0 == cmd[4]) ? 256 : cmd[4];
2488 check_prot = true;
2489 break;
2490 case READ_12:
2491 ei_lba = 0;
2492 lba = get_unaligned_be32(cmd + 2);
2493 num = get_unaligned_be32(cmd + 6);
2494 check_prot = true;
2495 break;
2496 case XDWRITEREAD_10:
2497 ei_lba = 0;
2498 lba = get_unaligned_be32(cmd + 2);
2499 num = get_unaligned_be16(cmd + 7);
2500 check_prot = false;
2501 break;
2502 default: /* assume READ(32) */
2503 lba = get_unaligned_be64(cmd + 12);
2504 ei_lba = get_unaligned_be32(cmd + 20);
2505 num = get_unaligned_be32(cmd + 28);
2506 check_prot = false;
2507 break;
2508 }
2509 if (check_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002510 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002511 (cmd[1] & 0xe0)) {
2512 mk_sense_invalid_opcode(scp);
2513 return check_condition_result;
2514 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002515 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2516 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002517 (cmd[1] & 0xe0) == 0)
2518 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2519 "to DIF device\n");
2520 }
2521 if (sdebug_any_injecting_opt) {
2522 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2523
2524 if (ep->inj_short)
2525 num /= 2;
2526 }
2527
2528 /* inline check_device_access_params() */
2529 if (lba + num > sdebug_capacity) {
2530 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2531 return check_condition_result;
2532 }
2533 /* transfer length excessive (tie in to block limits VPD page) */
2534 if (num > sdebug_store_sectors) {
2535 /* needs work to find which cdb byte 'num' comes from */
2536 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2537 return check_condition_result;
2538 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002539
Douglas Gilbert773642d2016-04-25 12:16:28 -04002540 if ((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002541 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002542 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2543 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002544 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002545 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002546 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2547 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002548 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2549 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002550 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002551 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002552 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 return check_condition_result;
2554 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002555
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002556 read_lock_irqsave(&atomic_rw, iflags);
2557
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002558 /* DIX + T10 DIF */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002559 if (sdebug_dix && scsi_prot_sg_count(scp)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002560 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002561
2562 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002563 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002564 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002565 return illegal_condition_result;
2566 }
2567 }
2568
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002569 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 read_unlock_irqrestore(&atomic_rw, iflags);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002571 if (ret == -1)
2572 return DID_ERROR << 16;
2573
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002574 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002575
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002576 if (sdebug_any_injecting_opt) {
2577 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2578
2579 if (ep->inj_recovered) {
2580 mk_sense_buffer(scp, RECOVERED_ERROR,
2581 THRESHOLD_EXCEEDED, 0);
2582 return check_condition_result;
2583 } else if (ep->inj_transport) {
2584 mk_sense_buffer(scp, ABORTED_COMMAND,
2585 TRANSPORT_PROBLEM, ACK_NAK_TO);
2586 return check_condition_result;
2587 } else if (ep->inj_dif) {
2588 /* Logical block guard check failed */
2589 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2590 return illegal_condition_result;
2591 } else if (ep->inj_dix) {
2592 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2593 return illegal_condition_result;
2594 }
2595 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002596 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597}
2598
Tomas Winkler58a86352015-07-28 16:54:23 +03002599static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002600{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002601 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002602
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002603 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002604 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002605 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002606
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002607 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002608 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002609
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002610 if (c >= 0x20 && c < 0x7e)
2611 n += scnprintf(b + n, sizeof(b) - n,
2612 " %c ", buf[i+j]);
2613 else
2614 n += scnprintf(b + n, sizeof(b) - n,
2615 "%02x ", buf[i+j]);
2616 }
2617 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002618 }
2619}
2620
2621static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002622 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002623{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002624 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002625 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002626 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002627 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002628 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002629 int dpage_offset;
2630 struct sg_mapping_iter diter;
2631 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002632
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002633 BUG_ON(scsi_sg_count(SCpnt) == 0);
2634 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2635
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002636 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2637 scsi_prot_sg_count(SCpnt),
2638 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2639 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2640 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002641
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002642 /* For each protection page */
2643 while (sg_miter_next(&piter)) {
2644 dpage_offset = 0;
2645 if (WARN_ON(!sg_miter_next(&diter))) {
2646 ret = 0x01;
2647 goto out;
2648 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002649
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002650 for (ppage_offset = 0; ppage_offset < piter.length;
2651 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002652 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002653 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002654 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002655 if (dpage_offset >= diter.length) {
2656 if (WARN_ON(!sg_miter_next(&diter))) {
2657 ret = 0x01;
2658 goto out;
2659 }
2660 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002661 }
2662
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002663 sdt = piter.addr + ppage_offset;
2664 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002665
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002666 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002667 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002668 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002669 goto out;
2670 }
2671
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002672 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002673 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002674 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002675 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002676 diter.consumed = dpage_offset;
2677 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002678 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002679 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002680
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002681 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002682 dix_writes++;
2683
2684 return 0;
2685
2686out:
2687 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002688 sg_miter_stop(&diter);
2689 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002690 return ret;
2691}
2692
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002693static unsigned long lba_to_map_index(sector_t lba)
2694{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002695 if (sdebug_unmap_alignment)
2696 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2697 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002698 return lba;
2699}
2700
2701static sector_t map_index_to_lba(unsigned long index)
2702{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002703 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002704
Douglas Gilbert773642d2016-04-25 12:16:28 -04002705 if (sdebug_unmap_alignment)
2706 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002707 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002708}
2709
Martin K. Petersen44d92692009-10-15 14:45:27 -04002710static unsigned int map_state(sector_t lba, unsigned int *num)
2711{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002712 sector_t end;
2713 unsigned int mapped;
2714 unsigned long index;
2715 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002716
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002717 index = lba_to_map_index(lba);
2718 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002719
2720 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002721 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002722 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002723 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002724
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002725 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002726 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002727 return mapped;
2728}
2729
2730static void map_region(sector_t lba, unsigned int len)
2731{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002732 sector_t end = lba + len;
2733
Martin K. Petersen44d92692009-10-15 14:45:27 -04002734 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002735 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002736
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002737 if (index < map_size)
2738 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002739
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002740 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002741 }
2742}
2743
2744static void unmap_region(sector_t lba, unsigned int len)
2745{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002746 sector_t end = lba + len;
2747
Martin K. Petersen44d92692009-10-15 14:45:27 -04002748 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002749 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002750
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002751 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002752 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002753 index < map_size) {
2754 clear_bit(index, map_storep);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002755 if (sdebug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002756 memset(fake_storep +
Douglas Gilbert773642d2016-04-25 12:16:28 -04002757 lba * sdebug_sector_size, 0,
2758 sdebug_sector_size *
2759 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002760 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002761 if (dif_storep) {
2762 memset(dif_storep + lba, 0xff,
2763 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002764 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002765 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002766 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002767 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002768 }
2769}
2770
Douglas Gilbertfd321192016-04-25 12:16:33 -04002771static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002773 u8 *cmd = scp->cmnd;
2774 u64 lba;
2775 u32 num;
2776 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002778 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002779 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002781 switch (cmd[0]) {
2782 case WRITE_16:
2783 ei_lba = 0;
2784 lba = get_unaligned_be64(cmd + 2);
2785 num = get_unaligned_be32(cmd + 10);
2786 check_prot = true;
2787 break;
2788 case WRITE_10:
2789 ei_lba = 0;
2790 lba = get_unaligned_be32(cmd + 2);
2791 num = get_unaligned_be16(cmd + 7);
2792 check_prot = true;
2793 break;
2794 case WRITE_6:
2795 ei_lba = 0;
2796 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2797 (u32)(cmd[1] & 0x1f) << 16;
2798 num = (0 == cmd[4]) ? 256 : cmd[4];
2799 check_prot = true;
2800 break;
2801 case WRITE_12:
2802 ei_lba = 0;
2803 lba = get_unaligned_be32(cmd + 2);
2804 num = get_unaligned_be32(cmd + 6);
2805 check_prot = true;
2806 break;
2807 case 0x53: /* XDWRITEREAD(10) */
2808 ei_lba = 0;
2809 lba = get_unaligned_be32(cmd + 2);
2810 num = get_unaligned_be16(cmd + 7);
2811 check_prot = false;
2812 break;
2813 default: /* assume WRITE(32) */
2814 lba = get_unaligned_be64(cmd + 12);
2815 ei_lba = get_unaligned_be32(cmd + 20);
2816 num = get_unaligned_be32(cmd + 28);
2817 check_prot = false;
2818 break;
2819 }
2820 if (check_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002821 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002822 (cmd[1] & 0xe0)) {
2823 mk_sense_invalid_opcode(scp);
2824 return check_condition_result;
2825 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002826 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
2827 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002828 (cmd[1] & 0xe0) == 0)
2829 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2830 "to DIF device\n");
2831 }
2832
2833 /* inline check_device_access_params() */
2834 if (lba + num > sdebug_capacity) {
2835 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2836 return check_condition_result;
2837 }
2838 /* transfer length excessive (tie in to block limits VPD page) */
2839 if (num > sdebug_store_sectors) {
2840 /* needs work to find which cdb byte 'num' comes from */
2841 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2842 return check_condition_result;
2843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002845 write_lock_irqsave(&atomic_rw, iflags);
2846
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002847 /* DIX + T10 DIF */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002848 if (sdebug_dix && scsi_prot_sg_count(scp)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002849 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002850
2851 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002852 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002853 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002854 return illegal_condition_result;
2855 }
2856 }
2857
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002858 ret = do_device_access(scp, lba, num, true);
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002859 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002860 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002862 if (-1 == ret)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002863 return DID_ERROR << 16;
2864 else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002865 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002866 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002867 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002868
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002869 if (sdebug_any_injecting_opt) {
2870 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2871
2872 if (ep->inj_recovered) {
2873 mk_sense_buffer(scp, RECOVERED_ERROR,
2874 THRESHOLD_EXCEEDED, 0);
2875 return check_condition_result;
2876 } else if (ep->inj_dif) {
2877 /* Logical block guard check failed */
2878 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2879 return illegal_condition_result;
2880 } else if (ep->inj_dix) {
2881 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2882 return illegal_condition_result;
2883 }
2884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 return 0;
2886}
2887
Douglas Gilbertfd321192016-04-25 12:16:33 -04002888static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
2889 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002890{
2891 unsigned long iflags;
2892 unsigned long long i;
2893 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002894 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002895
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002896 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002897 if (ret)
2898 return ret;
2899
2900 write_lock_irqsave(&atomic_rw, iflags);
2901
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002902 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002903 unmap_region(lba, num);
2904 goto out;
2905 }
2906
Douglas Gilbert773642d2016-04-25 12:16:28 -04002907 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002908 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2909 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002910 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002911 ret = 0;
2912 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04002913 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
2914 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002915
2916 if (-1 == ret) {
2917 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002918 return DID_ERROR << 16;
2919 } else if (sdebug_verbose && (ret < (num * sdebug_sector_size)))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002920 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002921 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2922 my_name, "write same",
Douglas Gilbert773642d2016-04-25 12:16:28 -04002923 num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002924
2925 /* Copy first sector to remaining blocks */
2926 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002927 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
2928 fake_storep + lba_off,
2929 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002930
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002931 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002932 map_region(lba, num);
2933out:
2934 write_unlock_irqrestore(&atomic_rw, iflags);
2935
2936 return 0;
2937}
2938
Douglas Gilbertfd321192016-04-25 12:16:33 -04002939static int resp_write_same_10(struct scsi_cmnd *scp,
2940 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002941{
2942 u8 *cmd = scp->cmnd;
2943 u32 lba;
2944 u16 num;
2945 u32 ei_lba = 0;
2946 bool unmap = false;
2947
2948 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002949 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002950 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2951 return check_condition_result;
2952 } else
2953 unmap = true;
2954 }
2955 lba = get_unaligned_be32(cmd + 2);
2956 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002957 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002958 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2959 return check_condition_result;
2960 }
2961 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2962}
2963
Douglas Gilbertfd321192016-04-25 12:16:33 -04002964static int resp_write_same_16(struct scsi_cmnd *scp,
2965 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002966{
2967 u8 *cmd = scp->cmnd;
2968 u64 lba;
2969 u32 num;
2970 u32 ei_lba = 0;
2971 bool unmap = false;
2972 bool ndob = false;
2973
2974 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04002975 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002976 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2977 return check_condition_result;
2978 } else
2979 unmap = true;
2980 }
2981 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
2982 ndob = true;
2983 lba = get_unaligned_be64(cmd + 2);
2984 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002985 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002986 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2987 return check_condition_result;
2988 }
2989 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
2990}
2991
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05002992/* Note the mode field is in the same position as the (lower) service action
2993 * field. For the Report supported operation codes command, SPC-4 suggests
2994 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002995static int resp_write_buffer(struct scsi_cmnd *scp,
2996 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05002997{
2998 u8 *cmd = scp->cmnd;
2999 struct scsi_device *sdp = scp->device;
3000 struct sdebug_dev_info *dp;
3001 u8 mode;
3002
3003 mode = cmd[1] & 0x1f;
3004 switch (mode) {
3005 case 0x4: /* download microcode (MC) and activate (ACT) */
3006 /* set UAs on this device only */
3007 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3008 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3009 break;
3010 case 0x5: /* download MC, save and ACT */
3011 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3012 break;
3013 case 0x6: /* download MC with offsets and ACT */
3014 /* set UAs on most devices (LUs) in this target */
3015 list_for_each_entry(dp,
3016 &devip->sdbg_host->dev_info_list,
3017 dev_list)
3018 if (dp->target == sdp->id) {
3019 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3020 if (devip != dp)
3021 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3022 dp->uas_bm);
3023 }
3024 break;
3025 case 0x7: /* download MC with offsets, save, and ACT */
3026 /* set UA on all devices (LUs) in this target */
3027 list_for_each_entry(dp,
3028 &devip->sdbg_host->dev_info_list,
3029 dev_list)
3030 if (dp->target == sdp->id)
3031 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3032 dp->uas_bm);
3033 break;
3034 default:
3035 /* do nothing for this command for other mode values */
3036 break;
3037 }
3038 return 0;
3039}
3040
Douglas Gilbertfd321192016-04-25 12:16:33 -04003041static int resp_comp_write(struct scsi_cmnd *scp,
3042 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003043{
3044 u8 *cmd = scp->cmnd;
3045 u8 *arr;
3046 u8 *fake_storep_hold;
3047 u64 lba;
3048 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003049 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003050 u8 num;
3051 unsigned long iflags;
3052 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003053 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003054
Douglas Gilbertd467d312014-11-26 12:33:48 -05003055 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003056 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3057 if (0 == num)
3058 return 0; /* degenerate case, not an error */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003059 if (sdebug_dif == SD_DIF_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003060 (cmd[1] & 0xe0)) {
3061 mk_sense_invalid_opcode(scp);
3062 return check_condition_result;
3063 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003064 if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION ||
3065 sdebug_dif == SD_DIF_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003066 (cmd[1] & 0xe0) == 0)
3067 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3068 "to DIF device\n");
3069
3070 /* inline check_device_access_params() */
3071 if (lba + num > sdebug_capacity) {
3072 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3073 return check_condition_result;
3074 }
3075 /* transfer length excessive (tie in to block limits VPD page) */
3076 if (num > sdebug_store_sectors) {
3077 /* needs work to find which cdb byte 'num' comes from */
3078 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3079 return check_condition_result;
3080 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003081 dnum = 2 * num;
3082 arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
3083 if (NULL == arr) {
3084 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3085 INSUFF_RES_ASCQ);
3086 return check_condition_result;
3087 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003088
3089 write_lock_irqsave(&atomic_rw, iflags);
3090
3091 /* trick do_device_access() to fetch both compare and write buffers
3092 * from data-in into arr. Safe (atomic) since write_lock held. */
3093 fake_storep_hold = fake_storep;
3094 fake_storep = arr;
3095 ret = do_device_access(scp, 0, dnum, true);
3096 fake_storep = fake_storep_hold;
3097 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003098 retval = DID_ERROR << 16;
3099 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003100 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003101 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3102 "indicated=%u, IO sent=%d bytes\n", my_name,
3103 dnum * lb_size, ret);
3104 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003105 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003106 retval = check_condition_result;
3107 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003108 }
3109 if (scsi_debug_lbp())
3110 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003111cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003112 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003113 kfree(arr);
3114 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003115}
3116
Martin K. Petersen44d92692009-10-15 14:45:27 -04003117struct unmap_block_desc {
3118 __be64 lba;
3119 __be32 blocks;
3120 __be32 __reserved;
3121};
3122
Douglas Gilbertfd321192016-04-25 12:16:33 -04003123static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003124{
3125 unsigned char *buf;
3126 struct unmap_block_desc *desc;
3127 unsigned int i, payload_len, descriptors;
3128 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003129 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003130
Martin K. Petersen44d92692009-10-15 14:45:27 -04003131
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003132 if (!scsi_debug_lbp())
3133 return 0; /* fib and say its done */
3134 payload_len = get_unaligned_be16(scp->cmnd + 7);
3135 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003136
3137 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003138 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003139 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003140 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003141 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003142
Douglas Gilbertb333a812016-04-25 12:16:30 -04003143 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003144 if (!buf) {
3145 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3146 INSUFF_RES_ASCQ);
3147 return check_condition_result;
3148 }
3149
3150 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003151
3152 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3153 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3154
3155 desc = (void *)&buf[8];
3156
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003157 write_lock_irqsave(&atomic_rw, iflags);
3158
Martin K. Petersen44d92692009-10-15 14:45:27 -04003159 for (i = 0 ; i < descriptors ; i++) {
3160 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3161 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3162
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003163 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003164 if (ret)
3165 goto out;
3166
3167 unmap_region(lba, num);
3168 }
3169
3170 ret = 0;
3171
3172out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003173 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003174 kfree(buf);
3175
3176 return ret;
3177}
3178
3179#define SDEBUG_GET_LBA_STATUS_LEN 32
3180
Douglas Gilbertfd321192016-04-25 12:16:33 -04003181static int resp_get_lba_status(struct scsi_cmnd *scp,
3182 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003183{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003184 u8 *cmd = scp->cmnd;
3185 u64 lba;
3186 u32 alloc_len, mapped, num;
3187 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003188 int ret;
3189
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003190 lba = get_unaligned_be64(cmd + 2);
3191 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003192
3193 if (alloc_len < 24)
3194 return 0;
3195
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003196 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003197 if (ret)
3198 return ret;
3199
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003200 if (scsi_debug_lbp())
3201 mapped = map_state(lba, &num);
3202 else {
3203 mapped = 1;
3204 /* following just in case virtual_gb changed */
3205 sdebug_capacity = get_sdebug_capacity();
3206 if (sdebug_capacity - lba <= 0xffffffff)
3207 num = sdebug_capacity - lba;
3208 else
3209 num = 0xffffffff;
3210 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003211
3212 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003213 put_unaligned_be32(20, arr); /* Parameter Data Length */
3214 put_unaligned_be64(lba, arr + 8); /* LBA */
3215 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3216 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003217
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003218 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003219}
3220
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003221#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
3223static int resp_report_luns(struct scsi_cmnd * scp,
3224 struct sdebug_dev_info * devip)
3225{
3226 unsigned int alloc_len;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003227 int lun_cnt, i, upper, num, n, want_wlun, shortish;
3228 u64 lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003229 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 int select_report = (int)cmd[2];
3231 struct scsi_lun *one_lun;
3232 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003233 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003235 clear_luns_changed_on_target(devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003237 shortish = (alloc_len < 4);
3238 if (shortish || (select_report > 2)) {
3239 mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 return check_condition_result;
3241 }
3242 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
3243 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003244 lun_cnt = sdebug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003245 if (1 == select_report)
3246 lun_cnt = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003247 else if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003248 --lun_cnt;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003249 want_wlun = (select_report > 0) ? 1 : 0;
3250 num = lun_cnt + want_wlun;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003251 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
3252 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
3253 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
3254 sizeof(struct scsi_lun)), num);
3255 if (n < num) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003256 want_wlun = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003257 lun_cnt = n;
3258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003260 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003261 for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003262 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
3263 i++, lun++) {
3264 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 if (upper)
3266 one_lun[i].scsi_lun[0] =
3267 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003268 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003269 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003270 if (want_wlun) {
Tomas Winkler34d55432015-07-28 16:54:21 +03003271 one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff;
3272 one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003273 i++;
3274 }
3275 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 return fill_from_dev_buffer(scp, arr,
3277 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
3278}
3279
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003280static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
3281 unsigned int num, struct sdebug_dev_info *devip)
3282{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003283 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003284 unsigned char *kaddr, *buf;
3285 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003286 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003287 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003288
3289 /* better not to use temporary buffer. */
Douglas Gilbertb333a812016-04-25 12:16:30 -04003290 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003291 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05003292 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3293 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003294 return check_condition_result;
3295 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003296
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003297 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003298
3299 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003300 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3301 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003302
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003303 while (sg_miter_next(&miter)) {
3304 kaddr = miter.addr;
3305 for (j = 0; j < miter.length; j++)
3306 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003307
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003308 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003309 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003310 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003311 kfree(buf);
3312
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003313 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003314}
3315
Douglas Gilbertfd321192016-04-25 12:16:33 -04003316static int resp_xdwriteread_10(struct scsi_cmnd *scp,
3317 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003318{
3319 u8 *cmd = scp->cmnd;
3320 u64 lba;
3321 u32 num;
3322 int errsts;
3323
3324 if (!scsi_bidi_cmnd(scp)) {
3325 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3326 INSUFF_RES_ASCQ);
3327 return check_condition_result;
3328 }
3329 errsts = resp_read_dt0(scp, devip);
3330 if (errsts)
3331 return errsts;
3332 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3333 errsts = resp_write_dt0(scp, devip);
3334 if (errsts)
3335 return errsts;
3336 }
3337 lba = get_unaligned_be32(cmd + 2);
3338 num = get_unaligned_be16(cmd + 7);
3339 return resp_xdwriteread(scp, lba, num, devip);
3340}
3341
Douglas Gilberta10bc122016-04-25 12:16:32 -04003342/* Queued command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003343static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003345 int qa_indx;
3346 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003348 struct sdebug_queued_cmd *sqcp;
3349 struct scsi_cmnd *scp;
3350 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003352 atomic_inc(&sdebug_completions);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003353 qa_indx = sd_dp->qa_indx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003354 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003355 pr_err("wild qa_indx=%d\n", qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 return;
3357 }
3358 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003359 sqcp = &queued_arr[qa_indx];
3360 scp = sqcp->a_cmnd;
3361 if (NULL == scp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003363 pr_err("scp is NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 return;
3365 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003366 devip = (struct sdebug_dev_info *)scp->device->hostdata;
3367 if (devip)
3368 atomic_dec(&devip->num_in_q);
3369 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003370 pr_err("devip=NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003371 if (atomic_read(&retired_max_queue) > 0)
3372 retiring = 1;
3373
3374 sqcp->a_cmnd = NULL;
3375 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3376 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003377 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003378 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003380
3381 if (unlikely(retiring)) { /* user has reduced max_queue */
3382 int k, retval;
3383
3384 retval = atomic_read(&retired_max_queue);
3385 if (qa_indx >= retval) {
3386 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003387 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003388 return;
3389 }
3390 k = find_last_bit(queued_in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003391 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003392 atomic_set(&retired_max_queue, 0);
3393 else
3394 atomic_set(&retired_max_queue, k + 1);
3395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003397 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398}
3399
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003400/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003401static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003402{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003403 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3404 hrt);
3405 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003406 return HRTIMER_NORESTART;
3407}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
Douglas Gilberta10bc122016-04-25 12:16:32 -04003409/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003410static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003411{
3412 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3413 ew.work);
3414 sdebug_q_cmd_complete(sd_dp);
3415}
3416
Douglas Gilbertfd321192016-04-25 12:16:33 -04003417static struct sdebug_dev_info *sdebug_device_create(
3418 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003419{
3420 struct sdebug_dev_info *devip;
3421
3422 devip = kzalloc(sizeof(*devip), flags);
3423 if (devip) {
3424 devip->sdbg_host = sdbg_host;
3425 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3426 }
3427 return devip;
3428}
3429
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
3431{
3432 struct sdebug_host_info * sdbg_host;
3433 struct sdebug_dev_info * open_devip = NULL;
3434 struct sdebug_dev_info * devip =
3435 (struct sdebug_dev_info *)sdev->hostdata;
3436
3437 if (devip)
3438 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003439 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3440 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003441 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 return NULL;
3443 }
3444 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3445 if ((devip->used) && (devip->channel == sdev->channel) &&
3446 (devip->target == sdev->id) &&
3447 (devip->lun == sdev->lun))
3448 return devip;
3449 else {
3450 if ((!devip->used) && (!open_devip))
3451 open_devip = devip;
3452 }
3453 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003454 if (!open_devip) { /* try and make a new one */
3455 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3456 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003457 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 return NULL;
3459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003461
3462 open_devip->channel = sdev->channel;
3463 open_devip->target = sdev->id;
3464 open_devip->lun = sdev->lun;
3465 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003466 atomic_set(&open_devip->num_in_q, 0);
3467 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003468 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003469 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470}
3471
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003472static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003474 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003475 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003476 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003477 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003478 return 0;
3479}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003481static int scsi_debug_slave_configure(struct scsi_device *sdp)
3482{
3483 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003484
Douglas Gilbert773642d2016-04-25 12:16:28 -04003485 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003486 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003487 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3488 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
3489 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
3490 devip = devInfoReg(sdp);
3491 if (NULL == devip)
3492 return 1; /* no resources, will be marked offline */
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003493 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003494 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003495 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003496 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003497 return 0;
3498}
3499
3500static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3501{
3502 struct sdebug_dev_info *devip =
3503 (struct sdebug_dev_info *)sdp->hostdata;
3504
Douglas Gilbert773642d2016-04-25 12:16:28 -04003505 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003506 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003507 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3508 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003509 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003510 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003511 sdp->hostdata = NULL;
3512 }
3513}
3514
Douglas Gilberta10bc122016-04-25 12:16:32 -04003515/* If @cmnd found deletes its timer or work queue and returns true; else
3516 returns false */
3517static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003518{
3519 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003520 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003521 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003522 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003523 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003524
3525 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003526 qmax = sdebug_max_queue;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003527 r_qmax = atomic_read(&retired_max_queue);
3528 if (r_qmax > qmax)
3529 qmax = r_qmax;
3530 for (k = 0; k < qmax; ++k) {
3531 if (test_bit(k, queued_in_use_bm)) {
3532 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003533 if (cmnd != sqcp->a_cmnd)
3534 continue;
3535 /* found command */
3536 devip = (struct sdebug_dev_info *)
3537 cmnd->device->hostdata;
3538 if (devip)
3539 atomic_dec(&devip->num_in_q);
3540 sqcp->a_cmnd = NULL;
3541 sd_dp = sqcp->sd_dp;
3542 spin_unlock_irqrestore(&queued_arr_lock,
3543 iflags);
3544 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
3545 if (sd_dp)
3546 hrtimer_cancel(&sd_dp->hrt);
3547 } else if (sdebug_jdelay < 0) {
3548 if (sd_dp)
3549 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003550 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003551 clear_bit(k, queued_in_use_bm);
3552 return true;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003553 }
3554 }
3555 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003556 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003557}
3558
Douglas Gilberta10bc122016-04-25 12:16:32 -04003559/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003560static void stop_all_queued(void)
3561{
3562 unsigned long iflags;
3563 int k;
3564 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003565 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003566 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003567
3568 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003569 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3570 if (test_bit(k, queued_in_use_bm)) {
3571 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003572 if (NULL == sqcp->a_cmnd)
3573 continue;
3574 devip = (struct sdebug_dev_info *)
3575 sqcp->a_cmnd->device->hostdata;
3576 if (devip)
3577 atomic_dec(&devip->num_in_q);
3578 sqcp->a_cmnd = NULL;
3579 sd_dp = sqcp->sd_dp;
3580 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3581 if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) {
3582 if (sd_dp)
3583 hrtimer_cancel(&sd_dp->hrt);
3584 } else if (sdebug_jdelay < 0) {
3585 if (sd_dp)
3586 cancel_work_sync(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003587 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003588 clear_bit(k, queued_in_use_bm);
3589 spin_lock_irqsave(&queued_arr_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003590 }
3591 }
3592 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593}
3594
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003595/* Free queued command memory on heap */
3596static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003598 int k;
3599 struct sdebug_queued_cmd *sqcp;
3600
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003601 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3602 sqcp = &queued_arr[k];
Douglas Gilberta10bc122016-04-25 12:16:32 -04003603 kfree(sqcp->sd_dp);
3604 sqcp->sd_dp = NULL;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606}
3607
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003608static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003610 bool ok;
3611
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003612 ++num_aborts;
3613 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04003614 ok = stop_queued_cmnd(SCpnt);
3615 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
3616 sdev_printk(KERN_INFO, SCpnt->device,
3617 "%s: command%s found\n", __func__,
3618 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003620 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621}
3622
3623static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3624{
3625 struct sdebug_dev_info * devip;
3626
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003628 if (SCpnt && SCpnt->device) {
3629 struct scsi_device *sdp = SCpnt->device;
3630
Douglas Gilbert773642d2016-04-25 12:16:28 -04003631 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003632 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3633 devip = devInfoReg(sdp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003635 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 }
3637 return SUCCESS;
3638}
3639
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003640static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3641{
3642 struct sdebug_host_info *sdbg_host;
3643 struct sdebug_dev_info *devip;
3644 struct scsi_device *sdp;
3645 struct Scsi_Host *hp;
3646 int k = 0;
3647
3648 ++num_target_resets;
3649 if (!SCpnt)
3650 goto lie;
3651 sdp = SCpnt->device;
3652 if (!sdp)
3653 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003654 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003655 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3656 hp = sdp->host;
3657 if (!hp)
3658 goto lie;
3659 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3660 if (sdbg_host) {
3661 list_for_each_entry(devip,
3662 &sdbg_host->dev_info_list,
3663 dev_list)
3664 if (devip->target == sdp->id) {
3665 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3666 ++k;
3667 }
3668 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003669 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003670 sdev_printk(KERN_INFO, sdp,
3671 "%s: %d device(s) found in target\n", __func__, k);
3672lie:
3673 return SUCCESS;
3674}
3675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3677{
3678 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003679 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 struct scsi_device * sdp;
3681 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003682 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003685 if (!(SCpnt && SCpnt->device))
3686 goto lie;
3687 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003688 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003689 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3690 hp = sdp->host;
3691 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003692 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003694 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003696 dev_list) {
3697 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3698 ++k;
3699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 }
3701 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003702 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003703 sdev_printk(KERN_INFO, sdp,
3704 "%s: %d device(s) found in host\n", __func__, k);
3705lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 return SUCCESS;
3707}
3708
3709static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3710{
3711 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003712 struct sdebug_dev_info *devip;
3713 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003716 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003717 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 spin_lock(&sdebug_host_list_lock);
3719 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003720 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3721 dev_list) {
3722 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3723 ++k;
3724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 }
3726 spin_unlock(&sdebug_host_list_lock);
3727 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04003728 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003729 sdev_printk(KERN_INFO, SCpnt->device,
3730 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 return SUCCESS;
3732}
3733
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003734static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003735 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736{
3737 struct partition * pp;
3738 int starts[SDEBUG_MAX_PARTS + 2];
3739 int sectors_per_part, num_sectors, k;
3740 int heads_by_sects, start_sec, end_sec;
3741
3742 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003743 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003745 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
3746 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03003747 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003749 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003751 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3753 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003754 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3756 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003757 starts[sdebug_num_parts] = num_sectors;
3758 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759
3760 ramp[510] = 0x55; /* magic partition markings */
3761 ramp[511] = 0xAA;
3762 pp = (struct partition *)(ramp + 0x1be);
3763 for (k = 0; starts[k + 1]; ++k, ++pp) {
3764 start_sec = starts[k];
3765 end_sec = starts[k + 1] - 1;
3766 pp->boot_ind = 0;
3767
3768 pp->cyl = start_sec / heads_by_sects;
3769 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3770 / sdebug_sectors_per;
3771 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3772
3773 pp->end_cyl = end_sec / heads_by_sects;
3774 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3775 / sdebug_sectors_per;
3776 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3777
Akinobu Mita150c3542013-08-26 22:08:40 +09003778 pp->start_sect = cpu_to_le32(start_sec);
3779 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 pp->sys_ind = 0x83; /* plain Linux partition */
3781 }
3782}
3783
Douglas Gilbertfd321192016-04-25 12:16:33 -04003784static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3785 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003787 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003788 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003789 struct sdebug_queued_cmd *sqcp = NULL;
Tomas Winkler299b6c02015-07-28 16:54:24 +03003790 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003791 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792
Tomas Winkler299b6c02015-07-28 16:54:24 +03003793 /* this should never happen */
3794 if (WARN_ON(!cmnd))
3795 return SCSI_MLQUEUE_HOST_BUSY;
3796
3797 if (NULL == devip) {
3798 pr_warn("called devip == NULL\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003799 /* no particularly good error to report back */
3800 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03003802
3803 sdp = cmnd->device;
3804
Douglas Gilbert773642d2016-04-25 12:16:28 -04003805 if (sdebug_verbose && scsi_result)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003806 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3807 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003808 if (delta_jiff == 0)
3809 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003811 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003812 spin_lock_irqsave(&queued_arr_lock, iflags);
3813 num_in_q = atomic_read(&devip->num_in_q);
3814 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003815 inject = 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003816 if ((qdepth > 0) && (num_in_q >= qdepth)) {
3817 if (scsi_result) {
3818 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3819 goto respond_in_thread;
3820 } else
3821 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003822 } else if ((sdebug_every_nth != 0) &&
3823 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003824 (scsi_result == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003825 if ((num_in_q == (qdepth - 1)) &&
3826 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04003827 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003828 atomic_set(&sdebug_a_tsf, 0);
3829 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003830 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003832 }
3833
Douglas Gilbert773642d2016-04-25 12:16:28 -04003834 k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue);
3835 if (k >= sdebug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003837 if (scsi_result)
3838 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003839 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003840 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003841 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003842 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003843 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003844 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003845 (scsi_result ? "status: TASK SET FULL" :
3846 "report: host busy"));
3847 if (scsi_result)
3848 goto respond_in_thread;
3849 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003850 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003852 __set_bit(k, queued_in_use_bm);
3853 atomic_inc(&devip->num_in_q);
3854 sqcp = &queued_arr[k];
3855 sqcp->a_cmnd = cmnd;
3856 cmnd->result = scsi_result;
3857 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003858 sd_dp = sqcp->sd_dp;
Douglas Gilbertb333a812016-04-25 12:16:30 -04003859 if ((delta_jiff > 0) || (sdebug_ndelay > 0)) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04003860 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003861
Douglas Gilbertb333a812016-04-25 12:16:30 -04003862 if (delta_jiff > 0) {
3863 struct timespec ts;
3864
3865 jiffies_to_timespec(delta_jiff, &ts);
3866 kt = ktime_set(ts.tv_sec, ts.tv_nsec);
3867 } else
3868 kt = ktime_set(0, sdebug_ndelay);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003869 if (NULL == sd_dp) {
3870 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
3871 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003872 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003873 sqcp->sd_dp = sd_dp;
3874 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003875 HRTIMER_MODE_REL);
Douglas Gilberta10bc122016-04-25 12:16:32 -04003876 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
3877 sd_dp->qa_indx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003878 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003879 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003880 } else { /* jdelay < 0 */
Douglas Gilberta10bc122016-04-25 12:16:32 -04003881 if (NULL == sd_dp) {
3882 sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC);
3883 if (NULL == sd_dp)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003884 return SCSI_MLQUEUE_HOST_BUSY;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003885 sqcp->sd_dp = sd_dp;
3886 sd_dp->qa_indx = k;
3887 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003888 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003889 schedule_work(&sd_dp->ew.work);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003890 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04003891 if ((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003892 (scsi_result == device_qfull_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003893 sdev_printk(KERN_INFO, sdp,
3894 "%s: num_in_q=%d +1, %s%s\n", __func__,
3895 num_in_q, (inject ? "<inject> " : ""),
3896 "status: TASK SET FULL");
3897 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003898
3899respond_in_thread: /* call back to mid-layer using invocation thread */
3900 cmnd->result = scsi_result;
3901 cmnd->scsi_done(cmnd);
3902 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003904
Douglas Gilbert23183912006-09-16 20:30:47 -04003905/* Note: The following macros create attribute files in the
3906 /sys/module/scsi_debug/parameters directory. Unfortunately this
3907 driver is unaware of a change and cannot trigger auxiliary actions
3908 as it can when the corresponding attribute in the
3909 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3910 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003911module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
3912module_param_named(ato, sdebug_ato, int, S_IRUGO);
3913module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04003914module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003915module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
3916module_param_named(dif, sdebug_dif, int, S_IRUGO);
3917module_param_named(dix, sdebug_dix, int, S_IRUGO);
3918module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
3919module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
3920module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
3921module_param_named(guard, sdebug_guard, uint, S_IRUGO);
3922module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
3923module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
3924module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
3925module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
3926module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
3927module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
3928module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
3929module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
3930module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
3931module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
3932module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
3933module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
3934module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
3935module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
3936module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
3937module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
3938module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
3939module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
3940module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
3941module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
3942module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
3943module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
3944module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
3945module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
3946module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
3947module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
3948module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04003949 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003950module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003951 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952
3953MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
3954MODULE_DESCRIPTION("SCSI debug adapter driver");
3955MODULE_LICENSE("GPL");
3956MODULE_VERSION(SCSI_DEBUG_VERSION);
3957
3958MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003959MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09003960MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003961MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003962MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003963MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
3964MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003965MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07003966MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04003967MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003968MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04003969MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003970MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
3971MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
3972MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003973MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003974MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003975MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003976MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3977MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003978MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003979MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003981MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05003982MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05003983MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003984MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02003986MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02003987MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003988MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003989MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003990MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
3991MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04003992MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
3993MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003994MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003995MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
3996MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997
3998static char sdebug_info[256];
3999
4000static const char * scsi_debug_info(struct Scsi_Host * shp)
4001{
4002 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
4003 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004004 sdebug_version_date, sdebug_dev_size_mb, sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 return sdebug_info;
4006}
4007
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004008/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004009static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4010 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011{
Al Viroc8ed5552013-03-31 01:46:06 -04004012 char arr[16];
4013 int opts;
4014 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015
Al Viroc8ed5552013-03-31 01:46:06 -04004016 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4017 return -EACCES;
4018 memcpy(arr, buffer, minLen);
4019 arr[minLen] = '\0';
4020 if (1 != sscanf(arr, "%d", &opts))
4021 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004022 sdebug_opts = opts;
4023 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4024 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4025 if (sdebug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004026 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04004027 return length;
4028}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004030/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4031 * same for each scsi_debug host (if more than one). Some of the counters
4032 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004033static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4034{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004035 int f, l;
4036 char b[32];
4037
Douglas Gilbert773642d2016-04-25 12:16:28 -04004038 if (sdebug_every_nth > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004039 snprintf(b, sizeof(b), " (curr:%d)",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004040 ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ?
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004041 atomic_read(&sdebug_a_tsf) :
4042 atomic_read(&sdebug_cmnd_count)));
4043 else
4044 b[0] = '\0';
4045
4046 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
4047 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
4048 "every_nth=%d%s\n"
4049 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
4050 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
4051 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
4052 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
4053 "usec_in_jiffy=%lu\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004054 SCSI_DEBUG_VERSION, sdebug_version_date,
4055 sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04004056 sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay,
Douglas Gilbert773642d2016-04-25 12:16:28 -04004057 sdebug_max_luns, atomic_read(&sdebug_completions),
4058 sdebug_sector_size, sdebug_cylinders_per, sdebug_heads,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004059 sdebug_sectors_per, num_aborts, num_dev_resets,
4060 num_target_resets, num_bus_resets, num_host_resets,
4061 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
4062
Douglas Gilbert773642d2016-04-25 12:16:28 -04004063 f = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4064 if (f != sdebug_max_queue) {
4065 l = find_last_bit(queued_in_use_bm, sdebug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004066 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
4067 "queued_in_use_bm", f, l);
4068 }
Al Viroc8ed5552013-03-31 01:46:06 -04004069 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070}
4071
Akinobu Mita82069372013-10-14 22:48:04 +09004072static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004074 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075}
Douglas Gilbertc2206092016-04-25 12:16:31 -04004076/* Returns -EBUSY if jdelay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09004077static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4078 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004080 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081
Douglas Gilbertc2206092016-04-25 12:16:31 -04004082 if ((count > 0) && (1 == sscanf(buf, "%d", &jdelay))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004083 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004084 if (sdebug_jdelay != jdelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004085 unsigned long iflags;
4086 int k;
4087
4088 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004089 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4090 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004091 res = -EBUSY; /* have queued commands */
4092 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004093 /* make sure sdebug_defer instances get
4094 * re-allocated for new delay variant */
4095 free_all_queued();
Douglas Gilbertc2206092016-04-25 12:16:31 -04004096 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004097 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004098 }
4099 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004101 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 }
4103 return -EINVAL;
4104}
Akinobu Mita82069372013-10-14 22:48:04 +09004105static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004107static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4108{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004109 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004110}
4111/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004112/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004113static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004114 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004115{
4116 unsigned long iflags;
4117 int ndelay, res, k;
4118
4119 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
4120 (ndelay >= 0) && (ndelay < 1000000000)) {
4121 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004122 if (sdebug_ndelay != ndelay) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004123 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004124 k = find_first_bit(queued_in_use_bm, sdebug_max_queue);
4125 if (k != sdebug_max_queue)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004126 res = -EBUSY; /* have queued commands */
4127 else {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004128 /* make sure sdebug_defer instances get
4129 * re-allocated for new delay variant */
4130 free_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004131 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004132 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4133 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004134 }
4135 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4136 }
4137 return res;
4138 }
4139 return -EINVAL;
4140}
4141static DRIVER_ATTR_RW(ndelay);
4142
Akinobu Mita82069372013-10-14 22:48:04 +09004143static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004145 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146}
4147
Akinobu Mita82069372013-10-14 22:48:04 +09004148static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4149 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150{
4151 int opts;
4152 char work[20];
4153
4154 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07004155 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 if (1 == sscanf(&work[2], "%x", &opts))
4157 goto opts_done;
4158 } else {
4159 if (1 == sscanf(work, "%d", &opts))
4160 goto opts_done;
4161 }
4162 }
4163 return -EINVAL;
4164opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004165 sdebug_opts = opts;
4166 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4167 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004168 atomic_set(&sdebug_cmnd_count, 0);
4169 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 return count;
4171}
Akinobu Mita82069372013-10-14 22:48:04 +09004172static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173
Akinobu Mita82069372013-10-14 22:48:04 +09004174static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004176 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177}
Akinobu Mita82069372013-10-14 22:48:04 +09004178static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4179 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180{
4181 int n;
4182
4183 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004184 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 return count;
4186 }
4187 return -EINVAL;
4188}
Akinobu Mita82069372013-10-14 22:48:04 +09004189static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190
Akinobu Mita82069372013-10-14 22:48:04 +09004191static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004193 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194}
Akinobu Mita82069372013-10-14 22:48:04 +09004195static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4196 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197{
4198 int n;
4199
4200 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004201 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 return count;
4203 }
4204 return -EINVAL;
4205}
Akinobu Mita82069372013-10-14 22:48:04 +09004206static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207
Akinobu Mita82069372013-10-14 22:48:04 +09004208static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004209{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004210 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004211}
Akinobu Mita82069372013-10-14 22:48:04 +09004212static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4213 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004214{
4215 int n;
4216
4217 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004218 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004219 sdebug_fake_rw = (sdebug_fake_rw > 0);
4220 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004221 if ((0 == n) && (NULL == fake_storep)) {
4222 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004223 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004224 1048576;
4225
4226 fake_storep = vmalloc(sz);
4227 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004228 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004229 return -ENOMEM;
4230 }
4231 memset(fake_storep, 0, sz);
4232 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004233 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004234 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004235 return count;
4236 }
4237 return -EINVAL;
4238}
Akinobu Mita82069372013-10-14 22:48:04 +09004239static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004240
Akinobu Mita82069372013-10-14 22:48:04 +09004241static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004242{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004243 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004244}
Akinobu Mita82069372013-10-14 22:48:04 +09004245static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4246 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004247{
4248 int n;
4249
4250 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004251 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004252 return count;
4253 }
4254 return -EINVAL;
4255}
Akinobu Mita82069372013-10-14 22:48:04 +09004256static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004257
Akinobu Mita82069372013-10-14 22:48:04 +09004258static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004260 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261}
Akinobu Mita82069372013-10-14 22:48:04 +09004262static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4263 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264{
4265 int n;
4266
4267 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004268 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 sdebug_max_tgts_luns();
4270 return count;
4271 }
4272 return -EINVAL;
4273}
Akinobu Mita82069372013-10-14 22:48:04 +09004274static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275
Akinobu Mita82069372013-10-14 22:48:04 +09004276static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004278 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279}
Akinobu Mita82069372013-10-14 22:48:04 +09004280static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281
Akinobu Mita82069372013-10-14 22:48:04 +09004282static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004284 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285}
Akinobu Mita82069372013-10-14 22:48:04 +09004286static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
Akinobu Mita82069372013-10-14 22:48:04 +09004288static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004290 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291}
Akinobu Mita82069372013-10-14 22:48:04 +09004292static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4293 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294{
4295 int nth;
4296
4297 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004298 sdebug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004299 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 return count;
4301 }
4302 return -EINVAL;
4303}
Akinobu Mita82069372013-10-14 22:48:04 +09004304static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305
Akinobu Mita82069372013-10-14 22:48:04 +09004306static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004308 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309}
Akinobu Mita82069372013-10-14 22:48:04 +09004310static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4311 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312{
4313 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004314 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315
4316 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004317 changed = (sdebug_max_luns != n);
4318 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004320 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004321 struct sdebug_host_info *sdhp;
4322 struct sdebug_dev_info *dp;
4323
4324 spin_lock(&sdebug_host_list_lock);
4325 list_for_each_entry(sdhp, &sdebug_host_list,
4326 host_list) {
4327 list_for_each_entry(dp, &sdhp->dev_info_list,
4328 dev_list) {
4329 set_bit(SDEBUG_UA_LUNS_CHANGED,
4330 dp->uas_bm);
4331 }
4332 }
4333 spin_unlock(&sdebug_host_list_lock);
4334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 return count;
4336 }
4337 return -EINVAL;
4338}
Akinobu Mita82069372013-10-14 22:48:04 +09004339static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
Akinobu Mita82069372013-10-14 22:48:04 +09004341static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004342{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004343 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004344}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004345/* N.B. max_queue can be changed while there are queued commands. In flight
4346 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004347static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4348 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004349{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004350 unsigned long iflags;
4351 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004352
4353 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4354 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004355 spin_lock_irqsave(&queued_arr_lock, iflags);
4356 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004357 sdebug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004358 if (SCSI_DEBUG_CANQUEUE == k)
4359 atomic_set(&retired_max_queue, 0);
4360 else if (k >= n)
4361 atomic_set(&retired_max_queue, k + 1);
4362 else
4363 atomic_set(&retired_max_queue, 0);
4364 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004365 return count;
4366 }
4367 return -EINVAL;
4368}
Akinobu Mita82069372013-10-14 22:48:04 +09004369static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004370
Akinobu Mita82069372013-10-14 22:48:04 +09004371static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004372{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004373 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004374}
Akinobu Mita82069372013-10-14 22:48:04 +09004375static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004376
Akinobu Mita82069372013-10-14 22:48:04 +09004377static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004379 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380}
Akinobu Mita82069372013-10-14 22:48:04 +09004381static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382
Akinobu Mita82069372013-10-14 22:48:04 +09004383static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004384{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004385 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004386}
Akinobu Mita82069372013-10-14 22:48:04 +09004387static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4388 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004389{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004390 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004391 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004392
4393 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004394 changed = (sdebug_virtual_gb != n);
4395 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004396 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004397 if (changed) {
4398 struct sdebug_host_info *sdhp;
4399 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004400
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004401 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004402 list_for_each_entry(sdhp, &sdebug_host_list,
4403 host_list) {
4404 list_for_each_entry(dp, &sdhp->dev_info_list,
4405 dev_list) {
4406 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4407 dp->uas_bm);
4408 }
4409 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004410 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004411 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004412 return count;
4413 }
4414 return -EINVAL;
4415}
Akinobu Mita82069372013-10-14 22:48:04 +09004416static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004417
Akinobu Mita82069372013-10-14 22:48:04 +09004418static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004420 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421}
4422
Douglas Gilbertfd321192016-04-25 12:16:33 -04004423static int sdebug_add_adapter(void);
4424static void sdebug_remove_adapter(void);
4425
Akinobu Mita82069372013-10-14 22:48:04 +09004426static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4427 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004429 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004431 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 if (delta_hosts > 0) {
4434 do {
4435 sdebug_add_adapter();
4436 } while (--delta_hosts);
4437 } else if (delta_hosts < 0) {
4438 do {
4439 sdebug_remove_adapter();
4440 } while (++delta_hosts);
4441 }
4442 return count;
4443}
Akinobu Mita82069372013-10-14 22:48:04 +09004444static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445
Akinobu Mita82069372013-10-14 22:48:04 +09004446static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004447{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004448 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004449}
Akinobu Mita82069372013-10-14 22:48:04 +09004450static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4451 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004452{
4453 int n;
4454
4455 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004456 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004457 return count;
4458 }
4459 return -EINVAL;
4460}
Akinobu Mita82069372013-10-14 22:48:04 +09004461static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004462
Akinobu Mita82069372013-10-14 22:48:04 +09004463static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004464{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004465 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004466}
Akinobu Mita82069372013-10-14 22:48:04 +09004467static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004468
Akinobu Mita82069372013-10-14 22:48:04 +09004469static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004470{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004471 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004472}
Akinobu Mita82069372013-10-14 22:48:04 +09004473static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004474
Akinobu Mita82069372013-10-14 22:48:04 +09004475static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004476{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004477 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004478}
Akinobu Mita82069372013-10-14 22:48:04 +09004479static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004480
Akinobu Mita82069372013-10-14 22:48:04 +09004481static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004482{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004483 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004484}
Akinobu Mita82069372013-10-14 22:48:04 +09004485static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004486
Akinobu Mita82069372013-10-14 22:48:04 +09004487static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004488{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004489 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004490}
Akinobu Mita82069372013-10-14 22:48:04 +09004491static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004492
Akinobu Mita82069372013-10-14 22:48:04 +09004493static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004494{
4495 ssize_t count;
4496
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004497 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004498 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4499 sdebug_store_sectors);
4500
Tejun Heoc7badc92015-02-13 14:37:51 -08004501 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
4502 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004503 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08004504 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04004505
4506 return count;
4507}
Akinobu Mita82069372013-10-14 22:48:04 +09004508static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004509
Akinobu Mita82069372013-10-14 22:48:04 +09004510static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004511{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004512 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02004513}
Akinobu Mita82069372013-10-14 22:48:04 +09004514static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4515 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004516{
4517 int n;
4518
4519 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004520 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02004521 return count;
4522 }
4523 return -EINVAL;
4524}
Akinobu Mita82069372013-10-14 22:48:04 +09004525static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004526
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004527static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4528{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004529 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004530}
Douglas Gilbert185dd232016-04-25 12:16:29 -04004531/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004532static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4533 size_t count)
4534{
Douglas Gilbert185dd232016-04-25 12:16:29 -04004535 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004536
4537 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04004538 sdebug_host_lock = (n > 0);
4539 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004540 }
4541 return -EINVAL;
4542}
4543static DRIVER_ATTR_RW(host_lock);
4544
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004545static ssize_t strict_show(struct device_driver *ddp, char *buf)
4546{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004547 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004548}
4549static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4550 size_t count)
4551{
4552 int n;
4553
4554 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004555 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004556 return count;
4557 }
4558 return -EINVAL;
4559}
4560static DRIVER_ATTR_RW(strict);
4561
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004562
Akinobu Mita82069372013-10-14 22:48:04 +09004563/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004564 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4565 files (over those found in the /sys/module/scsi_debug/parameters
4566 directory) is that auxiliary actions can be triggered when an attribute
4567 is changed. For example see: sdebug_add_host_store() above.
4568 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004569
Akinobu Mita82069372013-10-14 22:48:04 +09004570static struct attribute *sdebug_drv_attrs[] = {
4571 &driver_attr_delay.attr,
4572 &driver_attr_opts.attr,
4573 &driver_attr_ptype.attr,
4574 &driver_attr_dsense.attr,
4575 &driver_attr_fake_rw.attr,
4576 &driver_attr_no_lun_0.attr,
4577 &driver_attr_num_tgts.attr,
4578 &driver_attr_dev_size_mb.attr,
4579 &driver_attr_num_parts.attr,
4580 &driver_attr_every_nth.attr,
4581 &driver_attr_max_luns.attr,
4582 &driver_attr_max_queue.attr,
4583 &driver_attr_no_uld.attr,
4584 &driver_attr_scsi_level.attr,
4585 &driver_attr_virtual_gb.attr,
4586 &driver_attr_add_host.attr,
4587 &driver_attr_vpd_use_hostno.attr,
4588 &driver_attr_sector_size.attr,
4589 &driver_attr_dix.attr,
4590 &driver_attr_dif.attr,
4591 &driver_attr_guard.attr,
4592 &driver_attr_ato.attr,
4593 &driver_attr_map.attr,
4594 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004595 &driver_attr_host_lock.attr,
4596 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004597 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004598 NULL,
4599};
4600ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004602static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004603
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604static int __init scsi_debug_init(void)
4605{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004606 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 int host_to_add;
4608 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004609 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004611 atomic_set(&sdebug_cmnd_count, 0);
4612 atomic_set(&sdebug_completions, 0);
4613 atomic_set(&retired_max_queue, 0);
4614
Douglas Gilbert773642d2016-04-25 12:16:28 -04004615 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004616 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04004617 sdebug_ndelay = 0;
4618 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04004619 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004620
Douglas Gilbert773642d2016-04-25 12:16:28 -04004621 switch (sdebug_sector_size) {
Martin K. Petersen597136a2008-06-05 00:12:59 -04004622 case 512:
4623 case 1024:
4624 case 2048:
4625 case 4096:
4626 break;
4627 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004628 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004629 return -EINVAL;
4630 }
4631
Douglas Gilbert773642d2016-04-25 12:16:28 -04004632 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004633
4634 case SD_DIF_TYPE0_PROTECTION:
4635 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004636 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004637 case SD_DIF_TYPE3_PROTECTION:
4638 break;
4639
4640 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03004641 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004642 return -EINVAL;
4643 }
4644
Douglas Gilbert773642d2016-04-25 12:16:28 -04004645 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004646 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004647 return -EINVAL;
4648 }
4649
Douglas Gilbert773642d2016-04-25 12:16:28 -04004650 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004651 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004652 return -EINVAL;
4653 }
4654
Douglas Gilbert773642d2016-04-25 12:16:28 -04004655 if (sdebug_physblk_exp > 15) {
4656 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004657 return -EINVAL;
4658 }
4659
Douglas Gilbert773642d2016-04-25 12:16:28 -04004660 if (sdebug_lowest_aligned > 0x3fff) {
4661 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004662 return -EINVAL;
4663 }
4664
Douglas Gilbert773642d2016-04-25 12:16:28 -04004665 if (sdebug_dev_size_mb < 1)
4666 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
4667 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
4668 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004669 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
4671 /* play around with geometry, don't waste too much on track 0 */
4672 sdebug_heads = 8;
4673 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004674 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004676 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02004677 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4679 (sdebug_sectors_per * sdebug_heads);
4680 if (sdebug_cylinders_per >= 1024) {
4681 /* other LLDs do this; implies >= 1GB ram disk ... */
4682 sdebug_heads = 255;
4683 sdebug_sectors_per = 63;
4684 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4685 (sdebug_sectors_per * sdebug_heads);
4686 }
4687
Douglas Gilbert773642d2016-04-25 12:16:28 -04004688 if (0 == sdebug_fake_rw) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004689 fake_storep = vmalloc(sz);
4690 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004691 pr_err("out of memory, 1\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004692 return -ENOMEM;
4693 }
4694 memset(fake_storep, 0, sz);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004695 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004696 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698
Douglas Gilbert773642d2016-04-25 12:16:28 -04004699 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004700 int dif_size;
4701
4702 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4703 dif_storep = vmalloc(dif_size);
4704
Tomas Winklerc12879702015-07-28 16:54:20 +03004705 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004706
4707 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004708 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004709 ret = -ENOMEM;
4710 goto free_vm;
4711 }
4712
4713 memset(dif_storep, 0xff, dif_size);
4714 }
4715
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004716 /* Logical Block Provisioning */
4717 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004718 sdebug_unmap_max_blocks =
4719 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004720
Douglas Gilbert773642d2016-04-25 12:16:28 -04004721 sdebug_unmap_max_desc =
4722 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04004723
Douglas Gilbert773642d2016-04-25 12:16:28 -04004724 sdebug_unmap_granularity =
4725 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04004726
Douglas Gilbert773642d2016-04-25 12:16:28 -04004727 if (sdebug_unmap_alignment &&
4728 sdebug_unmap_granularity <=
4729 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004730 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004731 return -EINVAL;
4732 }
4733
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004734 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4735 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004736
Tomas Winklerc12879702015-07-28 16:54:20 +03004737 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004738
4739 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004740 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04004741 ret = -ENOMEM;
4742 goto free_vm;
4743 }
4744
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004745 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004746
4747 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004748 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004749 map_region(0, 2);
4750 }
4751
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004752 pseudo_primary = root_device_register("pseudo_0");
4753 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004754 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004755 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004756 goto free_vm;
4757 }
4758 ret = bus_register(&pseudo_lld_bus);
4759 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004760 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004761 goto dev_unreg;
4762 }
4763 ret = driver_register(&sdebug_driverfs_driver);
4764 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004765 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004766 goto bus_unreg;
4767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
Douglas Gilbert773642d2016-04-25 12:16:28 -04004769 host_to_add = sdebug_add_host;
4770 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
4772 for (k = 0; k < host_to_add; k++) {
4773 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004774 pr_err("sdebug_add_adapter failed k=%d\n", k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 break;
4776 }
4777 }
4778
Douglas Gilbert773642d2016-04-25 12:16:28 -04004779 if (sdebug_verbose)
4780 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03004781
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004783
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004784bus_unreg:
4785 bus_unregister(&pseudo_lld_bus);
4786dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004787 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004788free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03004789 vfree(map_storep);
4790 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004791 vfree(fake_storep);
4792
4793 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794}
4795
4796static void __exit scsi_debug_exit(void)
4797{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004798 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799
4800 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004801 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 for (; k; k--)
4803 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 driver_unregister(&sdebug_driverfs_driver);
4805 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004806 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
Tomas Winklerde232af2015-07-28 16:54:22 +03004808 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 vfree(fake_storep);
4810}
4811
4812device_initcall(scsi_debug_init);
4813module_exit(scsi_debug_exit);
4814
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815static void sdebug_release_adapter(struct device * dev)
4816{
4817 struct sdebug_host_info *sdbg_host;
4818
4819 sdbg_host = to_sdebug_host(dev);
4820 kfree(sdbg_host);
4821}
4822
4823static int sdebug_add_adapter(void)
4824{
4825 int k, devs_per_host;
4826 int error = 0;
4827 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004828 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004830 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 if (NULL == sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004832 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 return -ENOMEM;
4834 }
4835
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4837
Douglas Gilbert773642d2016-04-25 12:16:28 -04004838 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004840 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4841 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004842 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 error = -ENOMEM;
4844 goto clean;
4845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 }
4847
4848 spin_lock(&sdebug_host_list_lock);
4849 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4850 spin_unlock(&sdebug_host_list_lock);
4851
4852 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004853 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004855 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856
4857 error = device_register(&sdbg_host->dev);
4858
4859 if (error)
4860 goto clean;
4861
Douglas Gilbert773642d2016-04-25 12:16:28 -04004862 ++sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 return error;
4864
4865clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004866 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4867 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 list_del(&sdbg_devinfo->dev_list);
4869 kfree(sdbg_devinfo);
4870 }
4871
4872 kfree(sdbg_host);
4873 return error;
4874}
4875
4876static void sdebug_remove_adapter(void)
4877{
4878 struct sdebug_host_info * sdbg_host = NULL;
4879
4880 spin_lock(&sdebug_host_list_lock);
4881 if (!list_empty(&sdebug_host_list)) {
4882 sdbg_host = list_entry(sdebug_host_list.prev,
4883 struct sdebug_host_info, host_list);
4884 list_del(&sdbg_host->host_list);
4885 }
4886 spin_unlock(&sdebug_host_list_lock);
4887
4888 if (!sdbg_host)
4889 return;
4890
Douglas Gilbert773642d2016-04-25 12:16:28 -04004891 device_unregister(&sdbg_host->dev);
4892 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893}
4894
Douglas Gilbertfd321192016-04-25 12:16:33 -04004895static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004896{
4897 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004898 unsigned long iflags;
4899 struct sdebug_dev_info *devip;
4900
4901 spin_lock_irqsave(&queued_arr_lock, iflags);
4902 devip = (struct sdebug_dev_info *)sdev->hostdata;
4903 if (NULL == devip) {
4904 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4905 return -ENODEV;
4906 }
4907 num_in_q = atomic_read(&devip->num_in_q);
4908 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004909
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004910 if (qdepth < 1)
4911 qdepth = 1;
4912 /* allow to exceed max host queued_arr elements for testing */
4913 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4914 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004915 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004916
Douglas Gilbert773642d2016-04-25 12:16:28 -04004917 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004918 sdev_printk(KERN_INFO, sdev,
4919 "%s: qdepth=%d, num_in_q=%d\n",
4920 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004921 }
4922 return sdev->queue_depth;
4923}
4924
Douglas Gilbertfd321192016-04-25 12:16:33 -04004925static int check_inject(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004926{
4927 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4928
4929 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4930
Douglas Gilbert773642d2016-04-25 12:16:28 -04004931 if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) {
Douglas Gilbert817fd662014-11-24 20:18:02 -05004932 atomic_set(&sdebug_cmnd_count, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004933 if (sdebug_every_nth < -1)
4934 sdebug_every_nth = -1;
4935 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004936 return 1; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004937 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05004938 scsi_medium_access_command(scp))
4939 return 1; /* time out reads and writes */
4940 if (sdebug_any_injecting_opt) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004941 if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004942 ep->inj_recovered = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004943 if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004944 ep->inj_transport = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004945 if (SDEBUG_OPT_DIF_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004946 ep->inj_dif = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004947 if (SDEBUG_OPT_DIX_ERR & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004948 ep->inj_dix = true;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004949 if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts)
Douglas Gilbert817fd662014-11-24 20:18:02 -05004950 ep->inj_short = true;
4951 }
4952 }
4953 return 0;
4954}
4955
Douglas Gilbertfd321192016-04-25 12:16:33 -04004956static int scsi_debug_queuecommand(struct Scsi_Host *shost,
4957 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004958{
4959 u8 sdeb_i;
4960 struct scsi_device *sdp = scp->device;
4961 const struct opcode_info_t *oip;
4962 const struct opcode_info_t *r_oip;
4963 struct sdebug_dev_info *devip;
4964 u8 *cmd = scp->cmnd;
4965 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
4966 int k, na;
4967 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004968 u32 flags;
4969 u16 sa;
4970 u8 opcode = cmd[0];
4971 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004972
4973 scsi_set_resid(scp, 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004974 if (sdebug_verbose && !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004975 char b[120];
4976 int n, len, sb;
4977
4978 len = scp->cmd_len;
4979 sb = (int)sizeof(b);
4980 if (len > 32)
4981 strcpy(b, "too long, over 32 bytes");
4982 else {
4983 for (k = 0, n = 0; k < len && n < sb; ++k)
4984 n += scnprintf(b + n, sb - n, "%02x ",
4985 (u32)cmd[k]);
4986 }
4987 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
4988 }
Tomas Winkler34d55432015-07-28 16:54:21 +03004989 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004990 if ((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)
4991 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004992
4993 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
4994 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
4995 devip = (struct sdebug_dev_info *)sdp->hostdata;
4996 if (!devip) {
4997 devip = devInfoReg(sdp);
4998 if (NULL == devip)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004999 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16,
5000 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005001 }
5002 na = oip->num_attached;
5003 r_pfp = oip->pfp;
5004 if (na) { /* multiple commands with this opcode */
5005 r_oip = oip;
5006 if (FF_SA & r_oip->flags) {
5007 if (F_SA_LOW & oip->flags)
5008 sa = 0x1f & cmd[1];
5009 else
5010 sa = get_unaligned_be16(cmd + 8);
5011 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5012 if (opcode == oip->opcode && sa == oip->sa)
5013 break;
5014 }
5015 } else { /* since no service action only check opcode */
5016 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5017 if (opcode == oip->opcode)
5018 break;
5019 }
5020 }
5021 if (k > na) {
5022 if (F_SA_LOW & r_oip->flags)
5023 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5024 else if (F_SA_HIGH & r_oip->flags)
5025 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5026 else
5027 mk_sense_invalid_opcode(scp);
5028 goto check_cond;
5029 }
5030 } /* else (when na==0) we assume the oip is a match */
5031 flags = oip->flags;
5032 if (F_INV_OP & flags) {
5033 mk_sense_invalid_opcode(scp);
5034 goto check_cond;
5035 }
5036 if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005037 if (sdebug_verbose)
5038 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5039 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005040 mk_sense_invalid_opcode(scp);
5041 goto check_cond;
5042 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005043 if (sdebug_strict) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005044 u8 rem;
5045 int j;
5046
5047 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5048 rem = ~oip->len_mask[k] & cmd[k];
5049 if (rem) {
5050 for (j = 7; j >= 0; --j, rem <<= 1) {
5051 if (0x80 & rem)
5052 break;
5053 }
5054 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5055 goto check_cond;
5056 }
5057 }
5058 }
5059 if (!(F_SKIP_UA & flags) &&
5060 SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
5061 errsts = check_readiness(scp, UAS_ONLY, devip);
5062 if (errsts)
5063 goto check_cond;
5064 }
5065 if ((F_M_ACCESS & flags) && devip->stopped) {
5066 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005067 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005068 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5069 "%s\n", my_name, "initializing command "
5070 "required");
5071 errsts = check_condition_result;
5072 goto fini;
5073 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005074 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005075 goto fini;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005076 if (sdebug_every_nth) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005077 if (check_inject(scp))
5078 return 0; /* ignore command: make trouble */
5079 }
5080 if (oip->pfp) /* if this command has a resp_* function, call it */
5081 errsts = oip->pfp(scp, devip);
5082 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
5083 errsts = r_pfp(scp, devip);
5084
5085fini:
5086 return schedule_resp(scp, devip, errsts,
Douglas Gilbertc2206092016-04-25 12:16:31 -04005087 ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005088check_cond:
5089 return schedule_resp(scp, devip, check_condition_result, 0);
5090}
5091
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005092static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005093 .show_info = scsi_debug_show_info,
5094 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005095 .proc_name = sdebug_proc_name,
5096 .name = "SCSI DEBUG",
5097 .info = scsi_debug_info,
5098 .slave_alloc = scsi_debug_slave_alloc,
5099 .slave_configure = scsi_debug_slave_configure,
5100 .slave_destroy = scsi_debug_slave_destroy,
5101 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005102 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005103 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005104 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005105 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005106 .eh_target_reset_handler = scsi_debug_target_reset,
5107 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005108 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005109 .can_queue = SCSI_DEBUG_CANQUEUE,
5110 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005111 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005112 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005113 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005114 .use_clustering = DISABLE_CLUSTERING,
5115 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005116 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05005117 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005118};
5119
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120static int sdebug_driver_probe(struct device * dev)
5121{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005122 int error = 0;
5123 struct sdebug_host_info *sdbg_host;
5124 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005125 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126
5127 sdbg_host = to_sdebug_host(dev);
5128
Douglas Gilbert773642d2016-04-25 12:16:28 -04005129 sdebug_driver_template.can_queue = sdebug_max_queue;
5130 if (sdebug_clustering)
Akinobu Mita0759c662014-02-26 22:57:04 +09005131 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005132 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5133 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005134 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005135 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005136 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138
5139 sdbg_host->shost = hpnt;
5140 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005141 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5142 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005144 hpnt->max_id = sdebug_num_tgts;
5145 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005146 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005148 host_prot = 0;
5149
Douglas Gilbert773642d2016-04-25 12:16:28 -04005150 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005151
5152 case SD_DIF_TYPE1_PROTECTION:
5153 host_prot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005154 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005155 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
5156 break;
5157
5158 case SD_DIF_TYPE2_PROTECTION:
5159 host_prot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005160 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005161 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
5162 break;
5163
5164 case SD_DIF_TYPE3_PROTECTION:
5165 host_prot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005166 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005167 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
5168 break;
5169
5170 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005171 if (sdebug_dix)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005172 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
5173 break;
5174 }
5175
5176 scsi_host_set_prot(hpnt, host_prot);
5177
Tomas Winklerc12879702015-07-28 16:54:20 +03005178 pr_info("host protection%s%s%s%s%s%s%s\n",
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005179 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5180 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5181 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5182 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5183 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5184 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5185 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5186
Douglas Gilbert773642d2016-04-25 12:16:28 -04005187 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005188 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5189 else
5190 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5191
Douglas Gilbert773642d2016-04-25 12:16:28 -04005192 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5193 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 error = scsi_add_host(hpnt, &sdbg_host->dev);
5195 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005196 pr_err("scsi_add_host failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 error = -ENODEV;
5198 scsi_host_put(hpnt);
5199 } else
5200 scsi_scan_host(hpnt);
5201
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005202 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203}
5204
5205static int sdebug_driver_remove(struct device * dev)
5206{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005208 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209
5210 sdbg_host = to_sdebug_host(dev);
5211
5212 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005213 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 return -ENODEV;
5215 }
5216
5217 scsi_remove_host(sdbg_host->shost);
5218
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005219 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5220 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 list_del(&sdbg_devinfo->dev_list);
5222 kfree(sdbg_devinfo);
5223 }
5224
5225 scsi_host_put(sdbg_host->shost);
5226 return 0;
5227}
5228
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005229static int pseudo_lld_bus_match(struct device *dev,
5230 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005232 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005234
5235static struct bus_type pseudo_lld_bus = {
5236 .name = "pseudo",
5237 .match = pseudo_lld_bus_match,
5238 .probe = sdebug_driver_probe,
5239 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005240 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005241};