blob: 2181427a1ea5ed1487faa4020ea91f8c22c1a117 [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 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040015 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/types.h>
35#include <linux/string.h>
36#include <linux/genhd.h>
37#include <linux/fs.h>
38#include <linux/init.h>
39#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/vmalloc.h>
41#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020042#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050044#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040045#include <linux/spinlock.h>
46#include <linux/interrupt.h>
47#include <linux/atomic.h>
48#include <linux/hrtimer.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050049
50#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090051
Martin K. Petersen44d92692009-10-15 14:45:27 -040052#include <asm/unaligned.h>
53
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090054#include <scsi/scsi.h>
55#include <scsi/scsi_cmnd.h>
56#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <scsi/scsi_host.h>
58#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090059#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040060#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040061#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Martin K. Petersenc6a44282009-01-04 03:08:19 -050063#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Douglas Gilbert22017ed2014-11-24 23:04:47 -050066#define SCSI_DEBUG_VERSION "1.85"
67static const char *scsi_debug_version_date = "20141022";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040068
69#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050071/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040072#define NO_ADDITIONAL_SENSE 0x0
73#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050074#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040076#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050078#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070079#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040080#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040081#define UA_RESET_ASC 0x29
82#define UA_CHANGED_ASC 0x2a
Douglas Gilbert22017ed2014-11-24 23:04:47 -050083#define INSUFF_RES_ASC 0x55
84#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040085#define POWER_ON_RESET_ASCQ 0x0
86#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
87#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050088#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050090#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define THRESHOLD_EXCEEDED 0x5d
92#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050093#define MISCOMPARE_VERIFY_ASC 0x1d
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
99/* Default values for driver parameters */
100#define DEF_NUM_HOST 1
101#define DEF_NUM_TGTS 1
102#define DEF_MAX_LUNS 1
103/* With these defaults, this driver will make 1 host with 1 target
104 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
105 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500106#define DEF_ATO 1
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400107#define DEF_DELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500109#define DEF_DIF 0
110#define DEF_DIX 0
111#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500113#define DEF_FAKE_RW 0
114#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400115#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500116#define DEF_LBPU 0
117#define DEF_LBPWS 0
118#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600119#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500120#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400121#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500122#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define DEF_NUM_PARTS 0
124#define DEF_OPTS 0
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400125#define DEF_OPT_BLKS 64
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500126#define DEF_PHYSBLK_EXP 0
127#define DEF_PTYPE 0
Martin Pittd9867882012-09-06 12:04:33 +0200128#define DEF_REMOVABLE false
Douglas Gilberte46b0342014-08-05 12:21:53 +0200129#define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500130#define DEF_SECTOR_SIZE 512
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400131#define DEF_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500132#define DEF_UNMAP_ALIGNMENT 0
133#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400134#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
135#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500136#define DEF_VIRTUAL_GB 0
137#define DEF_VPD_USE_HOSTNO 1
138#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500139#define DEF_STRICT 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400140#define DELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142/* bit mask values for scsi_debug_opts */
143#define SCSI_DEBUG_OPT_NOISE 1
144#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
145#define SCSI_DEBUG_OPT_TIMEOUT 4
146#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500147#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500148#define SCSI_DEBUG_OPT_DIF_ERR 32
149#define SCSI_DEBUG_OPT_DIX_ERR 64
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -0500150#define SCSI_DEBUG_OPT_MAC_TIMEOUT 128
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400151#define SCSI_DEBUG_OPT_SHORT_TRANSFER 0x100
152#define SCSI_DEBUG_OPT_Q_NOISE 0x200
153#define SCSI_DEBUG_OPT_ALL_TSF 0x400
154#define SCSI_DEBUG_OPT_RARE_TSF 0x800
155#define SCSI_DEBUG_OPT_N_WCE 0x1000
156#define SCSI_DEBUG_OPT_RESET_NOISE 0x2000
157#define SCSI_DEBUG_OPT_NO_CDB_NOISE 0x4000
158#define SCSI_DEBUG_OPT_ALL_NOISE (0x1 | 0x200 | 0x2000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159/* When "every_nth" > 0 then modulo "every_nth" commands:
160 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
161 * - a RECOVERED_ERROR is simulated on successful read and write
162 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500163 * - a TRANSPORT_ERROR is simulated on successful read and write
164 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 *
166 * When "every_nth" < 0 then after "- every_nth" commands:
167 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
168 * - a RECOVERED_ERROR is simulated on successful read and write
169 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500170 * - a TRANSPORT_ERROR is simulated on successful read and write
171 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 * This will continue until some other action occurs (e.g. the user
173 * writing a new value (other than -1 or 1) to every_nth via sysfs).
174 */
175
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400176/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in
177 * priority order. In the subset implemented here lower numbers have higher
178 * priority. The UA numbers should be a sequence starting from 0 with
179 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
180#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
181#define SDEBUG_UA_BUS_RESET 1
182#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500183#define SDEBUG_UA_CAPACITY_CHANGED 3
184#define SDEBUG_NUM_UAS 4
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400185
186/* for check_readiness() */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500187#define UAS_ONLY 1 /* check for UAs only */
188#define UAS_TUR 0 /* if no UAs then check if media access possible */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
191 * sector on read commands: */
192#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500193#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
196 * or "peripheral device" addressing (value 0) */
197#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400198#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400200/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
201 * (for response) at one time. Can be reduced by max_queue option. Command
202 * responses are not queued when delay=0 and ndelay=0. The per-device
203 * DEF_CMD_PER_LUN can be changed via sysfs:
204 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
205 * SCSI_DEBUG_CANQUEUE. */
206#define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */
207#define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
208#define DEF_CMD_PER_LUN 255
209
210#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
211#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
212#endif
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400213
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500214/* SCSI opcodes (first byte of cdb) mapped onto these indexes */
215enum sdeb_opcode_index {
216 SDEB_I_INVALID_OPCODE = 0,
217 SDEB_I_INQUIRY = 1,
218 SDEB_I_REPORT_LUNS = 2,
219 SDEB_I_REQUEST_SENSE = 3,
220 SDEB_I_TEST_UNIT_READY = 4,
221 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
222 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
223 SDEB_I_LOG_SENSE = 7,
224 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
225 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
226 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
227 SDEB_I_START_STOP = 11,
228 SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
229 SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
230 SDEB_I_MAINT_IN = 14,
231 SDEB_I_MAINT_OUT = 15,
232 SDEB_I_VERIFY = 16, /* 10 only */
233 SDEB_I_VARIABLE_LEN = 17,
234 SDEB_I_RESERVE = 18, /* 6, 10 */
235 SDEB_I_RELEASE = 19, /* 6, 10 */
236 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
237 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
238 SDEB_I_ATA_PT = 22, /* 12, 16 */
239 SDEB_I_SEND_DIAG = 23,
240 SDEB_I_UNMAP = 24,
241 SDEB_I_XDWRITEREAD = 25, /* 10 only */
242 SDEB_I_WRITE_BUFFER = 26,
243 SDEB_I_WRITE_SAME = 27, /* 10, 16 */
244 SDEB_I_SYNC_CACHE = 28, /* 10 only */
245 SDEB_I_COMP_WRITE = 29,
246 SDEB_I_LAST_ELEMENT = 30, /* keep this last */
247};
248
249static const unsigned char opcode_ind_arr[256] = {
250/* 0x0; 0x0->0x1f: 6 byte cdbs */
251 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
252 0, 0, 0, 0,
253 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
254 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
255 SDEB_I_RELEASE,
256 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
257 SDEB_I_ALLOW_REMOVAL, 0,
258/* 0x20; 0x20->0x3f: 10 byte cdbs */
259 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
260 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
261 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
262 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
263/* 0x40; 0x40->0x5f: 10 byte cdbs */
264 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
265 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
266 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
267 SDEB_I_RELEASE,
268 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
269/* 0x60; 0x60->0x7d are reserved */
270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
272 0, SDEB_I_VARIABLE_LEN,
273/* 0x80; 0x80->0x9f: 16 byte cdbs */
274 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
275 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
276 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
277 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
278/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
279 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
280 SDEB_I_MAINT_OUT, 0, 0, 0,
281 SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
282 0, 0, 0, 0,
283 0, 0, 0, 0, 0, 0, 0, 0,
284 0, 0, 0, 0, 0, 0, 0, 0,
285/* 0xc0; 0xc0->0xff: vendor specific */
286 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
287 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
288 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
290};
291
292#define F_D_IN 1
293#define F_D_OUT 2
294#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
295#define F_D_UNKN 8
296#define F_RL_WLUN_OK 0x10
297#define F_SKIP_UA 0x20
298#define F_DELAY_OVERR 0x40
299#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
300#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
301#define F_INV_OP 0x200
302#define F_FAKE_RW 0x400
303#define F_M_ACCESS 0x800 /* media access */
304
305#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
306#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
307#define FF_SA (F_SA_HIGH | F_SA_LOW)
308
309struct sdebug_dev_info;
310static int scsi_debug_queuecommand(struct scsi_cmnd *scp);
311static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
312static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
313static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
314static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
315static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
316static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
317static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
318static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
319static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
320static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
321static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
322static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
323static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
324static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
325static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
326static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
327static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
328
329struct opcode_info_t {
330 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff
331 * for terminating element */
332 u8 opcode; /* if num_attached > 0, preferred */
333 u16 sa; /* service action */
334 u32 flags; /* OR-ed set of SDEB_F_* */
335 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
336 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
337 u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
338 /* ignore cdb bytes after position 15 */
339};
340
341static const struct opcode_info_t msense_iarr[1] = {
342 {0, 0x1a, 0, F_D_IN, NULL, NULL,
343 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
344};
345
346static const struct opcode_info_t mselect_iarr[1] = {
347 {0, 0x15, 0, F_D_OUT, NULL, NULL,
348 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
349};
350
351static const struct opcode_info_t read_iarr[3] = {
352 {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
353 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
354 0, 0, 0, 0} },
355 {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
356 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
357 {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
358 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
359 0xc7, 0, 0, 0, 0} },
360};
361
362static const struct opcode_info_t write_iarr[3] = {
363 {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
364 {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
365 0, 0, 0, 0} },
366 {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
367 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
368 {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
369 {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
370 0xc7, 0, 0, 0, 0} },
371};
372
373static const struct opcode_info_t sa_in_iarr[1] = {
374 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
375 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
376 0xff, 0xff, 0xff, 0, 0xc7} },
377};
378
379static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
380 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
381 NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
382 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
383};
384
385static const struct opcode_info_t maint_in_iarr[2] = {
386 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, NULL, NULL,
387 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
388 0xc7, 0, 0, 0, 0} },
389 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, NULL, NULL,
390 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
391 0, 0} },
392};
393
394static const struct opcode_info_t write_same_iarr[1] = {
395 {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
396 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
397 0xff, 0xff, 0xff, 0x1f, 0xc7} },
398};
399
400static const struct opcode_info_t reserve_iarr[1] = {
401 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
402 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
403};
404
405static const struct opcode_info_t release_iarr[1] = {
406 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
407 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
408};
409
410
411/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
412 * plus the terminating elements for logic that scans this table such as
413 * REPORT SUPPORTED OPERATION CODES. */
414static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
415/* 0 */
416 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
417 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
418 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
419 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
420 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
421 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
422 0, 0} },
423 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
424 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
425 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
426 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
427 {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
428 {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
429 0} },
430 {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
431 {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
432 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
433 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
434 0, 0, 0} },
435 {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
436 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
437 0, 0} },
438 {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
439 {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
440 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */
441/* 10 */
442 {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
443 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
444 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */
445 {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
446 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
447 {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
448 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
449 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
450 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
451 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
452 {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
453 {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
454 0} },
455 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
456 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
457 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */
458 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
459 {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
460 vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
461 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
462 {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
463 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
464 0} },
465 {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
466 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
467 0} },
468/* 20 */
469 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */
470 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
471 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
472 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
473 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
474 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
475 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
476 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
477 {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
478 {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
479 {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
480 NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
481 0, 0, 0, 0, 0, 0} },
482 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* WRITE_BUFFER */
483 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
484 {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
485 write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
486 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
487 {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
488 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
489 0, 0, 0, 0} },
490 {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, NULL, NULL,
491 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
492 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
493
494/* 30 */
495 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
496 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
497};
498
Douglas Gilbert817fd662014-11-24 20:18:02 -0500499struct sdebug_scmd_extra_t {
500 bool inj_recovered;
501 bool inj_transport;
502 bool inj_dif;
503 bool inj_dix;
504 bool inj_short;
505};
506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507static int scsi_debug_add_host = DEF_NUM_HOST;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500508static int scsi_debug_ato = DEF_ATO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509static int scsi_debug_delay = DEF_DELAY;
510static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500511static int scsi_debug_dif = DEF_DIF;
512static int scsi_debug_dix = DEF_DIX;
513static int scsi_debug_dsense = DEF_D_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514static int scsi_debug_every_nth = DEF_EVERY_NTH;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500515static int scsi_debug_fake_rw = DEF_FAKE_RW;
Akinobu Mita68aee7b2013-09-18 21:27:27 +0900516static unsigned int scsi_debug_guard = DEF_GUARD;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500517static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518static int scsi_debug_max_luns = DEF_MAX_LUNS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400519static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400520static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
521static int scsi_debug_ndelay = DEF_NDELAY;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400522static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500523static int scsi_debug_no_uld = 0;
524static int scsi_debug_num_parts = DEF_NUM_PARTS;
525static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400526static int scsi_debug_opt_blks = DEF_OPT_BLKS;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500527static int scsi_debug_opts = DEF_OPTS;
528static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
529static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
530static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
531static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
532static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
533static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
534static unsigned int scsi_debug_lbpu = DEF_LBPU;
535static unsigned int scsi_debug_lbpws = DEF_LBPWS;
536static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600537static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
Martin K. Petersen60147592010-08-19 11:49:00 -0400538static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500539static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
540static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
541static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
542static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
Martin Pittd9867882012-09-06 12:04:33 +0200543static bool scsi_debug_removable = DEF_REMOVABLE;
Akinobu Mita0759c662014-02-26 22:57:04 +0900544static bool scsi_debug_clustering;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400545static bool scsi_debug_host_lock = DEF_HOST_LOCK;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500546static bool scsi_debug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500547static bool sdebug_any_injecting_opt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400549static atomic_t sdebug_cmnd_count;
550static atomic_t sdebug_completions;
551static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553#define DEV_READONLY(TGT) (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400555static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556static sector_t sdebug_capacity; /* in sectors */
557
558/* old BIOS stuff, kernel may get rid of them but some mode sense pages
559 may still need them */
560static int sdebug_heads; /* heads per disk */
561static int sdebug_cylinders_per; /* cylinders per surface */
562static int sdebug_sectors_per; /* sectors per cylinder */
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564#define SDEBUG_MAX_PARTS 4
565
Martin K. Petersen395cef02009-09-18 17:33:03 -0400566#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900567
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500568static unsigned int scsi_debug_lbp(void)
569{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400570 return ((0 == scsi_debug_fake_rw) &&
571 (scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10));
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500572}
573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574struct sdebug_dev_info {
575 struct list_head dev_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 unsigned int channel;
577 unsigned int target;
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200578 u64 lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400580 unsigned long uas_bm[1];
581 atomic_t num_in_q;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500582 char stopped; /* TODO: should be atomic */
583 bool used;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584};
585
586struct sdebug_host_info {
587 struct list_head host_list;
588 struct Scsi_Host *shost;
589 struct device dev;
590 struct list_head dev_info_list;
591};
592
593#define to_sdebug_host(d) \
594 container_of(d, struct sdebug_host_info, dev)
595
596static LIST_HEAD(sdebug_host_list);
597static DEFINE_SPINLOCK(sdebug_host_list_lock);
598
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400599
600struct sdebug_hrtimer { /* ... is derived from hrtimer */
601 struct hrtimer hrt; /* must be first element */
602 int qa_indx;
603};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605struct sdebug_queued_cmd {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400606 /* in_use flagged by a bit in queued_in_use_bm[] */
607 struct timer_list *cmnd_timerp;
608 struct tasklet_struct *tletp;
609 struct sdebug_hrtimer *sd_hrtp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 struct scsi_cmnd * a_cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611};
612static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400613static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616static unsigned char * fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900617static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400618static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Martin K. Petersen44d92692009-10-15 14:45:27 -0400620static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400621static int num_aborts;
622static int num_dev_resets;
623static int num_target_resets;
624static int num_bus_resets;
625static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500626static int dix_writes;
627static int dix_reads;
628static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630static DEFINE_SPINLOCK(queued_arr_lock);
631static DEFINE_RWLOCK(atomic_rw);
632
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400633static char sdebug_proc_name[] = MY_NAME;
634static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636static struct bus_type pseudo_lld_bus;
637
638static struct device_driver sdebug_driverfs_driver = {
639 .name = sdebug_proc_name,
640 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641};
642
643static const int check_condition_result =
644 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
645
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500646static const int illegal_condition_result =
647 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
648
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400649static const int device_qfull_result =
650 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
651
652static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
653 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
654 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400655static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
656 0, 0, 0x2, 0x4b};
657static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
658 0, 0, 0x0, 0x0};
659
Akinobu Mita14faa942013-09-18 21:27:24 +0900660static void *fake_store(unsigned long long lba)
661{
662 lba = do_div(lba, sdebug_store_sectors);
663
664 return fake_storep + lba * scsi_debug_sector_size;
665}
666
667static struct sd_dif_tuple *dif_store(sector_t sector)
668{
669 sector = do_div(sector, sdebug_store_sectors);
670
671 return dif_storep + sector;
672}
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674static int sdebug_add_adapter(void);
675static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900677static void sdebug_max_tgts_luns(void)
678{
679 struct sdebug_host_info *sdbg_host;
680 struct Scsi_Host *hpnt;
681
682 spin_lock(&sdebug_host_list_lock);
683 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
684 hpnt = sdbg_host->shost;
685 if ((hpnt->this_id >= 0) &&
686 (scsi_debug_num_tgts > hpnt->this_id))
687 hpnt->max_id = scsi_debug_num_tgts + 1;
688 else
689 hpnt->max_id = scsi_debug_num_tgts;
690 /* scsi_debug_max_luns; */
691 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
692 }
693 spin_unlock(&sdebug_host_list_lock);
694}
695
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500696enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
697
698/* Set in_bit to -1 to indicate no bit position of invalid field */
699static void
700mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
701 int in_byte, int in_bit)
702{
703 unsigned char *sbuff;
704 u8 sks[4];
705 int sl, asc;
706
707 sbuff = scp->sense_buffer;
708 if (!sbuff) {
709 sdev_printk(KERN_ERR, scp->device,
710 "%s: sense_buffer is NULL\n", __func__);
711 return;
712 }
713 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
714 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
715 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, ILLEGAL_REQUEST,
716 asc, 0);
717 memset(sks, 0, sizeof(sks));
718 sks[0] = 0x80;
719 if (c_d)
720 sks[0] |= 0x40;
721 if (in_bit >= 0) {
722 sks[0] |= 0x8;
723 sks[0] |= 0x7 & in_bit;
724 }
725 put_unaligned_be16(in_byte, sks + 1);
726 if (scsi_debug_dsense) {
727 sl = sbuff[7] + 8;
728 sbuff[7] = sl;
729 sbuff[sl] = 0x2;
730 sbuff[sl + 1] = 0x6;
731 memcpy(sbuff + sl + 4, sks, 3);
732 } else
733 memcpy(sbuff + 15, sks, 3);
734 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
735 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
736 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
737 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
738}
739
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400740static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900741{
742 unsigned char *sbuff;
743
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400744 sbuff = scp->sense_buffer;
745 if (!sbuff) {
746 sdev_printk(KERN_ERR, scp->device,
747 "%s: sense_buffer is NULL\n", __func__);
748 return;
749 }
750 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900751
752 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
753
754 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400755 sdev_printk(KERN_INFO, scp->device,
756 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
757 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900758}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500760static void
761mk_sense_invalid_opcode(struct scsi_cmnd *scp)
762{
763 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
764}
765
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
767{
768 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400769 if (0x1261 == cmd)
770 sdev_printk(KERN_INFO, dev,
771 "%s: BLKFLSBUF [0x1261]\n", __func__);
772 else if (0x5331 == cmd)
773 sdev_printk(KERN_INFO, dev,
774 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
775 __func__);
776 else
777 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
778 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 }
780 return -EINVAL;
781 /* return -ENOTTY; // correct return but upsets fdisk */
782}
783
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400784static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400785 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400787 int k;
788 bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
789
790 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
791 if (k != SDEBUG_NUM_UAS) {
792 const char *cp = NULL;
793
794 switch (k) {
795 case SDEBUG_UA_POR:
796 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
797 UA_RESET_ASC, POWER_ON_RESET_ASCQ);
798 if (debug)
799 cp = "power on reset";
800 break;
801 case SDEBUG_UA_BUS_RESET:
802 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
803 UA_RESET_ASC, BUS_RESET_ASCQ);
804 if (debug)
805 cp = "bus reset";
806 break;
807 case SDEBUG_UA_MODE_CHANGED:
808 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
809 UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
810 if (debug)
811 cp = "mode parameters changed";
812 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500813 case SDEBUG_UA_CAPACITY_CHANGED:
814 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
815 UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
816 if (debug)
817 cp = "capacity data changed";
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400818 default:
819 pr_warn("%s: unexpected unit attention code=%d\n",
820 __func__, k);
821 if (debug)
822 cp = "unknown";
823 break;
824 }
825 clear_bit(k, devip->uas_bm);
826 if (debug)
827 sdev_printk(KERN_INFO, SCpnt->device,
828 "%s reports: Unit attention: %s\n",
829 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 return check_condition_result;
831 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400832 if ((UAS_TUR == uas_only) && devip->stopped) {
833 mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400834 0x2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400835 if (debug)
836 sdev_printk(KERN_INFO, SCpnt->device,
837 "%s reports: Not ready: %s\n", my_name,
838 "initializing command required");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400839 return check_condition_result;
840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 return 0;
842}
843
844/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900845static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 int arr_len)
847{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900848 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900849 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900851 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900853 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900855
856 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
857 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700858 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900859
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 return 0;
861}
862
863/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900864static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
865 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900867 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900869 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900871
872 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873}
874
875
876static const char * inq_vendor_id = "Linux ";
877static const char * inq_product_id = "scsi_debug ";
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400878static const char *inq_product_rev = "0184"; /* version less '.' */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400880/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200881static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
882 int target_dev_id, int dev_id_num,
883 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400884 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400886 int num, port_a;
887 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400889 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 /* T10 vendor identifier field format (faked) */
891 arr[0] = 0x2; /* ASCII */
892 arr[1] = 0x1;
893 arr[2] = 0x0;
894 memcpy(&arr[4], inq_vendor_id, 8);
895 memcpy(&arr[12], inq_product_id, 16);
896 memcpy(&arr[28], dev_id_str, dev_id_str_len);
897 num = 8 + 16 + dev_id_str_len;
898 arr[3] = num;
899 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400900 if (dev_id_num >= 0) {
901 /* NAA-5, Logical unit identifier (binary) */
902 arr[num++] = 0x1; /* binary (not necessarily sas) */
903 arr[num++] = 0x3; /* PIV=0, lu, naa */
904 arr[num++] = 0x0;
905 arr[num++] = 0x8;
906 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
907 arr[num++] = 0x33;
908 arr[num++] = 0x33;
909 arr[num++] = 0x30;
910 arr[num++] = (dev_id_num >> 24);
911 arr[num++] = (dev_id_num >> 16) & 0xff;
912 arr[num++] = (dev_id_num >> 8) & 0xff;
913 arr[num++] = dev_id_num & 0xff;
914 /* Target relative port number */
915 arr[num++] = 0x61; /* proto=sas, binary */
916 arr[num++] = 0x94; /* PIV=1, target port, rel port */
917 arr[num++] = 0x0; /* reserved */
918 arr[num++] = 0x4; /* length */
919 arr[num++] = 0x0; /* reserved */
920 arr[num++] = 0x0; /* reserved */
921 arr[num++] = 0x0;
922 arr[num++] = 0x1; /* relative port A */
923 }
924 /* NAA-5, Target port identifier */
925 arr[num++] = 0x61; /* proto=sas, binary */
926 arr[num++] = 0x93; /* piv=1, target port, naa */
927 arr[num++] = 0x0;
928 arr[num++] = 0x8;
929 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
930 arr[num++] = 0x22;
931 arr[num++] = 0x22;
932 arr[num++] = 0x20;
933 arr[num++] = (port_a >> 24);
934 arr[num++] = (port_a >> 16) & 0xff;
935 arr[num++] = (port_a >> 8) & 0xff;
936 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200937 /* NAA-5, Target port group identifier */
938 arr[num++] = 0x61; /* proto=sas, binary */
939 arr[num++] = 0x95; /* piv=1, target port group id */
940 arr[num++] = 0x0;
941 arr[num++] = 0x4;
942 arr[num++] = 0;
943 arr[num++] = 0;
944 arr[num++] = (port_group_id >> 8) & 0xff;
945 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400946 /* NAA-5, Target device identifier */
947 arr[num++] = 0x61; /* proto=sas, binary */
948 arr[num++] = 0xa3; /* piv=1, target device, naa */
949 arr[num++] = 0x0;
950 arr[num++] = 0x8;
951 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
952 arr[num++] = 0x22;
953 arr[num++] = 0x22;
954 arr[num++] = 0x20;
955 arr[num++] = (target_dev_id >> 24);
956 arr[num++] = (target_dev_id >> 16) & 0xff;
957 arr[num++] = (target_dev_id >> 8) & 0xff;
958 arr[num++] = target_dev_id & 0xff;
959 /* SCSI name string: Target device identifier */
960 arr[num++] = 0x63; /* proto=sas, UTF-8 */
961 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
962 arr[num++] = 0x0;
963 arr[num++] = 24;
964 memcpy(arr + num, "naa.52222220", 12);
965 num += 12;
966 snprintf(b, sizeof(b), "%08X", target_dev_id);
967 memcpy(arr + num, b, 8);
968 num += 8;
969 memset(arr + num, 0, 4);
970 num += 4;
971 return num;
972}
973
974
975static unsigned char vpd84_data[] = {
976/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
977 0x22,0x22,0x22,0x0,0xbb,0x1,
978 0x22,0x22,0x22,0x0,0xbb,0x2,
979};
980
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400981/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400982static int inquiry_evpd_84(unsigned char * arr)
983{
984 memcpy(arr, vpd84_data, sizeof(vpd84_data));
985 return sizeof(vpd84_data);
986}
987
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400988/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400989static int inquiry_evpd_85(unsigned char * arr)
990{
991 int num = 0;
992 const char * na1 = "https://www.kernel.org/config";
993 const char * na2 = "http://www.kernel.org/log";
994 int plen, olen;
995
996 arr[num++] = 0x1; /* lu, storage config */
997 arr[num++] = 0x0; /* reserved */
998 arr[num++] = 0x0;
999 olen = strlen(na1);
1000 plen = olen + 1;
1001 if (plen % 4)
1002 plen = ((plen / 4) + 1) * 4;
1003 arr[num++] = plen; /* length, null termianted, padded */
1004 memcpy(arr + num, na1, olen);
1005 memset(arr + num + olen, 0, plen - olen);
1006 num += plen;
1007
1008 arr[num++] = 0x4; /* lu, logging */
1009 arr[num++] = 0x0; /* reserved */
1010 arr[num++] = 0x0;
1011 olen = strlen(na2);
1012 plen = olen + 1;
1013 if (plen % 4)
1014 plen = ((plen / 4) + 1) * 4;
1015 arr[num++] = plen; /* length, null terminated, padded */
1016 memcpy(arr + num, na2, olen);
1017 memset(arr + num + olen, 0, plen - olen);
1018 num += plen;
1019
1020 return num;
1021}
1022
1023/* SCSI ports VPD page */
1024static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
1025{
1026 int num = 0;
1027 int port_a, port_b;
1028
1029 port_a = target_dev_id + 1;
1030 port_b = port_a + 1;
1031 arr[num++] = 0x0; /* reserved */
1032 arr[num++] = 0x0; /* reserved */
1033 arr[num++] = 0x0;
1034 arr[num++] = 0x1; /* relative port 1 (primary) */
1035 memset(arr + num, 0, 6);
1036 num += 6;
1037 arr[num++] = 0x0;
1038 arr[num++] = 12; /* length tp descriptor */
1039 /* naa-5 target port identifier (A) */
1040 arr[num++] = 0x61; /* proto=sas, binary */
1041 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1042 arr[num++] = 0x0; /* reserved */
1043 arr[num++] = 0x8; /* length */
1044 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
1045 arr[num++] = 0x22;
1046 arr[num++] = 0x22;
1047 arr[num++] = 0x20;
1048 arr[num++] = (port_a >> 24);
1049 arr[num++] = (port_a >> 16) & 0xff;
1050 arr[num++] = (port_a >> 8) & 0xff;
1051 arr[num++] = port_a & 0xff;
1052
1053 arr[num++] = 0x0; /* reserved */
1054 arr[num++] = 0x0; /* reserved */
1055 arr[num++] = 0x0;
1056 arr[num++] = 0x2; /* relative port 2 (secondary) */
1057 memset(arr + num, 0, 6);
1058 num += 6;
1059 arr[num++] = 0x0;
1060 arr[num++] = 12; /* length tp descriptor */
1061 /* naa-5 target port identifier (B) */
1062 arr[num++] = 0x61; /* proto=sas, binary */
1063 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1064 arr[num++] = 0x0; /* reserved */
1065 arr[num++] = 0x8; /* length */
1066 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
1067 arr[num++] = 0x22;
1068 arr[num++] = 0x22;
1069 arr[num++] = 0x20;
1070 arr[num++] = (port_b >> 24);
1071 arr[num++] = (port_b >> 16) & 0xff;
1072 arr[num++] = (port_b >> 8) & 0xff;
1073 arr[num++] = port_b & 0xff;
1074
1075 return num;
1076}
1077
1078
1079static unsigned char vpd89_data[] = {
1080/* from 4th byte */ 0,0,0,0,
1081'l','i','n','u','x',' ',' ',' ',
1082'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1083'1','2','3','4',
10840x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
10850xec,0,0,0,
10860x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
10870,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
10880x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
10890x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
10900x53,0x41,
10910x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
10920x20,0x20,
10930x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
10940x10,0x80,
10950,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
10960x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
10970x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
10980,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
10990x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
11000x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
11010,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
11020,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11030,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11050x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
11060,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
11070xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
11080,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
11090,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
11200,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1121};
1122
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001123/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001124static int inquiry_evpd_89(unsigned char * arr)
1125{
1126 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1127 return sizeof(vpd89_data);
1128}
1129
1130
1131static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001132 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1133 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1134 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1135 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001136};
1137
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001138/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001139static int inquiry_evpd_b0(unsigned char * arr)
1140{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001141 unsigned int gran;
1142
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001143 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001144
1145 /* Optimal transfer length granularity */
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001146 gran = 1 << scsi_debug_physblk_exp;
1147 arr[2] = (gran >> 8) & 0xff;
1148 arr[3] = gran & 0xff;
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001149
1150 /* Maximum Transfer Length */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001151 if (sdebug_store_sectors > 0x400) {
1152 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
1153 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
1154 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
1155 arr[7] = sdebug_store_sectors & 0xff;
1156 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001157
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001158 /* Optimal Transfer Length */
1159 put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
1160
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001161 if (scsi_debug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001162 /* Maximum Unmap LBA Count */
Martin K. Petersen60147592010-08-19 11:49:00 -04001163 put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001164
1165 /* Maximum Unmap Block Descriptor Count */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001166 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
1167 }
1168
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001169 /* Unmap Granularity Alignment */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001170 if (scsi_debug_unmap_alignment) {
1171 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
1172 arr[28] |= 0x80; /* UGAVALID */
1173 }
1174
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001175 /* Optimal Unmap Granularity */
Martin K. Petersen60147592010-08-19 11:49:00 -04001176 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
1177
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001178 /* Maximum WRITE SAME Length */
1179 put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
1180
1181 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001182
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001183 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184}
1185
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001186/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001187static int inquiry_evpd_b1(unsigned char *arr)
1188{
1189 memset(arr, 0, 0x3c);
1190 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001191 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1192 arr[2] = 0;
1193 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001194
1195 return 0x3c;
1196}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001198/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001199static int inquiry_evpd_b2(unsigned char *arr)
1200{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001201 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001202 arr[0] = 0; /* threshold exponent */
1203
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001204 if (scsi_debug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001205 arr[1] = 1 << 7;
1206
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001207 if (scsi_debug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001208 arr[1] |= 1 << 6;
1209
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001210 if (scsi_debug_lbpws10)
1211 arr[1] |= 1 << 5;
1212
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001213 if (scsi_debug_lbprz)
1214 arr[1] |= 1 << 2;
1215
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001216 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001217}
1218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001220#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001222static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
1224 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001225 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001226 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001227 int alloc_len, n, ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001228 bool have_wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001231 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1232 if (! arr)
1233 return DID_REQUEUE << 16;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001234 have_wlun = (scp->device->lun == SAM2_WLUN_REPORT_LUNS);
1235 if (have_wlun)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001236 pq_pdt = 0x1e; /* present, wlun */
1237 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
1238 pq_pdt = 0x7f; /* not present, no device type */
1239 else
1240 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 arr[0] = pq_pdt;
1242 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001243 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001244 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 return check_condition_result;
1246 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001247 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001248 char lu_id_str[6];
1249 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001251 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1252 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -04001253 if (0 == scsi_debug_vpd_use_hostno)
1254 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001255 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001256 (devip->target * 1000) + devip->lun);
1257 target_dev_id = ((host_no + 1) * 2000) +
1258 (devip->target * 1000) - 3;
1259 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001261 arr[1] = cmd[2]; /*sanity */
1262 n = 4;
1263 arr[n++] = 0x0; /* this page */
1264 arr[n++] = 0x80; /* unit serial number */
1265 arr[n++] = 0x83; /* device identification */
1266 arr[n++] = 0x84; /* software interface ident. */
1267 arr[n++] = 0x85; /* management network addresses */
1268 arr[n++] = 0x86; /* extended inquiry */
1269 arr[n++] = 0x87; /* mode page policy */
1270 arr[n++] = 0x88; /* SCSI ports */
1271 arr[n++] = 0x89; /* ATA information */
1272 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001273 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001274 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
1275 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001276 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001278 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001280 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001282 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001283 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1284 target_dev_id, lu_id_num,
1285 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001286 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1287 arr[1] = cmd[2]; /*sanity */
1288 arr[3] = inquiry_evpd_84(&arr[4]);
1289 } else if (0x85 == cmd[2]) { /* Management network addresses */
1290 arr[1] = cmd[2]; /*sanity */
1291 arr[3] = inquiry_evpd_85(&arr[4]);
1292 } else if (0x86 == cmd[2]) { /* extended inquiry */
1293 arr[1] = cmd[2]; /*sanity */
1294 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001295 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
1296 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
1297 else if (scsi_debug_dif)
1298 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1299 else
1300 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001301 arr[5] = 0x7; /* head of q, ordered + simple q's */
1302 } else if (0x87 == cmd[2]) { /* mode page policy */
1303 arr[1] = cmd[2]; /*sanity */
1304 arr[3] = 0x8; /* number of following entries */
1305 arr[4] = 0x2; /* disconnect-reconnect mp */
1306 arr[6] = 0x80; /* mlus, shared */
1307 arr[8] = 0x18; /* protocol specific lu */
1308 arr[10] = 0x82; /* mlus, per initiator port */
1309 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1310 arr[1] = cmd[2]; /*sanity */
1311 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1312 } else if (0x89 == cmd[2]) { /* ATA information */
1313 arr[1] = cmd[2]; /*sanity */
1314 n = inquiry_evpd_89(&arr[4]);
1315 arr[2] = (n >> 8);
1316 arr[3] = (n & 0xff);
1317 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1318 arr[1] = cmd[2]; /*sanity */
1319 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001320 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1321 arr[1] = cmd[2]; /*sanity */
1322 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001323 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001324 arr[1] = cmd[2]; /*sanity */
1325 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001327 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001328 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 return check_condition_result;
1330 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001331 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001332 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001333 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001334 kfree(arr);
1335 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 }
1337 /* drops through here for a standard inquiry */
Martin Pittd9867882012-09-06 12:04:33 +02001338 arr[1] = scsi_debug_removable ? 0x80 : 0; /* Removable disk */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 arr[2] = scsi_debug_scsi_level;
1340 arr[3] = 2; /* response_data_format==2 */
1341 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001342 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001343 if (0 == scsi_debug_vpd_use_hostno)
1344 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001345 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001347 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 memcpy(&arr[8], inq_vendor_id, 8);
1349 memcpy(&arr[16], inq_product_id, 16);
1350 memcpy(&arr[32], inq_product_rev, 4);
1351 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001352 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1353 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001354 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 if (scsi_debug_ptype == 0) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001356 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 } else if (scsi_debug_ptype == 1) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001358 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001360 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001361 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001363 kfree(arr);
1364 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365}
1366
1367static int resp_requests(struct scsi_cmnd * scp,
1368 struct sdebug_dev_info * devip)
1369{
1370 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001371 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001372 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001373 bool dsense, want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 int len = 18;
1375
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001376 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001377 dsense = !!(cmd[1] & 1);
1378 want_dsense = dsense || scsi_debug_dsense;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001379 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001380 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001381 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001382 arr[0] = 0x72;
1383 arr[1] = 0x0; /* NO_SENSE in sense_key */
1384 arr[2] = THRESHOLD_EXCEEDED;
1385 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001386 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001387 } else {
1388 arr[0] = 0x70;
1389 arr[2] = 0x0; /* NO_SENSE in sense_key */
1390 arr[7] = 0xa; /* 18 byte sense buffer */
1391 arr[12] = THRESHOLD_EXCEEDED;
1392 arr[13] = 0xff; /* TEST set and MRIE==6 */
1393 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001394 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001395 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001396 if (arr[0] >= 0x70 && dsense == scsi_debug_dsense)
1397 ; /* have sense and formats match */
1398 else if (arr[0] <= 0x70) {
1399 if (dsense) {
1400 memset(arr, 0, 8);
1401 arr[0] = 0x72;
1402 len = 8;
1403 } else {
1404 memset(arr, 0, 18);
1405 arr[0] = 0x70;
1406 arr[7] = 0xa;
1407 }
1408 } else if (dsense) {
1409 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001410 arr[0] = 0x72;
1411 arr[1] = sbuff[2]; /* sense key */
1412 arr[2] = sbuff[12]; /* asc */
1413 arr[3] = sbuff[13]; /* ascq */
1414 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001415 } else {
1416 memset(arr, 0, 18);
1417 arr[0] = 0x70;
1418 arr[2] = sbuff[1];
1419 arr[7] = 0xa;
1420 arr[12] = sbuff[1];
1421 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001422 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001423
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001424 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001425 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 return fill_from_dev_buffer(scp, arr, len);
1427}
1428
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001429static int resp_start_stop(struct scsi_cmnd * scp,
1430 struct sdebug_dev_info * devip)
1431{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001432 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001433 int power_cond, start;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001434
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001435 power_cond = (cmd[4] & 0xf0) >> 4;
1436 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001437 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001438 return check_condition_result;
1439 }
1440 start = cmd[4] & 1;
1441 if (start == devip->stopped)
1442 devip->stopped = !start;
1443 return 0;
1444}
1445
FUJITA Tomonori28898872008-03-30 00:59:55 +09001446static sector_t get_sdebug_capacity(void)
1447{
1448 if (scsi_debug_virtual_gb > 0)
Douglas Gilbert5447ed62010-04-25 12:30:23 +02001449 return (sector_t)scsi_debug_virtual_gb *
1450 (1073741824 / scsi_debug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001451 else
1452 return sdebug_store_sectors;
1453}
1454
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455#define SDEBUG_READCAP_ARR_SZ 8
1456static int resp_readcap(struct scsi_cmnd * scp,
1457 struct sdebug_dev_info * devip)
1458{
1459 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001460 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001463 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001465 if (sdebug_capacity < 0xffffffff) {
1466 capac = (unsigned int)sdebug_capacity - 1;
1467 arr[0] = (capac >> 24);
1468 arr[1] = (capac >> 16) & 0xff;
1469 arr[2] = (capac >> 8) & 0xff;
1470 arr[3] = capac & 0xff;
1471 } else {
1472 arr[0] = 0xff;
1473 arr[1] = 0xff;
1474 arr[2] = 0xff;
1475 arr[3] = 0xff;
1476 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001477 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1478 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1480}
1481
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001482#define SDEBUG_READCAP16_ARR_SZ 32
1483static int resp_readcap16(struct scsi_cmnd * scp,
1484 struct sdebug_dev_info * devip)
1485{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001486 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001487 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1488 unsigned long long capac;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001489 int k, alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001490
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001491 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1492 + cmd[13]);
1493 /* 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);
1496 capac = sdebug_capacity - 1;
1497 for (k = 0; k < 8; ++k, capac >>= 8)
1498 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001499 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1500 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1501 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1502 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001503 arr[13] = scsi_debug_physblk_exp & 0xf;
1504 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001505
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001506 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001507 arr[14] |= 0x80; /* LBPME */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001508 if (scsi_debug_lbprz)
1509 arr[14] |= 0x40; /* LBPRZ */
1510 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001511
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001512 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001513
1514 if (scsi_debug_dif) {
1515 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1516 arr[12] |= 1; /* PROT_EN */
1517 }
1518
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001519 return fill_from_dev_buffer(scp, arr,
1520 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1521}
1522
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001523#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1524
1525static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1526 struct sdebug_dev_info * devip)
1527{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001528 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001529 unsigned char * arr;
1530 int host_no = devip->sdbg_host->shost->host_no;
1531 int n, ret, alen, rlen;
1532 int port_group_a, port_group_b, port_a, port_b;
1533
1534 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1535 + cmd[9]);
1536
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001537 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1538 if (! arr)
1539 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001540 /*
1541 * EVPD page 0x88 states we have two ports, one
1542 * real and a fake port with no device connected.
1543 * So we create two port groups with one port each
1544 * and set the group with port B to unavailable.
1545 */
1546 port_a = 0x1; /* relative port A */
1547 port_b = 0x2; /* relative port B */
1548 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1549 (devip->channel & 0x7f);
1550 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1551 (devip->channel & 0x7f) + 0x80;
1552
1553 /*
1554 * The asymmetric access state is cycled according to the host_id.
1555 */
1556 n = 4;
1557 if (0 == scsi_debug_vpd_use_hostno) {
1558 arr[n++] = host_no % 3; /* Asymm access state */
1559 arr[n++] = 0x0F; /* claim: all states are supported */
1560 } else {
1561 arr[n++] = 0x0; /* Active/Optimized path */
1562 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1563 }
1564 arr[n++] = (port_group_a >> 8) & 0xff;
1565 arr[n++] = port_group_a & 0xff;
1566 arr[n++] = 0; /* Reserved */
1567 arr[n++] = 0; /* Status code */
1568 arr[n++] = 0; /* Vendor unique */
1569 arr[n++] = 0x1; /* One port per group */
1570 arr[n++] = 0; /* Reserved */
1571 arr[n++] = 0; /* Reserved */
1572 arr[n++] = (port_a >> 8) & 0xff;
1573 arr[n++] = port_a & 0xff;
1574 arr[n++] = 3; /* Port unavailable */
1575 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1576 arr[n++] = (port_group_b >> 8) & 0xff;
1577 arr[n++] = port_group_b & 0xff;
1578 arr[n++] = 0; /* Reserved */
1579 arr[n++] = 0; /* Status code */
1580 arr[n++] = 0; /* Vendor unique */
1581 arr[n++] = 0x1; /* One port per group */
1582 arr[n++] = 0; /* Reserved */
1583 arr[n++] = 0; /* Reserved */
1584 arr[n++] = (port_b >> 8) & 0xff;
1585 arr[n++] = port_b & 0xff;
1586
1587 rlen = n - 4;
1588 arr[0] = (rlen >> 24) & 0xff;
1589 arr[1] = (rlen >> 16) & 0xff;
1590 arr[2] = (rlen >> 8) & 0xff;
1591 arr[3] = rlen & 0xff;
1592
1593 /*
1594 * Return the smallest value of either
1595 * - The allocated length
1596 * - The constructed command length
1597 * - The maximum array size
1598 */
1599 rlen = min(alen,n);
1600 ret = fill_from_dev_buffer(scp, arr,
1601 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1602 kfree(arr);
1603 return ret;
1604}
1605
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606/* <<Following mode page info copied from ST318451LW>> */
1607
1608static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1609{ /* Read-Write Error Recovery page for mode_sense */
1610 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1611 5, 0, 0xff, 0xff};
1612
1613 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1614 if (1 == pcontrol)
1615 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1616 return sizeof(err_recov_pg);
1617}
1618
1619static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1620{ /* Disconnect-Reconnect page for mode_sense */
1621 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1622 0, 0, 0, 0, 0, 0, 0, 0};
1623
1624 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1625 if (1 == pcontrol)
1626 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1627 return sizeof(disconnect_pg);
1628}
1629
1630static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1631{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001632 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1633 0, 0, 0, 0, 0, 0, 0, 0,
1634 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
Martin K. Petersen597136a2008-06-05 00:12:59 -04001636 memcpy(p, format_pg, sizeof(format_pg));
1637 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1638 p[11] = sdebug_sectors_per & 0xff;
1639 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1640 p[13] = scsi_debug_sector_size & 0xff;
Martin Pittd9867882012-09-06 12:04:33 +02001641 if (scsi_debug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001642 p[20] |= 0x20; /* should agree with INQUIRY */
1643 if (1 == pcontrol)
1644 memset(p + 2, 0, sizeof(format_pg) - 2);
1645 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646}
1647
1648static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1649{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001650 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1651 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1652 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1654
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001655 if (SCSI_DEBUG_OPT_N_WCE & scsi_debug_opts)
1656 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 memcpy(p, caching_pg, sizeof(caching_pg));
1658 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001659 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1660 else if (2 == pcontrol)
1661 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 return sizeof(caching_pg);
1663}
1664
1665static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1666{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001667 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1668 0, 0, 0, 0};
1669 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 0, 0, 0x2, 0x4b};
1671
1672 if (scsi_debug_dsense)
1673 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001674 else
1675 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001676
1677 if (scsi_debug_ato)
1678 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1679
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1681 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001682 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1683 else if (2 == pcontrol)
1684 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 return sizeof(ctrl_m_pg);
1686}
1687
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001688
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1690{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001691 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1692 0, 0, 0x0, 0x0};
1693 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1694 0, 0, 0x0, 0x0};
1695
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1697 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001698 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1699 else if (2 == pcontrol)
1700 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 return sizeof(iec_m_pg);
1702}
1703
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001704static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1705{ /* SAS SSP mode page - short format for mode_sense */
1706 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1707 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1708
1709 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1710 if (1 == pcontrol)
1711 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1712 return sizeof(sas_sf_m_pg);
1713}
1714
1715
1716static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1717 int target_dev_id)
1718{ /* SAS phy control and discover mode page for mode_sense */
1719 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1720 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1721 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1722 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1723 0x2, 0, 0, 0, 0, 0, 0, 0,
1724 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1725 0, 0, 0, 0, 0, 0, 0, 0,
1726 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1727 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1728 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1729 0x3, 0, 0, 0, 0, 0, 0, 0,
1730 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1731 0, 0, 0, 0, 0, 0, 0, 0,
1732 };
1733 int port_a, port_b;
1734
1735 port_a = target_dev_id + 1;
1736 port_b = port_a + 1;
1737 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1738 p[20] = (port_a >> 24);
1739 p[21] = (port_a >> 16) & 0xff;
1740 p[22] = (port_a >> 8) & 0xff;
1741 p[23] = port_a & 0xff;
1742 p[48 + 20] = (port_b >> 24);
1743 p[48 + 21] = (port_b >> 16) & 0xff;
1744 p[48 + 22] = (port_b >> 8) & 0xff;
1745 p[48 + 23] = port_b & 0xff;
1746 if (1 == pcontrol)
1747 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1748 return sizeof(sas_pcd_m_pg);
1749}
1750
1751static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1752{ /* SAS SSP shared protocol specific port mode subpage */
1753 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1754 0, 0, 0, 0, 0, 0, 0, 0,
1755 };
1756
1757 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1758 if (1 == pcontrol)
1759 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1760 return sizeof(sas_sha_m_pg);
1761}
1762
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763#define SDEBUG_MAX_MSENSE_SZ 256
1764
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001765static int
1766resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767{
Douglas Gilbert23183912006-09-16 20:30:47 -04001768 unsigned char dbd, llbaa;
1769 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 unsigned char dev_spec;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001771 int k, alloc_len, msense_6, offset, len, target_dev_id;
1772 int target = scp->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 unsigned char * ap;
1774 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001775 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
Douglas Gilbert23183912006-09-16 20:30:47 -04001777 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 pcontrol = (cmd[2] & 0xc0) >> 6;
1779 pcode = cmd[2] & 0x3f;
1780 subpcode = cmd[3];
1781 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001782 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1783 if ((0 == scsi_debug_ptype) && (0 == dbd))
1784 bd_len = llbaa ? 16 : 8;
1785 else
1786 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1788 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1789 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001790 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 return check_condition_result;
1792 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001793 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1794 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001795 /* set DPOFUA bit for disks */
1796 if (0 == scsi_debug_ptype)
1797 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1798 else
1799 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 if (msense_6) {
1801 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001802 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 offset = 4;
1804 } else {
1805 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001806 if (16 == bd_len)
1807 arr[4] = 0x1; /* set LONGLBA bit */
1808 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 offset = 8;
1810 }
1811 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001812 if ((bd_len > 0) && (!sdebug_capacity))
1813 sdebug_capacity = get_sdebug_capacity();
1814
Douglas Gilbert23183912006-09-16 20:30:47 -04001815 if (8 == bd_len) {
1816 if (sdebug_capacity > 0xfffffffe) {
1817 ap[0] = 0xff;
1818 ap[1] = 0xff;
1819 ap[2] = 0xff;
1820 ap[3] = 0xff;
1821 } else {
1822 ap[0] = (sdebug_capacity >> 24) & 0xff;
1823 ap[1] = (sdebug_capacity >> 16) & 0xff;
1824 ap[2] = (sdebug_capacity >> 8) & 0xff;
1825 ap[3] = sdebug_capacity & 0xff;
1826 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001827 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1828 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001829 offset += bd_len;
1830 ap = arr + offset;
1831 } else if (16 == bd_len) {
1832 unsigned long long capac = sdebug_capacity;
1833
1834 for (k = 0; k < 8; ++k, capac >>= 8)
1835 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001836 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1837 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1838 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1839 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001840 offset += bd_len;
1841 ap = arr + offset;
1842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001844 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1845 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001846 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 return check_condition_result;
1848 }
1849 switch (pcode) {
1850 case 0x1: /* Read-Write error recovery page, direct access */
1851 len = resp_err_recov_pg(ap, pcontrol, target);
1852 offset += len;
1853 break;
1854 case 0x2: /* Disconnect-Reconnect page, all devices */
1855 len = resp_disconnect_pg(ap, pcontrol, target);
1856 offset += len;
1857 break;
1858 case 0x3: /* Format device page, direct access */
1859 len = resp_format_pg(ap, pcontrol, target);
1860 offset += len;
1861 break;
1862 case 0x8: /* Caching page, direct access */
1863 len = resp_caching_pg(ap, pcontrol, target);
1864 offset += len;
1865 break;
1866 case 0xa: /* Control Mode page, all devices */
1867 len = resp_ctrl_m_pg(ap, pcontrol, target);
1868 offset += len;
1869 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001870 case 0x19: /* if spc==1 then sas phy, control+discover */
1871 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001872 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001873 return check_condition_result;
1874 }
1875 len = 0;
1876 if ((0x0 == subpcode) || (0xff == subpcode))
1877 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1878 if ((0x1 == subpcode) || (0xff == subpcode))
1879 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1880 target_dev_id);
1881 if ((0x2 == subpcode) || (0xff == subpcode))
1882 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1883 offset += len;
1884 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 case 0x1c: /* Informational Exceptions Mode page, all devices */
1886 len = resp_iec_m_pg(ap, pcontrol, target);
1887 offset += len;
1888 break;
1889 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001890 if ((0 == subpcode) || (0xff == subpcode)) {
1891 len = resp_err_recov_pg(ap, pcontrol, target);
1892 len += resp_disconnect_pg(ap + len, pcontrol, target);
1893 len += resp_format_pg(ap + len, pcontrol, target);
1894 len += resp_caching_pg(ap + len, pcontrol, target);
1895 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1896 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1897 if (0xff == subpcode) {
1898 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1899 target, target_dev_id);
1900 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1901 }
1902 len += resp_iec_m_pg(ap + len, pcontrol, target);
1903 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001904 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001905 return check_condition_result;
1906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 offset += len;
1908 break;
1909 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001910 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 return check_condition_result;
1912 }
1913 if (msense_6)
1914 arr[0] = offset - 1;
1915 else {
1916 arr[0] = ((offset - 2) >> 8) & 0xff;
1917 arr[1] = (offset - 2) & 0xff;
1918 }
1919 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1920}
1921
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001922#define SDEBUG_MAX_MSELECT_SZ 512
1923
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001924static int
1925resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001926{
1927 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001928 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001929 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001930 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001931 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001932
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001933 memset(arr, 0, sizeof(arr));
1934 pf = cmd[1] & 0x10;
1935 sp = cmd[1] & 0x1;
1936 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1937 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001938 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001939 return check_condition_result;
1940 }
1941 res = fetch_to_dev_buffer(scp, arr, param_len);
1942 if (-1 == res)
1943 return (DID_ERROR << 16);
1944 else if ((res < param_len) &&
1945 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001946 sdev_printk(KERN_INFO, scp->device,
1947 "%s: cdb indicated=%d, IO sent=%d bytes\n",
1948 __func__, param_len, res);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001949 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1950 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001951 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001952 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001953 return check_condition_result;
1954 }
1955 off = bd_len + (mselect6 ? 4 : 8);
1956 mpage = arr[off] & 0x3f;
1957 ps = !!(arr[off] & 0x80);
1958 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001959 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001960 return check_condition_result;
1961 }
1962 spf = !!(arr[off] & 0x40);
1963 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1964 (arr[off + 1] + 2);
1965 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001966 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001967 PARAMETER_LIST_LENGTH_ERR, 0);
1968 return check_condition_result;
1969 }
1970 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001971 case 0x8: /* Caching Mode page */
1972 if (caching_pg[1] == arr[off + 1]) {
1973 memcpy(caching_pg + 2, arr + off + 2,
1974 sizeof(caching_pg) - 2);
1975 goto set_mode_changed_ua;
1976 }
1977 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001978 case 0xa: /* Control Mode page */
1979 if (ctrl_m_pg[1] == arr[off + 1]) {
1980 memcpy(ctrl_m_pg + 2, arr + off + 2,
1981 sizeof(ctrl_m_pg) - 2);
1982 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001983 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001984 }
1985 break;
1986 case 0x1c: /* Informational Exceptions Mode page */
1987 if (iec_m_pg[1] == arr[off + 1]) {
1988 memcpy(iec_m_pg + 2, arr + off + 2,
1989 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001990 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001991 }
1992 break;
1993 default:
1994 break;
1995 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001996 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001997 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001998set_mode_changed_ua:
1999 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2000 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002001}
2002
2003static int resp_temp_l_pg(unsigned char * arr)
2004{
2005 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2006 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2007 };
2008
2009 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2010 return sizeof(temp_l_pg);
2011}
2012
2013static int resp_ie_l_pg(unsigned char * arr)
2014{
2015 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2016 };
2017
2018 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
2019 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2020 arr[4] = THRESHOLD_EXCEEDED;
2021 arr[5] = 0xff;
2022 }
2023 return sizeof(ie_l_pg);
2024}
2025
2026#define SDEBUG_MAX_LSENSE_SZ 512
2027
2028static int resp_log_sense(struct scsi_cmnd * scp,
2029 struct sdebug_dev_info * devip)
2030{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002031 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002032 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002033 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002034
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002035 memset(arr, 0, sizeof(arr));
2036 ppc = cmd[1] & 0x2;
2037 sp = cmd[1] & 0x1;
2038 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002039 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002040 return check_condition_result;
2041 }
2042 pcontrol = (cmd[2] & 0xc0) >> 6;
2043 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002044 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002045 alloc_len = (cmd[7] << 8) + cmd[8];
2046 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002047 if (0 == subpcode) {
2048 switch (pcode) {
2049 case 0x0: /* Supported log pages log page */
2050 n = 4;
2051 arr[n++] = 0x0; /* this page */
2052 arr[n++] = 0xd; /* Temperature */
2053 arr[n++] = 0x2f; /* Informational exceptions */
2054 arr[3] = n - 4;
2055 break;
2056 case 0xd: /* Temperature log page */
2057 arr[3] = resp_temp_l_pg(arr + 4);
2058 break;
2059 case 0x2f: /* Informational exceptions log page */
2060 arr[3] = resp_ie_l_pg(arr + 4);
2061 break;
2062 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002063 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002064 return check_condition_result;
2065 }
2066 } else if (0xff == subpcode) {
2067 arr[0] |= 0x40;
2068 arr[1] = subpcode;
2069 switch (pcode) {
2070 case 0x0: /* Supported log pages and subpages log page */
2071 n = 4;
2072 arr[n++] = 0x0;
2073 arr[n++] = 0x0; /* 0,0 page */
2074 arr[n++] = 0x0;
2075 arr[n++] = 0xff; /* this page */
2076 arr[n++] = 0xd;
2077 arr[n++] = 0x0; /* Temperature */
2078 arr[n++] = 0x2f;
2079 arr[n++] = 0x0; /* Informational exceptions */
2080 arr[3] = n - 4;
2081 break;
2082 case 0xd: /* Temperature subpages */
2083 n = 4;
2084 arr[n++] = 0xd;
2085 arr[n++] = 0x0; /* Temperature */
2086 arr[3] = n - 4;
2087 break;
2088 case 0x2f: /* Informational exceptions subpages */
2089 n = 4;
2090 arr[n++] = 0x2f;
2091 arr[n++] = 0x0; /* Informational exceptions */
2092 arr[3] = n - 4;
2093 break;
2094 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002095 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002096 return check_condition_result;
2097 }
2098 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002099 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002100 return check_condition_result;
2101 }
2102 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
2103 return fill_from_dev_buffer(scp, arr,
2104 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2105}
2106
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002107static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002108 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002110 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002111 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 return check_condition_result;
2113 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002114 /* transfer length excessive (tie in to block limits VPD page) */
2115 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002116 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002117 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002118 return check_condition_result;
2119 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002120 return 0;
2121}
2122
Akinobu Mitaa4517512013-07-08 16:01:57 -07002123/* Returns number of bytes copied or -1 if error. */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002124static int
2125do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002126{
2127 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002128 u64 block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002129 struct scsi_data_buffer *sdb;
2130 enum dma_data_direction dir;
2131 size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
2132 off_t);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002133
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002134 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002135 sdb = scsi_out(scmd);
2136 dir = DMA_TO_DEVICE;
2137 func = sg_pcopy_to_buffer;
2138 } else {
2139 sdb = scsi_in(scmd);
2140 dir = DMA_FROM_DEVICE;
2141 func = sg_pcopy_from_buffer;
2142 }
2143
2144 if (!sdb->length)
2145 return 0;
2146 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
2147 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002148
2149 block = do_div(lba, sdebug_store_sectors);
2150 if (block + num > sdebug_store_sectors)
2151 rest = block + num - sdebug_store_sectors;
2152
Akinobu Mitaa4517512013-07-08 16:01:57 -07002153 ret = func(sdb->table.sgl, sdb->table.nents,
2154 fake_storep + (block * scsi_debug_sector_size),
2155 (num - rest) * scsi_debug_sector_size, 0);
2156 if (ret != (num - rest) * scsi_debug_sector_size)
2157 return ret;
2158
2159 if (rest) {
2160 ret += func(sdb->table.sgl, sdb->table.nents,
2161 fake_storep, rest * scsi_debug_sector_size,
2162 (num - rest) * scsi_debug_sector_size);
2163 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002164
2165 return ret;
2166}
2167
Akinobu Mita51d648a2013-09-18 21:27:28 +09002168static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002169{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002170 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002171
Akinobu Mita51d648a2013-09-18 21:27:28 +09002172 if (scsi_debug_guard)
2173 csum = (__force __be16)ip_compute_csum(buf, len);
2174 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002175 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002176
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002177 return csum;
2178}
2179
2180static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
2181 sector_t sector, u32 ei_lba)
2182{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002183 __be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002184
2185 if (sdt->guard_tag != csum) {
2186 pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
2187 __func__,
2188 (unsigned long)sector,
2189 be16_to_cpu(sdt->guard_tag),
2190 be16_to_cpu(csum));
2191 return 0x01;
2192 }
2193 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
2194 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
2195 pr_err("%s: REF check failed on sector %lu\n",
2196 __func__, (unsigned long)sector);
2197 return 0x03;
2198 }
2199 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2200 be32_to_cpu(sdt->ref_tag) != ei_lba) {
2201 pr_err("%s: REF check failed on sector %lu\n",
2202 __func__, (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002203 return 0x03;
2204 }
2205 return 0;
2206}
2207
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002208static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002209 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002210{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002211 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002212 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002213 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002214 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002215
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002216 /* Bytes of protection data to copy into sgl */
2217 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002218
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002219 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2220 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2221 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2222
2223 while (sg_miter_next(&miter) && resid > 0) {
2224 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002225 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002226 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002227
2228 if (dif_store_end < start + len)
2229 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002230
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002231 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002232
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002233 if (read)
2234 memcpy(paddr, start, len - rest);
2235 else
2236 memcpy(start, paddr, len - rest);
2237
2238 if (rest) {
2239 if (read)
2240 memcpy(paddr + len - rest, dif_storep, rest);
2241 else
2242 memcpy(dif_storep, paddr + len - rest, rest);
2243 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002244
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002245 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002246 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002247 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002248 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002249}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002250
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002251static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2252 unsigned int sectors, u32 ei_lba)
2253{
2254 unsigned int i;
2255 struct sd_dif_tuple *sdt;
2256 sector_t sector;
2257
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002258 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002259 int ret;
2260
2261 sector = start_sec + i;
2262 sdt = dif_store(sector);
2263
Akinobu Mita51d648a2013-09-18 21:27:28 +09002264 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002265 continue;
2266
2267 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2268 if (ret) {
2269 dif_errors++;
2270 return ret;
2271 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002272 }
2273
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002274 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002275 dix_reads++;
2276
2277 return 0;
2278}
2279
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002280static int
2281resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002282{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002283 u8 *cmd = scp->cmnd;
2284 u64 lba;
2285 u32 num;
2286 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002287 unsigned long iflags;
2288 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002289 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002290
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002291 switch (cmd[0]) {
2292 case READ_16:
2293 ei_lba = 0;
2294 lba = get_unaligned_be64(cmd + 2);
2295 num = get_unaligned_be32(cmd + 10);
2296 check_prot = true;
2297 break;
2298 case READ_10:
2299 ei_lba = 0;
2300 lba = get_unaligned_be32(cmd + 2);
2301 num = get_unaligned_be16(cmd + 7);
2302 check_prot = true;
2303 break;
2304 case READ_6:
2305 ei_lba = 0;
2306 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2307 (u32)(cmd[1] & 0x1f) << 16;
2308 num = (0 == cmd[4]) ? 256 : cmd[4];
2309 check_prot = true;
2310 break;
2311 case READ_12:
2312 ei_lba = 0;
2313 lba = get_unaligned_be32(cmd + 2);
2314 num = get_unaligned_be32(cmd + 6);
2315 check_prot = true;
2316 break;
2317 case XDWRITEREAD_10:
2318 ei_lba = 0;
2319 lba = get_unaligned_be32(cmd + 2);
2320 num = get_unaligned_be16(cmd + 7);
2321 check_prot = false;
2322 break;
2323 default: /* assume READ(32) */
2324 lba = get_unaligned_be64(cmd + 12);
2325 ei_lba = get_unaligned_be32(cmd + 20);
2326 num = get_unaligned_be32(cmd + 28);
2327 check_prot = false;
2328 break;
2329 }
2330 if (check_prot) {
2331 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2332 (cmd[1] & 0xe0)) {
2333 mk_sense_invalid_opcode(scp);
2334 return check_condition_result;
2335 }
2336 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
2337 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
2338 (cmd[1] & 0xe0) == 0)
2339 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2340 "to DIF device\n");
2341 }
2342 if (sdebug_any_injecting_opt) {
2343 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2344
2345 if (ep->inj_short)
2346 num /= 2;
2347 }
2348
2349 /* inline check_device_access_params() */
2350 if (lba + num > sdebug_capacity) {
2351 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2352 return check_condition_result;
2353 }
2354 /* transfer length excessive (tie in to block limits VPD page) */
2355 if (num > sdebug_store_sectors) {
2356 /* needs work to find which cdb byte 'num' comes from */
2357 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2358 return check_condition_result;
2359 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002360
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002362 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002363 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2364 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002365 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002366 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002367 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2368 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002369 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2370 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002371 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002372 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002373 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 return check_condition_result;
2375 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002376
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002377 read_lock_irqsave(&atomic_rw, iflags);
2378
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002379 /* DIX + T10 DIF */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002380 if (scsi_debug_dix && scsi_prot_sg_count(scp)) {
2381 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002382
2383 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002384 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002385 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002386 return illegal_condition_result;
2387 }
2388 }
2389
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002390 ret = do_device_access(scp, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 read_unlock_irqrestore(&atomic_rw, iflags);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002392 if (ret == -1)
2393 return DID_ERROR << 16;
2394
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002395 scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002396
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002397 if (sdebug_any_injecting_opt) {
2398 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2399
2400 if (ep->inj_recovered) {
2401 mk_sense_buffer(scp, RECOVERED_ERROR,
2402 THRESHOLD_EXCEEDED, 0);
2403 return check_condition_result;
2404 } else if (ep->inj_transport) {
2405 mk_sense_buffer(scp, ABORTED_COMMAND,
2406 TRANSPORT_PROBLEM, ACK_NAK_TO);
2407 return check_condition_result;
2408 } else if (ep->inj_dif) {
2409 /* Logical block guard check failed */
2410 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2411 return illegal_condition_result;
2412 } else if (ep->inj_dix) {
2413 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2414 return illegal_condition_result;
2415 }
2416 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002417 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418}
2419
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002420void dump_sector(unsigned char *buf, int len)
2421{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002422 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002423
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002424 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002425 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002426 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002427
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002428 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002429 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002430
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002431 if (c >= 0x20 && c < 0x7e)
2432 n += scnprintf(b + n, sizeof(b) - n,
2433 " %c ", buf[i+j]);
2434 else
2435 n += scnprintf(b + n, sizeof(b) - n,
2436 "%02x ", buf[i+j]);
2437 }
2438 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002439 }
2440}
2441
2442static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002443 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002444{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002445 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002446 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002447 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002448 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002449 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002450 int dpage_offset;
2451 struct sg_mapping_iter diter;
2452 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002453
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002454 BUG_ON(scsi_sg_count(SCpnt) == 0);
2455 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2456
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002457 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2458 scsi_prot_sg_count(SCpnt),
2459 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2460 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2461 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002462
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002463 /* For each protection page */
2464 while (sg_miter_next(&piter)) {
2465 dpage_offset = 0;
2466 if (WARN_ON(!sg_miter_next(&diter))) {
2467 ret = 0x01;
2468 goto out;
2469 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002470
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002471 for (ppage_offset = 0; ppage_offset < piter.length;
2472 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002473 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002474 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002475 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002476 if (dpage_offset >= diter.length) {
2477 if (WARN_ON(!sg_miter_next(&diter))) {
2478 ret = 0x01;
2479 goto out;
2480 }
2481 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002482 }
2483
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002484 sdt = piter.addr + ppage_offset;
2485 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002486
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002487 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002488 if (ret) {
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002489 dump_sector(daddr, scsi_debug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002490 goto out;
2491 }
2492
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002493 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002494 ei_lba++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002495 dpage_offset += scsi_debug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002496 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002497 diter.consumed = dpage_offset;
2498 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002499 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002500 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002501
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002502 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002503 dix_writes++;
2504
2505 return 0;
2506
2507out:
2508 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002509 sg_miter_stop(&diter);
2510 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002511 return ret;
2512}
2513
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002514static unsigned long lba_to_map_index(sector_t lba)
2515{
2516 if (scsi_debug_unmap_alignment) {
2517 lba += scsi_debug_unmap_granularity -
2518 scsi_debug_unmap_alignment;
2519 }
2520 do_div(lba, scsi_debug_unmap_granularity);
2521
2522 return lba;
2523}
2524
2525static sector_t map_index_to_lba(unsigned long index)
2526{
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002527 sector_t lba = index * scsi_debug_unmap_granularity;
2528
2529 if (scsi_debug_unmap_alignment) {
2530 lba -= scsi_debug_unmap_granularity -
2531 scsi_debug_unmap_alignment;
2532 }
2533
2534 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002535}
2536
Martin K. Petersen44d92692009-10-15 14:45:27 -04002537static unsigned int map_state(sector_t lba, unsigned int *num)
2538{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002539 sector_t end;
2540 unsigned int mapped;
2541 unsigned long index;
2542 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002543
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002544 index = lba_to_map_index(lba);
2545 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002546
2547 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002548 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002549 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002550 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002551
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002552 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002553 *num = end - lba;
2554
2555 return mapped;
2556}
2557
2558static void map_region(sector_t lba, unsigned int len)
2559{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002560 sector_t end = lba + len;
2561
Martin K. Petersen44d92692009-10-15 14:45:27 -04002562 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002563 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002564
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002565 if (index < map_size)
2566 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002567
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002568 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002569 }
2570}
2571
2572static void unmap_region(sector_t lba, unsigned int len)
2573{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002574 sector_t end = lba + len;
2575
Martin K. Petersen44d92692009-10-15 14:45:27 -04002576 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002577 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002578
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002579 if (lba == map_index_to_lba(index) &&
2580 lba + scsi_debug_unmap_granularity <= end &&
2581 index < map_size) {
2582 clear_bit(index, map_storep);
2583 if (scsi_debug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002584 memset(fake_storep +
Akinobu Mitacc34a8e2013-04-16 22:11:57 +09002585 lba * scsi_debug_sector_size, 0,
2586 scsi_debug_sector_size *
2587 scsi_debug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002588 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002589 if (dif_storep) {
2590 memset(dif_storep + lba, 0xff,
2591 sizeof(*dif_storep) *
2592 scsi_debug_unmap_granularity);
2593 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002594 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002595 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002596 }
2597}
2598
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002599static int
2600resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002602 u8 *cmd = scp->cmnd;
2603 u64 lba;
2604 u32 num;
2605 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002607 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002608 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002610 switch (cmd[0]) {
2611 case WRITE_16:
2612 ei_lba = 0;
2613 lba = get_unaligned_be64(cmd + 2);
2614 num = get_unaligned_be32(cmd + 10);
2615 check_prot = true;
2616 break;
2617 case WRITE_10:
2618 ei_lba = 0;
2619 lba = get_unaligned_be32(cmd + 2);
2620 num = get_unaligned_be16(cmd + 7);
2621 check_prot = true;
2622 break;
2623 case WRITE_6:
2624 ei_lba = 0;
2625 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2626 (u32)(cmd[1] & 0x1f) << 16;
2627 num = (0 == cmd[4]) ? 256 : cmd[4];
2628 check_prot = true;
2629 break;
2630 case WRITE_12:
2631 ei_lba = 0;
2632 lba = get_unaligned_be32(cmd + 2);
2633 num = get_unaligned_be32(cmd + 6);
2634 check_prot = true;
2635 break;
2636 case 0x53: /* XDWRITEREAD(10) */
2637 ei_lba = 0;
2638 lba = get_unaligned_be32(cmd + 2);
2639 num = get_unaligned_be16(cmd + 7);
2640 check_prot = false;
2641 break;
2642 default: /* assume WRITE(32) */
2643 lba = get_unaligned_be64(cmd + 12);
2644 ei_lba = get_unaligned_be32(cmd + 20);
2645 num = get_unaligned_be32(cmd + 28);
2646 check_prot = false;
2647 break;
2648 }
2649 if (check_prot) {
2650 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
2651 (cmd[1] & 0xe0)) {
2652 mk_sense_invalid_opcode(scp);
2653 return check_condition_result;
2654 }
2655 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
2656 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
2657 (cmd[1] & 0xe0) == 0)
2658 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
2659 "to DIF device\n");
2660 }
2661
2662 /* inline check_device_access_params() */
2663 if (lba + num > sdebug_capacity) {
2664 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2665 return check_condition_result;
2666 }
2667 /* transfer length excessive (tie in to block limits VPD page) */
2668 if (num > sdebug_store_sectors) {
2669 /* needs work to find which cdb byte 'num' comes from */
2670 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2671 return check_condition_result;
2672 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002674 write_lock_irqsave(&atomic_rw, iflags);
2675
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002676 /* DIX + T10 DIF */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002677 if (scsi_debug_dix && scsi_prot_sg_count(scp)) {
2678 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002679
2680 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002681 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002682 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002683 return illegal_condition_result;
2684 }
2685 }
2686
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002687 ret = do_device_access(scp, lba, num, true);
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002688 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002689 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002691 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002693 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002695 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002696 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2697 my_name, num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002698
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002699 if (sdebug_any_injecting_opt) {
2700 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
2701
2702 if (ep->inj_recovered) {
2703 mk_sense_buffer(scp, RECOVERED_ERROR,
2704 THRESHOLD_EXCEEDED, 0);
2705 return check_condition_result;
2706 } else if (ep->inj_dif) {
2707 /* Logical block guard check failed */
2708 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2709 return illegal_condition_result;
2710 } else if (ep->inj_dix) {
2711 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2712 return illegal_condition_result;
2713 }
2714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 return 0;
2716}
2717
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002718static int
2719resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba,
2720 bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002721{
2722 unsigned long iflags;
2723 unsigned long long i;
2724 int ret;
2725
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002726 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002727 if (ret)
2728 return ret;
2729
2730 write_lock_irqsave(&atomic_rw, iflags);
2731
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002732 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002733 unmap_region(lba, num);
2734 goto out;
2735 }
2736
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002737 /* if ndob then zero 1 logical block, else fetch 1 logical block */
2738 if (ndob) {
2739 memset(fake_storep + (lba * scsi_debug_sector_size), 0,
2740 scsi_debug_sector_size);
2741 ret = 0;
2742 } else
2743 ret = fetch_to_dev_buffer(scp, fake_storep +
2744 (lba * scsi_debug_sector_size),
2745 scsi_debug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002746
2747 if (-1 == ret) {
2748 write_unlock_irqrestore(&atomic_rw, iflags);
2749 return (DID_ERROR << 16);
2750 } else if ((ret < (num * scsi_debug_sector_size)) &&
2751 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002752 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002753 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2754 my_name, "write same",
2755 num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002756
2757 /* Copy first sector to remaining blocks */
2758 for (i = 1 ; i < num ; i++)
2759 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2760 fake_storep + (lba * scsi_debug_sector_size),
2761 scsi_debug_sector_size);
2762
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002763 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002764 map_region(lba, num);
2765out:
2766 write_unlock_irqrestore(&atomic_rw, iflags);
2767
2768 return 0;
2769}
2770
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002771static int
2772resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2773{
2774 u8 *cmd = scp->cmnd;
2775 u32 lba;
2776 u16 num;
2777 u32 ei_lba = 0;
2778 bool unmap = false;
2779
2780 if (cmd[1] & 0x8) {
2781 if (scsi_debug_lbpws10 == 0) {
2782 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2783 return check_condition_result;
2784 } else
2785 unmap = true;
2786 }
2787 lba = get_unaligned_be32(cmd + 2);
2788 num = get_unaligned_be16(cmd + 7);
2789 if (num > scsi_debug_write_same_length) {
2790 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
2791 return check_condition_result;
2792 }
2793 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
2794}
2795
2796static int
2797resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
2798{
2799 u8 *cmd = scp->cmnd;
2800 u64 lba;
2801 u32 num;
2802 u32 ei_lba = 0;
2803 bool unmap = false;
2804 bool ndob = false;
2805
2806 if (cmd[1] & 0x8) { /* UNMAP */
2807 if (scsi_debug_lbpws == 0) {
2808 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
2809 return check_condition_result;
2810 } else
2811 unmap = true;
2812 }
2813 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
2814 ndob = true;
2815 lba = get_unaligned_be64(cmd + 2);
2816 num = get_unaligned_be32(cmd + 10);
2817 if (num > scsi_debug_write_same_length) {
2818 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
2819 return check_condition_result;
2820 }
2821 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
2822}
2823
Martin K. Petersen44d92692009-10-15 14:45:27 -04002824struct unmap_block_desc {
2825 __be64 lba;
2826 __be32 blocks;
2827 __be32 __reserved;
2828};
2829
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002830static int
2831resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002832{
2833 unsigned char *buf;
2834 struct unmap_block_desc *desc;
2835 unsigned int i, payload_len, descriptors;
2836 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002837 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002838
Martin K. Petersen44d92692009-10-15 14:45:27 -04002839
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002840 if (!scsi_debug_lbp())
2841 return 0; /* fib and say its done */
2842 payload_len = get_unaligned_be16(scp->cmnd + 7);
2843 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002844
2845 descriptors = (payload_len - 8) / 16;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002846 if (descriptors > scsi_debug_unmap_max_desc) {
2847 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002848 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002849 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04002850
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002851 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2852 if (!buf) {
2853 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
2854 INSUFF_RES_ASCQ);
2855 return check_condition_result;
2856 }
2857
2858 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002859
2860 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2861 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2862
2863 desc = (void *)&buf[8];
2864
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002865 write_lock_irqsave(&atomic_rw, iflags);
2866
Martin K. Petersen44d92692009-10-15 14:45:27 -04002867 for (i = 0 ; i < descriptors ; i++) {
2868 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2869 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2870
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002871 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002872 if (ret)
2873 goto out;
2874
2875 unmap_region(lba, num);
2876 }
2877
2878 ret = 0;
2879
2880out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002881 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002882 kfree(buf);
2883
2884 return ret;
2885}
2886
2887#define SDEBUG_GET_LBA_STATUS_LEN 32
2888
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002889static int
2890resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002891{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002892 u8 *cmd = scp->cmnd;
2893 u64 lba;
2894 u32 alloc_len, mapped, num;
2895 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04002896 int ret;
2897
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002898 lba = get_unaligned_be64(cmd + 2);
2899 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002900
2901 if (alloc_len < 24)
2902 return 0;
2903
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002904 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002905 if (ret)
2906 return ret;
2907
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002908 if (scsi_debug_lbp())
2909 mapped = map_state(lba, &num);
2910 else {
2911 mapped = 1;
2912 /* following just in case virtual_gb changed */
2913 sdebug_capacity = get_sdebug_capacity();
2914 if (sdebug_capacity - lba <= 0xffffffff)
2915 num = sdebug_capacity - lba;
2916 else
2917 num = 0xffffffff;
2918 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04002919
2920 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002921 put_unaligned_be32(20, arr); /* Parameter Data Length */
2922 put_unaligned_be64(lba, arr + 8); /* LBA */
2923 put_unaligned_be32(num, arr + 16); /* Number of blocks */
2924 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04002925
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002926 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002927}
2928
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002929#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930
2931static int resp_report_luns(struct scsi_cmnd * scp,
2932 struct sdebug_dev_info * devip)
2933{
2934 unsigned int alloc_len;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002935 int lun_cnt, i, upper, num, n, want_wlun, shortish;
2936 u64 lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002937 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 int select_report = (int)cmd[2];
2939 struct scsi_lun *one_lun;
2940 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002941 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942
2943 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002944 shortish = (alloc_len < 4);
2945 if (shortish || (select_report > 2)) {
2946 mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 return check_condition_result;
2948 }
2949 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2950 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2951 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002952 if (1 == select_report)
2953 lun_cnt = 0;
2954 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2955 --lun_cnt;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002956 want_wlun = (select_report > 0) ? 1 : 0;
2957 num = lun_cnt + want_wlun;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002958 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2959 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2960 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2961 sizeof(struct scsi_lun)), num);
2962 if (n < num) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002963 want_wlun = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002964 lun_cnt = n;
2965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002967 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2968 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2969 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2970 i++, lun++) {
2971 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 if (upper)
2973 one_lun[i].scsi_lun[0] =
2974 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002975 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002977 if (want_wlun) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002978 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2979 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2980 i++;
2981 }
2982 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 return fill_from_dev_buffer(scp, arr,
2984 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2985}
2986
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002987static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2988 unsigned int num, struct sdebug_dev_info *devip)
2989{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002990 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002991 unsigned char *kaddr, *buf;
2992 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002993 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002994 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002995
2996 /* better not to use temporary buffer. */
2997 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09002998 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002999 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3000 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09003001 return check_condition_result;
3002 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003003
FUJITA Tomonori21a61822008-03-09 13:44:30 +09003004 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003005
3006 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003007 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
3008 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003009
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003010 while (sg_miter_next(&miter)) {
3011 kaddr = miter.addr;
3012 for (j = 0; j < miter.length; j++)
3013 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003014
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003015 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003016 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003017 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003018 kfree(buf);
3019
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09003020 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09003021}
3022
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003023static int
3024resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
3025{
3026 u8 *cmd = scp->cmnd;
3027 u64 lba;
3028 u32 num;
3029 int errsts;
3030
3031 if (!scsi_bidi_cmnd(scp)) {
3032 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3033 INSUFF_RES_ASCQ);
3034 return check_condition_result;
3035 }
3036 errsts = resp_read_dt0(scp, devip);
3037 if (errsts)
3038 return errsts;
3039 if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
3040 errsts = resp_write_dt0(scp, devip);
3041 if (errsts)
3042 return errsts;
3043 }
3044 lba = get_unaligned_be32(cmd + 2);
3045 num = get_unaligned_be16(cmd + 7);
3046 return resp_xdwriteread(scp, lba, num, devip);
3047}
3048
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003049/* When timer or tasklet goes off this function is called. */
3050static void sdebug_q_cmd_complete(unsigned long indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003052 int qa_indx;
3053 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003055 struct sdebug_queued_cmd *sqcp;
3056 struct scsi_cmnd *scp;
3057 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003059 atomic_inc(&sdebug_completions);
3060 qa_indx = indx;
3061 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
3062 pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 return;
3064 }
3065 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003066 sqcp = &queued_arr[qa_indx];
3067 scp = sqcp->a_cmnd;
3068 if (NULL == scp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003070 pr_err("%s: scp is NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 return;
3072 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003073 devip = (struct sdebug_dev_info *)scp->device->hostdata;
3074 if (devip)
3075 atomic_dec(&devip->num_in_q);
3076 else
3077 pr_err("%s: devip=NULL\n", __func__);
3078 if (atomic_read(&retired_max_queue) > 0)
3079 retiring = 1;
3080
3081 sqcp->a_cmnd = NULL;
3082 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3083 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3084 pr_err("%s: Unexpected completion\n", __func__);
3085 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003087
3088 if (unlikely(retiring)) { /* user has reduced max_queue */
3089 int k, retval;
3090
3091 retval = atomic_read(&retired_max_queue);
3092 if (qa_indx >= retval) {
3093 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3094 pr_err("%s: index %d too large\n", __func__, retval);
3095 return;
3096 }
3097 k = find_last_bit(queued_in_use_bm, retval);
3098 if ((k < scsi_debug_max_queue) || (k == retval))
3099 atomic_set(&retired_max_queue, 0);
3100 else
3101 atomic_set(&retired_max_queue, k + 1);
3102 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003104 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105}
3106
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003107/* When high resolution timer goes off this function is called. */
3108static enum hrtimer_restart
3109sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
3110{
3111 int qa_indx;
3112 int retiring = 0;
3113 unsigned long iflags;
3114 struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
3115 struct sdebug_queued_cmd *sqcp;
3116 struct scsi_cmnd *scp;
3117 struct sdebug_dev_info *devip;
3118
3119 atomic_inc(&sdebug_completions);
3120 qa_indx = sd_hrtp->qa_indx;
3121 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
3122 pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
3123 goto the_end;
3124 }
3125 spin_lock_irqsave(&queued_arr_lock, iflags);
3126 sqcp = &queued_arr[qa_indx];
3127 scp = sqcp->a_cmnd;
3128 if (NULL == scp) {
3129 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3130 pr_err("%s: scp is NULL\n", __func__);
3131 goto the_end;
3132 }
3133 devip = (struct sdebug_dev_info *)scp->device->hostdata;
3134 if (devip)
3135 atomic_dec(&devip->num_in_q);
3136 else
3137 pr_err("%s: devip=NULL\n", __func__);
3138 if (atomic_read(&retired_max_queue) > 0)
3139 retiring = 1;
3140
3141 sqcp->a_cmnd = NULL;
3142 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
3143 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3144 pr_err("%s: Unexpected completion\n", __func__);
3145 goto the_end;
3146 }
3147
3148 if (unlikely(retiring)) { /* user has reduced max_queue */
3149 int k, retval;
3150
3151 retval = atomic_read(&retired_max_queue);
3152 if (qa_indx >= retval) {
3153 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3154 pr_err("%s: index %d too large\n", __func__, retval);
3155 goto the_end;
3156 }
3157 k = find_last_bit(queued_in_use_bm, retval);
3158 if ((k < scsi_debug_max_queue) || (k == retval))
3159 atomic_set(&retired_max_queue, 0);
3160 else
3161 atomic_set(&retired_max_queue, k + 1);
3162 }
3163 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3164 scp->scsi_done(scp); /* callback to mid level */
3165the_end:
3166 return HRTIMER_NORESTART;
3167}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003169static struct sdebug_dev_info *
3170sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003171{
3172 struct sdebug_dev_info *devip;
3173
3174 devip = kzalloc(sizeof(*devip), flags);
3175 if (devip) {
3176 devip->sdbg_host = sdbg_host;
3177 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3178 }
3179 return devip;
3180}
3181
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
3183{
3184 struct sdebug_host_info * sdbg_host;
3185 struct sdebug_dev_info * open_devip = NULL;
3186 struct sdebug_dev_info * devip =
3187 (struct sdebug_dev_info *)sdev->hostdata;
3188
3189 if (devip)
3190 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003191 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3192 if (!sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003193 pr_err("%s: Host info NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 return NULL;
3195 }
3196 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3197 if ((devip->used) && (devip->channel == sdev->channel) &&
3198 (devip->target == sdev->id) &&
3199 (devip->lun == sdev->lun))
3200 return devip;
3201 else {
3202 if ((!devip->used) && (!open_devip))
3203 open_devip = devip;
3204 }
3205 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003206 if (!open_devip) { /* try and make a new one */
3207 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3208 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003210 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 return NULL;
3212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003214
3215 open_devip->channel = sdev->channel;
3216 open_devip->target = sdev->id;
3217 open_devip->lun = sdev->lun;
3218 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003219 atomic_set(&open_devip->num_in_q, 0);
3220 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003221 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003222 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223}
3224
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003225static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003227 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02003228 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003229 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02003230 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003231 return 0;
3232}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003234static int scsi_debug_slave_configure(struct scsi_device *sdp)
3235{
3236 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003237
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02003239 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003240 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3241 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
3242 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
3243 devip = devInfoReg(sdp);
3244 if (NULL == devip)
3245 return 1; /* no resources, will be marked offline */
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003246 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09003247 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003248 if (scsi_debug_no_uld)
3249 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003250 return 0;
3251}
3252
3253static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3254{
3255 struct sdebug_dev_info *devip =
3256 (struct sdebug_dev_info *)sdp->hostdata;
3257
3258 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02003259 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003260 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3261 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003262 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003263 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003264 sdp->hostdata = NULL;
3265 }
3266}
3267
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003268/* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003269static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
3270{
3271 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003272 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003273 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003274 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003275
3276 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003277 qmax = scsi_debug_max_queue;
3278 r_qmax = atomic_read(&retired_max_queue);
3279 if (r_qmax > qmax)
3280 qmax = r_qmax;
3281 for (k = 0; k < qmax; ++k) {
3282 if (test_bit(k, queued_in_use_bm)) {
3283 sqcp = &queued_arr[k];
3284 if (cmnd == sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003285 devip = (struct sdebug_dev_info *)
3286 cmnd->device->hostdata;
3287 if (devip)
3288 atomic_dec(&devip->num_in_q);
3289 sqcp->a_cmnd = NULL;
3290 spin_unlock_irqrestore(&queued_arr_lock,
3291 iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003292 if (scsi_debug_ndelay > 0) {
3293 if (sqcp->sd_hrtp)
3294 hrtimer_cancel(
3295 &sqcp->sd_hrtp->hrt);
3296 } else if (scsi_debug_delay > 0) {
3297 if (sqcp->cmnd_timerp)
3298 del_timer_sync(
3299 sqcp->cmnd_timerp);
3300 } else if (scsi_debug_delay < 0) {
3301 if (sqcp->tletp)
3302 tasklet_kill(sqcp->tletp);
3303 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003304 clear_bit(k, queued_in_use_bm);
3305 return 1;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003306 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003307 }
3308 }
3309 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003310 return 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003311}
3312
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003313/* Deletes (stops) timers or tasklets of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003314static void stop_all_queued(void)
3315{
3316 unsigned long iflags;
3317 int k;
3318 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003319 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003320
3321 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003322 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3323 if (test_bit(k, queued_in_use_bm)) {
3324 sqcp = &queued_arr[k];
3325 if (sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003326 devip = (struct sdebug_dev_info *)
3327 sqcp->a_cmnd->device->hostdata;
3328 if (devip)
3329 atomic_dec(&devip->num_in_q);
3330 sqcp->a_cmnd = NULL;
3331 spin_unlock_irqrestore(&queued_arr_lock,
3332 iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003333 if (scsi_debug_ndelay > 0) {
3334 if (sqcp->sd_hrtp)
3335 hrtimer_cancel(
3336 &sqcp->sd_hrtp->hrt);
3337 } else if (scsi_debug_delay > 0) {
3338 if (sqcp->cmnd_timerp)
3339 del_timer_sync(
3340 sqcp->cmnd_timerp);
3341 } else if (scsi_debug_delay < 0) {
3342 if (sqcp->tletp)
3343 tasklet_kill(sqcp->tletp);
3344 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04003345 clear_bit(k, queued_in_use_bm);
3346 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003347 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003348 }
3349 }
3350 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351}
3352
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003353/* Free queued command memory on heap */
3354static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003356 unsigned long iflags;
3357 int k;
3358 struct sdebug_queued_cmd *sqcp;
3359
3360 spin_lock_irqsave(&queued_arr_lock, iflags);
3361 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
3362 sqcp = &queued_arr[k];
3363 kfree(sqcp->cmnd_timerp);
3364 sqcp->cmnd_timerp = NULL;
3365 kfree(sqcp->tletp);
3366 sqcp->tletp = NULL;
3367 kfree(sqcp->sd_hrtp);
3368 sqcp->sd_hrtp = NULL;
3369 }
3370 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371}
3372
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003373static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003375 ++num_aborts;
3376 if (SCpnt) {
3377 if (SCpnt->device &&
3378 (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
3379 sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
3380 __func__);
3381 stop_queued_cmnd(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003383 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384}
3385
3386static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
3387{
3388 struct sdebug_dev_info * devip;
3389
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003391 if (SCpnt && SCpnt->device) {
3392 struct scsi_device *sdp = SCpnt->device;
3393
3394 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3395 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3396 devip = devInfoReg(sdp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003398 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 }
3400 return SUCCESS;
3401}
3402
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003403static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
3404{
3405 struct sdebug_host_info *sdbg_host;
3406 struct sdebug_dev_info *devip;
3407 struct scsi_device *sdp;
3408 struct Scsi_Host *hp;
3409 int k = 0;
3410
3411 ++num_target_resets;
3412 if (!SCpnt)
3413 goto lie;
3414 sdp = SCpnt->device;
3415 if (!sdp)
3416 goto lie;
3417 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3418 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3419 hp = sdp->host;
3420 if (!hp)
3421 goto lie;
3422 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
3423 if (sdbg_host) {
3424 list_for_each_entry(devip,
3425 &sdbg_host->dev_info_list,
3426 dev_list)
3427 if (devip->target == sdp->id) {
3428 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3429 ++k;
3430 }
3431 }
3432 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3433 sdev_printk(KERN_INFO, sdp,
3434 "%s: %d device(s) found in target\n", __func__, k);
3435lie:
3436 return SUCCESS;
3437}
3438
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
3440{
3441 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003442 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 struct scsi_device * sdp;
3444 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003445 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003448 if (!(SCpnt && SCpnt->device))
3449 goto lie;
3450 sdp = SCpnt->device;
3451 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
3452 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
3453 hp = sdp->host;
3454 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003455 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003457 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003459 dev_list) {
3460 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3461 ++k;
3462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 }
3464 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003465 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3466 sdev_printk(KERN_INFO, sdp,
3467 "%s: %d device(s) found in host\n", __func__, k);
3468lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 return SUCCESS;
3470}
3471
3472static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
3473{
3474 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003475 struct sdebug_dev_info *devip;
3476 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 ++num_host_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003479 if ((SCpnt->device) && (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
3480 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 spin_lock(&sdebug_host_list_lock);
3482 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003483 list_for_each_entry(devip, &sdbg_host->dev_info_list,
3484 dev_list) {
3485 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3486 ++k;
3487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 }
3489 spin_unlock(&sdebug_host_list_lock);
3490 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003491 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
3492 sdev_printk(KERN_INFO, SCpnt->device,
3493 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 return SUCCESS;
3495}
3496
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003497static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003498 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499{
3500 struct partition * pp;
3501 int starts[SDEBUG_MAX_PARTS + 2];
3502 int sectors_per_part, num_sectors, k;
3503 int heads_by_sects, start_sec, end_sec;
3504
3505 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003506 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 return;
3508 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
3509 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003510 pr_warn("%s: reducing partitions to %d\n", __func__,
3511 SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003513 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 sectors_per_part = (num_sectors - sdebug_sectors_per)
3515 / scsi_debug_num_parts;
3516 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3517 starts[0] = sdebug_sectors_per;
3518 for (k = 1; k < scsi_debug_num_parts; ++k)
3519 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3520 * heads_by_sects;
3521 starts[scsi_debug_num_parts] = num_sectors;
3522 starts[scsi_debug_num_parts + 1] = 0;
3523
3524 ramp[510] = 0x55; /* magic partition markings */
3525 ramp[511] = 0xAA;
3526 pp = (struct partition *)(ramp + 0x1be);
3527 for (k = 0; starts[k + 1]; ++k, ++pp) {
3528 start_sec = starts[k];
3529 end_sec = starts[k + 1] - 1;
3530 pp->boot_ind = 0;
3531
3532 pp->cyl = start_sec / heads_by_sects;
3533 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3534 / sdebug_sectors_per;
3535 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3536
3537 pp->end_cyl = end_sec / heads_by_sects;
3538 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3539 / sdebug_sectors_per;
3540 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3541
Akinobu Mita150c3542013-08-26 22:08:40 +09003542 pp->start_sect = cpu_to_le32(start_sec);
3543 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 pp->sys_ind = 0x83; /* plain Linux partition */
3545 }
3546}
3547
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003548static int
3549schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3550 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003552 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003553 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003554 struct sdebug_queued_cmd *sqcp = NULL;
3555 struct scsi_device *sdp = cmnd->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003557 if (NULL == cmnd || NULL == devip) {
3558 pr_warn("%s: called with NULL cmnd or devip pointer\n",
3559 __func__);
3560 /* no particularly good error to report back */
3561 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003563 if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
3564 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3565 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003566 if (delta_jiff == 0)
3567 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003569 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003570 spin_lock_irqsave(&queued_arr_lock, iflags);
3571 num_in_q = atomic_read(&devip->num_in_q);
3572 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003573 inject = 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003574 if ((qdepth > 0) && (num_in_q >= qdepth)) {
3575 if (scsi_result) {
3576 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3577 goto respond_in_thread;
3578 } else
3579 scsi_result = device_qfull_result;
3580 } else if ((scsi_debug_every_nth != 0) &&
3581 (SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) &&
3582 (scsi_result == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003583 if ((num_in_q == (qdepth - 1)) &&
3584 (atomic_inc_return(&sdebug_a_tsf) >=
3585 abs(scsi_debug_every_nth))) {
3586 atomic_set(&sdebug_a_tsf, 0);
3587 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003588 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003590 }
3591
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003592 k = find_first_zero_bit(queued_in_use_bm, scsi_debug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003593 if (k >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003595 if (scsi_result)
3596 goto respond_in_thread;
3597 else if (SCSI_DEBUG_OPT_ALL_TSF & scsi_debug_opts)
3598 scsi_result = device_qfull_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003599 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts)
3600 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003601 "%s: max_queue=%d exceeded, %s\n",
3602 __func__, scsi_debug_max_queue,
3603 (scsi_result ? "status: TASK SET FULL" :
3604 "report: host busy"));
3605 if (scsi_result)
3606 goto respond_in_thread;
3607 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003608 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003610 __set_bit(k, queued_in_use_bm);
3611 atomic_inc(&devip->num_in_q);
3612 sqcp = &queued_arr[k];
3613 sqcp->a_cmnd = cmnd;
3614 cmnd->result = scsi_result;
3615 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3616 if (delta_jiff > 0) {
3617 if (NULL == sqcp->cmnd_timerp) {
3618 sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list),
3619 GFP_ATOMIC);
3620 if (NULL == sqcp->cmnd_timerp)
3621 return SCSI_MLQUEUE_HOST_BUSY;
3622 init_timer(sqcp->cmnd_timerp);
3623 }
3624 sqcp->cmnd_timerp->function = sdebug_q_cmd_complete;
3625 sqcp->cmnd_timerp->data = k;
3626 sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff;
3627 add_timer(sqcp->cmnd_timerp);
3628 } else if (scsi_debug_ndelay > 0) {
3629 ktime_t kt = ktime_set(0, scsi_debug_ndelay);
3630 struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
3631
3632 if (NULL == sd_hp) {
3633 sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC);
3634 if (NULL == sd_hp)
3635 return SCSI_MLQUEUE_HOST_BUSY;
3636 sqcp->sd_hrtp = sd_hp;
3637 hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
3638 HRTIMER_MODE_REL);
3639 sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
3640 sd_hp->qa_indx = k;
3641 }
3642 hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
3643 } else { /* delay < 0 */
3644 if (NULL == sqcp->tletp) {
3645 sqcp->tletp = kmalloc(sizeof(*sqcp->tletp),
3646 GFP_ATOMIC);
3647 if (NULL == sqcp->tletp)
3648 return SCSI_MLQUEUE_HOST_BUSY;
3649 tasklet_init(sqcp->tletp,
3650 sdebug_q_cmd_complete, k);
3651 }
3652 if (-1 == delta_jiff)
3653 tasklet_hi_schedule(sqcp->tletp);
3654 else
3655 tasklet_schedule(sqcp->tletp);
3656 }
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003657 if ((SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) &&
3658 (scsi_result == device_qfull_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003659 sdev_printk(KERN_INFO, sdp,
3660 "%s: num_in_q=%d +1, %s%s\n", __func__,
3661 num_in_q, (inject ? "<inject> " : ""),
3662 "status: TASK SET FULL");
3663 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003664
3665respond_in_thread: /* call back to mid-layer using invocation thread */
3666 cmnd->result = scsi_result;
3667 cmnd->scsi_done(cmnd);
3668 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003670
Douglas Gilbert23183912006-09-16 20:30:47 -04003671/* Note: The following macros create attribute files in the
3672 /sys/module/scsi_debug/parameters directory. Unfortunately this
3673 driver is unaware of a change and cannot trigger auxiliary actions
3674 as it can when the corresponding attribute in the
3675 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3676 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003677module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003678module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Akinobu Mita0759c662014-02-26 22:57:04 +09003679module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003680module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
3681module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003682module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
3683module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003684module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
3685module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04003686module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Akinobu Mita68aee7b2013-09-18 21:27:27 +09003687module_param_named(guard, scsi_debug_guard, uint, S_IRUGO);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003688module_param_named(host_lock, scsi_debug_host_lock, bool, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003689module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
3690module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
3691module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003692module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003693module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003694module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003695module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003696module_param_named(ndelay, scsi_debug_ndelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003697module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003698module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003699module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
3700module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003701module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003702module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003703module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003704module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
Martin Pittd9867882012-09-06 12:04:33 +02003705module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003706module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003707module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003708module_param_named(strict, scsi_debug_strict, bool, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003709module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
3710module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
3711module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
3712module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003713module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04003714module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
3715 S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003716module_param_named(write_same_length, scsi_debug_write_same_length, int,
3717 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718
3719MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
3720MODULE_DESCRIPTION("SCSI debug adapter driver");
3721MODULE_LICENSE("GPL");
3722MODULE_VERSION(SCSI_DEBUG_VERSION);
3723
3724MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003725MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09003726MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003727MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003728MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003729MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
3730MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003731MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07003732MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04003733MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003734MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003735MODULE_PARM_DESC(host_lock, "use host_lock around all commands (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003736MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
3737MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
3738MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003739MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003740MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003741MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003742MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3743MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003744MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003745MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003747MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003748MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05003749MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003750MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02003752MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02003753MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003754MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003755MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003756MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
3757MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04003758MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
3759MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003760MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003761MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
3762MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
3764static char sdebug_info[256];
3765
3766static const char * scsi_debug_info(struct Scsi_Host * shp)
3767{
3768 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
3769 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
3770 scsi_debug_version_date, scsi_debug_dev_size_mb,
3771 scsi_debug_opts);
3772 return sdebug_info;
3773}
3774
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003775/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Al Viroc8ed5552013-03-31 01:46:06 -04003776static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777{
Al Viroc8ed5552013-03-31 01:46:06 -04003778 char arr[16];
3779 int opts;
3780 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781
Al Viroc8ed5552013-03-31 01:46:06 -04003782 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
3783 return -EACCES;
3784 memcpy(arr, buffer, minLen);
3785 arr[minLen] = '\0';
3786 if (1 != sscanf(arr, "%d", &opts))
3787 return -EINVAL;
3788 scsi_debug_opts = opts;
3789 if (scsi_debug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003790 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04003791 return length;
3792}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003794/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
3795 * same for each scsi_debug host (if more than one). Some of the counters
3796 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04003797static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
3798{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003799 int f, l;
3800 char b[32];
3801
3802 if (scsi_debug_every_nth > 0)
3803 snprintf(b, sizeof(b), " (curr:%d)",
3804 ((SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) ?
3805 atomic_read(&sdebug_a_tsf) :
3806 atomic_read(&sdebug_cmnd_count)));
3807 else
3808 b[0] = '\0';
3809
3810 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
3811 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
3812 "every_nth=%d%s\n"
3813 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
3814 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
3815 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
3816 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
3817 "usec_in_jiffy=%lu\n",
3818 SCSI_DEBUG_VERSION, scsi_debug_version_date,
3819 scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts,
3820 scsi_debug_every_nth, b, scsi_debug_delay, scsi_debug_ndelay,
3821 scsi_debug_max_luns, atomic_read(&sdebug_completions),
3822 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
3823 sdebug_sectors_per, num_aborts, num_dev_resets,
3824 num_target_resets, num_bus_resets, num_host_resets,
3825 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
3826
3827 f = find_first_bit(queued_in_use_bm, scsi_debug_max_queue);
3828 if (f != scsi_debug_max_queue) {
3829 l = find_last_bit(queued_in_use_bm, scsi_debug_max_queue);
3830 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
3831 "queued_in_use_bm", f, l);
3832 }
Al Viroc8ed5552013-03-31 01:46:06 -04003833 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834}
3835
Akinobu Mita82069372013-10-14 22:48:04 +09003836static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837{
3838 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
3839}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003840/* Returns -EBUSY if delay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09003841static ssize_t delay_store(struct device_driver *ddp, const char *buf,
3842 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003844 int delay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003846 if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
3847 res = count;
3848 if (scsi_debug_delay != delay) {
3849 unsigned long iflags;
3850 int k;
3851
3852 spin_lock_irqsave(&queued_arr_lock, iflags);
3853 k = find_first_bit(queued_in_use_bm,
3854 scsi_debug_max_queue);
3855 if (k != scsi_debug_max_queue)
3856 res = -EBUSY; /* have queued commands */
3857 else {
3858 scsi_debug_delay = delay;
3859 scsi_debug_ndelay = 0;
3860 }
3861 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003863 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 }
3865 return -EINVAL;
3866}
Akinobu Mita82069372013-10-14 22:48:04 +09003867static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003869static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
3870{
3871 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ndelay);
3872}
3873/* Returns -EBUSY if ndelay is being changed and commands are queued */
3874/* If > 0 and accepted then scsi_debug_delay is set to DELAY_OVERRIDDEN */
3875static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
3876 size_t count)
3877{
3878 unsigned long iflags;
3879 int ndelay, res, k;
3880
3881 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
3882 (ndelay >= 0) && (ndelay < 1000000000)) {
3883 res = count;
3884 if (scsi_debug_ndelay != ndelay) {
3885 spin_lock_irqsave(&queued_arr_lock, iflags);
3886 k = find_first_bit(queued_in_use_bm,
3887 scsi_debug_max_queue);
3888 if (k != scsi_debug_max_queue)
3889 res = -EBUSY; /* have queued commands */
3890 else {
3891 scsi_debug_ndelay = ndelay;
3892 scsi_debug_delay = ndelay ? DELAY_OVERRIDDEN
3893 : DEF_DELAY;
3894 }
3895 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3896 }
3897 return res;
3898 }
3899 return -EINVAL;
3900}
3901static DRIVER_ATTR_RW(ndelay);
3902
Akinobu Mita82069372013-10-14 22:48:04 +09003903static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904{
3905 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
3906}
3907
Akinobu Mita82069372013-10-14 22:48:04 +09003908static ssize_t opts_store(struct device_driver *ddp, const char *buf,
3909 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910{
3911 int opts;
3912 char work[20];
3913
3914 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07003915 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 if (1 == sscanf(&work[2], "%x", &opts))
3917 goto opts_done;
3918 } else {
3919 if (1 == sscanf(work, "%d", &opts))
3920 goto opts_done;
3921 }
3922 }
3923 return -EINVAL;
3924opts_done:
3925 scsi_debug_opts = opts;
Douglas Gilbert817fd662014-11-24 20:18:02 -05003926 if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
3927 sdebug_any_injecting_opt = true;
3928 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
3929 sdebug_any_injecting_opt = true;
3930 else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
3931 sdebug_any_injecting_opt = true;
3932 else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
3933 sdebug_any_injecting_opt = true;
3934 else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
3935 sdebug_any_injecting_opt = true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003936 atomic_set(&sdebug_cmnd_count, 0);
3937 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 return count;
3939}
Akinobu Mita82069372013-10-14 22:48:04 +09003940static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941
Akinobu Mita82069372013-10-14 22:48:04 +09003942static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943{
3944 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
3945}
Akinobu Mita82069372013-10-14 22:48:04 +09003946static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
3947 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948{
3949 int n;
3950
3951 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3952 scsi_debug_ptype = n;
3953 return count;
3954 }
3955 return -EINVAL;
3956}
Akinobu Mita82069372013-10-14 22:48:04 +09003957static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958
Akinobu Mita82069372013-10-14 22:48:04 +09003959static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960{
3961 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
3962}
Akinobu Mita82069372013-10-14 22:48:04 +09003963static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
3964 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965{
3966 int n;
3967
3968 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3969 scsi_debug_dsense = n;
3970 return count;
3971 }
3972 return -EINVAL;
3973}
Akinobu Mita82069372013-10-14 22:48:04 +09003974static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975
Akinobu Mita82069372013-10-14 22:48:04 +09003976static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04003977{
3978 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
3979}
Akinobu Mita82069372013-10-14 22:48:04 +09003980static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
3981 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04003982{
3983 int n;
3984
3985 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003986 n = (n > 0);
3987 scsi_debug_fake_rw = (scsi_debug_fake_rw > 0);
3988 if (scsi_debug_fake_rw != n) {
3989 if ((0 == n) && (NULL == fake_storep)) {
3990 unsigned long sz =
3991 (unsigned long)scsi_debug_dev_size_mb *
3992 1048576;
3993
3994 fake_storep = vmalloc(sz);
3995 if (NULL == fake_storep) {
3996 pr_err("%s: out of memory, 9\n",
3997 __func__);
3998 return -ENOMEM;
3999 }
4000 memset(fake_storep, 0, sz);
4001 }
4002 scsi_debug_fake_rw = n;
4003 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004004 return count;
4005 }
4006 return -EINVAL;
4007}
Akinobu Mita82069372013-10-14 22:48:04 +09004008static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004009
Akinobu Mita82069372013-10-14 22:48:04 +09004010static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004011{
4012 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
4013}
Akinobu Mita82069372013-10-14 22:48:04 +09004014static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4015 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004016{
4017 int n;
4018
4019 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4020 scsi_debug_no_lun_0 = n;
4021 return count;
4022 }
4023 return -EINVAL;
4024}
Akinobu Mita82069372013-10-14 22:48:04 +09004025static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004026
Akinobu Mita82069372013-10-14 22:48:04 +09004027static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028{
4029 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
4030}
Akinobu Mita82069372013-10-14 22:48:04 +09004031static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4032 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033{
4034 int n;
4035
4036 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4037 scsi_debug_num_tgts = n;
4038 sdebug_max_tgts_luns();
4039 return count;
4040 }
4041 return -EINVAL;
4042}
Akinobu Mita82069372013-10-14 22:48:04 +09004043static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
Akinobu Mita82069372013-10-14 22:48:04 +09004045static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046{
4047 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
4048}
Akinobu Mita82069372013-10-14 22:48:04 +09004049static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050
Akinobu Mita82069372013-10-14 22:48:04 +09004051static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052{
4053 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
4054}
Akinobu Mita82069372013-10-14 22:48:04 +09004055static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056
Akinobu Mita82069372013-10-14 22:48:04 +09004057static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058{
4059 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
4060}
Akinobu Mita82069372013-10-14 22:48:04 +09004061static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4062 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063{
4064 int nth;
4065
4066 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
4067 scsi_debug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004068 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 return count;
4070 }
4071 return -EINVAL;
4072}
Akinobu Mita82069372013-10-14 22:48:04 +09004073static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074
Akinobu Mita82069372013-10-14 22:48:04 +09004075static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076{
4077 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
4078}
Akinobu Mita82069372013-10-14 22:48:04 +09004079static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4080 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081{
4082 int n;
4083
4084 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4085 scsi_debug_max_luns = n;
4086 sdebug_max_tgts_luns();
4087 return count;
4088 }
4089 return -EINVAL;
4090}
Akinobu Mita82069372013-10-14 22:48:04 +09004091static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092
Akinobu Mita82069372013-10-14 22:48:04 +09004093static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004094{
4095 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
4096}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004097/* N.B. max_queue can be changed while there are queued commands. In flight
4098 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004099static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4100 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004101{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004102 unsigned long iflags;
4103 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004104
4105 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
4106 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004107 spin_lock_irqsave(&queued_arr_lock, iflags);
4108 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004109 scsi_debug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004110 if (SCSI_DEBUG_CANQUEUE == k)
4111 atomic_set(&retired_max_queue, 0);
4112 else if (k >= n)
4113 atomic_set(&retired_max_queue, k + 1);
4114 else
4115 atomic_set(&retired_max_queue, 0);
4116 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004117 return count;
4118 }
4119 return -EINVAL;
4120}
Akinobu Mita82069372013-10-14 22:48:04 +09004121static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004122
Akinobu Mita82069372013-10-14 22:48:04 +09004123static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004124{
4125 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
4126}
Akinobu Mita82069372013-10-14 22:48:04 +09004127static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004128
Akinobu Mita82069372013-10-14 22:48:04 +09004129static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130{
4131 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
4132}
Akinobu Mita82069372013-10-14 22:48:04 +09004133static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134
Akinobu Mita82069372013-10-14 22:48:04 +09004135static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004136{
4137 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
4138}
Akinobu Mita82069372013-10-14 22:48:04 +09004139static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4140 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004141{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004142 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004143 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004144
4145 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004146 changed = (scsi_debug_virtual_gb != n);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004147 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004148 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004149 if (changed) {
4150 struct sdebug_host_info *sdhp;
4151 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004152
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004153 list_for_each_entry(sdhp, &sdebug_host_list,
4154 host_list) {
4155 list_for_each_entry(dp, &sdhp->dev_info_list,
4156 dev_list) {
4157 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4158 dp->uas_bm);
4159 }
4160 }
4161 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004162 return count;
4163 }
4164 return -EINVAL;
4165}
Akinobu Mita82069372013-10-14 22:48:04 +09004166static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004167
Akinobu Mita82069372013-10-14 22:48:04 +09004168static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169{
4170 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
4171}
4172
Akinobu Mita82069372013-10-14 22:48:04 +09004173static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4174 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004176 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004178 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 if (delta_hosts > 0) {
4181 do {
4182 sdebug_add_adapter();
4183 } while (--delta_hosts);
4184 } else if (delta_hosts < 0) {
4185 do {
4186 sdebug_remove_adapter();
4187 } while (++delta_hosts);
4188 }
4189 return count;
4190}
Akinobu Mita82069372013-10-14 22:48:04 +09004191static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
Akinobu Mita82069372013-10-14 22:48:04 +09004193static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004194{
4195 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
4196}
Akinobu Mita82069372013-10-14 22:48:04 +09004197static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
4198 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004199{
4200 int n;
4201
4202 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4203 scsi_debug_vpd_use_hostno = n;
4204 return count;
4205 }
4206 return -EINVAL;
4207}
Akinobu Mita82069372013-10-14 22:48:04 +09004208static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04004209
Akinobu Mita82069372013-10-14 22:48:04 +09004210static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04004211{
4212 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
4213}
Akinobu Mita82069372013-10-14 22:48:04 +09004214static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04004215
Akinobu Mita82069372013-10-14 22:48:04 +09004216static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004217{
4218 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
4219}
Akinobu Mita82069372013-10-14 22:48:04 +09004220static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004221
Akinobu Mita82069372013-10-14 22:48:04 +09004222static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004223{
4224 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
4225}
Akinobu Mita82069372013-10-14 22:48:04 +09004226static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004227
Akinobu Mita82069372013-10-14 22:48:04 +09004228static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004229{
Akinobu Mita68aee7b2013-09-18 21:27:27 +09004230 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004231}
Akinobu Mita82069372013-10-14 22:48:04 +09004232static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004233
Akinobu Mita82069372013-10-14 22:48:04 +09004234static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004235{
4236 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
4237}
Akinobu Mita82069372013-10-14 22:48:04 +09004238static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004239
Akinobu Mita82069372013-10-14 22:48:04 +09004240static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04004241{
4242 ssize_t count;
4243
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004244 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04004245 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
4246 sdebug_store_sectors);
4247
4248 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
4249
4250 buf[count++] = '\n';
4251 buf[count++] = 0;
4252
4253 return count;
4254}
Akinobu Mita82069372013-10-14 22:48:04 +09004255static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004256
Akinobu Mita82069372013-10-14 22:48:04 +09004257static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02004258{
4259 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
4260}
Akinobu Mita82069372013-10-14 22:48:04 +09004261static ssize_t removable_store(struct device_driver *ddp, const char *buf,
4262 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02004263{
4264 int n;
4265
4266 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4267 scsi_debug_removable = (n > 0);
4268 return count;
4269 }
4270 return -EINVAL;
4271}
Akinobu Mita82069372013-10-14 22:48:04 +09004272static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02004273
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004274static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
4275{
4276 return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_host_lock);
4277}
4278/* Returns -EBUSY if host_lock is being changed and commands are queued */
4279static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
4280 size_t count)
4281{
4282 int n, res;
4283
4284 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4285 bool new_host_lock = (n > 0);
4286
4287 res = count;
4288 if (new_host_lock != scsi_debug_host_lock) {
4289 unsigned long iflags;
4290 int k;
4291
4292 spin_lock_irqsave(&queued_arr_lock, iflags);
4293 k = find_first_bit(queued_in_use_bm,
4294 scsi_debug_max_queue);
4295 if (k != scsi_debug_max_queue)
4296 res = -EBUSY; /* have queued commands */
4297 else
4298 scsi_debug_host_lock = new_host_lock;
4299 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4300 }
4301 return res;
4302 }
4303 return -EINVAL;
4304}
4305static DRIVER_ATTR_RW(host_lock);
4306
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004307static ssize_t strict_show(struct device_driver *ddp, char *buf)
4308{
4309 return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_strict);
4310}
4311static ssize_t strict_store(struct device_driver *ddp, const char *buf,
4312 size_t count)
4313{
4314 int n;
4315
4316 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
4317 scsi_debug_strict = (n > 0);
4318 return count;
4319 }
4320 return -EINVAL;
4321}
4322static DRIVER_ATTR_RW(strict);
4323
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004324
Akinobu Mita82069372013-10-14 22:48:04 +09004325/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04004326 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
4327 files (over those found in the /sys/module/scsi_debug/parameters
4328 directory) is that auxiliary actions can be triggered when an attribute
4329 is changed. For example see: sdebug_add_host_store() above.
4330 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004331
Akinobu Mita82069372013-10-14 22:48:04 +09004332static struct attribute *sdebug_drv_attrs[] = {
4333 &driver_attr_delay.attr,
4334 &driver_attr_opts.attr,
4335 &driver_attr_ptype.attr,
4336 &driver_attr_dsense.attr,
4337 &driver_attr_fake_rw.attr,
4338 &driver_attr_no_lun_0.attr,
4339 &driver_attr_num_tgts.attr,
4340 &driver_attr_dev_size_mb.attr,
4341 &driver_attr_num_parts.attr,
4342 &driver_attr_every_nth.attr,
4343 &driver_attr_max_luns.attr,
4344 &driver_attr_max_queue.attr,
4345 &driver_attr_no_uld.attr,
4346 &driver_attr_scsi_level.attr,
4347 &driver_attr_virtual_gb.attr,
4348 &driver_attr_add_host.attr,
4349 &driver_attr_vpd_use_hostno.attr,
4350 &driver_attr_sector_size.attr,
4351 &driver_attr_dix.attr,
4352 &driver_attr_dif.attr,
4353 &driver_attr_guard.attr,
4354 &driver_attr_ato.attr,
4355 &driver_attr_map.attr,
4356 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004357 &driver_attr_host_lock.attr,
4358 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004359 &driver_attr_strict.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09004360 NULL,
4361};
4362ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363
Akinobu Mita11ddcec2014-02-26 22:56:59 +09004364static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004365
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366static int __init scsi_debug_init(void)
4367{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004368 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 int host_to_add;
4370 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004371 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004373 atomic_set(&sdebug_cmnd_count, 0);
4374 atomic_set(&sdebug_completions, 0);
4375 atomic_set(&retired_max_queue, 0);
4376
4377 if (scsi_debug_ndelay >= 1000000000) {
4378 pr_warn("%s: ndelay must be less than 1 second, ignored\n",
4379 __func__);
4380 scsi_debug_ndelay = 0;
4381 } else if (scsi_debug_ndelay > 0)
4382 scsi_debug_delay = DELAY_OVERRIDDEN;
4383
Martin K. Petersen597136a2008-06-05 00:12:59 -04004384 switch (scsi_debug_sector_size) {
4385 case 512:
4386 case 1024:
4387 case 2048:
4388 case 4096:
4389 break;
4390 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004391 pr_err("%s: invalid sector_size %d\n", __func__,
Martin K. Petersen597136a2008-06-05 00:12:59 -04004392 scsi_debug_sector_size);
4393 return -EINVAL;
4394 }
4395
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004396 switch (scsi_debug_dif) {
4397
4398 case SD_DIF_TYPE0_PROTECTION:
4399 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004400 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004401 case SD_DIF_TYPE3_PROTECTION:
4402 break;
4403
4404 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004405 pr_err("%s: dif must be 0, 1, 2 or 3\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004406 return -EINVAL;
4407 }
4408
4409 if (scsi_debug_guard > 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004410 pr_err("%s: guard must be 0 or 1\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004411 return -EINVAL;
4412 }
4413
4414 if (scsi_debug_ato > 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004415 pr_err("%s: ato must be 0 or 1\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004416 return -EINVAL;
4417 }
4418
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004419 if (scsi_debug_physblk_exp > 15) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004420 pr_err("%s: invalid physblk_exp %u\n", __func__,
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004421 scsi_debug_physblk_exp);
4422 return -EINVAL;
4423 }
4424
4425 if (scsi_debug_lowest_aligned > 0x3fff) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004426 pr_err("%s: lowest_aligned too big: %u\n", __func__,
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004427 scsi_debug_lowest_aligned);
4428 return -EINVAL;
4429 }
4430
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 if (scsi_debug_dev_size_mb < 1)
4432 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004433 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04004434 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004435 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436
4437 /* play around with geometry, don't waste too much on track 0 */
4438 sdebug_heads = 8;
4439 sdebug_sectors_per = 32;
4440 if (scsi_debug_dev_size_mb >= 16)
4441 sdebug_heads = 32;
4442 else if (scsi_debug_dev_size_mb >= 256)
4443 sdebug_heads = 64;
4444 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4445 (sdebug_sectors_per * sdebug_heads);
4446 if (sdebug_cylinders_per >= 1024) {
4447 /* other LLDs do this; implies >= 1GB ram disk ... */
4448 sdebug_heads = 255;
4449 sdebug_sectors_per = 63;
4450 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
4451 (sdebug_sectors_per * sdebug_heads);
4452 }
4453
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004454 if (0 == scsi_debug_fake_rw) {
4455 fake_storep = vmalloc(sz);
4456 if (NULL == fake_storep) {
4457 pr_err("%s: out of memory, 1\n", __func__);
4458 return -ENOMEM;
4459 }
4460 memset(fake_storep, 0, sz);
4461 if (scsi_debug_num_parts > 0)
4462 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464
Akinobu Mita7cb69d02013-06-29 17:59:16 +09004465 if (scsi_debug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004466 int dif_size;
4467
4468 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
4469 dif_storep = vmalloc(dif_size);
4470
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004471 pr_err("%s: dif_storep %u bytes @ %p\n", __func__, dif_size,
4472 dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004473
4474 if (dif_storep == NULL) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004475 pr_err("%s: out of mem. (DIX)\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004476 ret = -ENOMEM;
4477 goto free_vm;
4478 }
4479
4480 memset(dif_storep, 0xff, dif_size);
4481 }
4482
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004483 /* Logical Block Provisioning */
4484 if (scsi_debug_lbp()) {
Martin K. Petersen60147592010-08-19 11:49:00 -04004485 scsi_debug_unmap_max_blocks =
4486 clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
4487
4488 scsi_debug_unmap_max_desc =
4489 clamp(scsi_debug_unmap_max_desc, 0U, 256U);
4490
4491 scsi_debug_unmap_granularity =
4492 clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
4493
4494 if (scsi_debug_unmap_alignment &&
Akinobu Mitaac170782013-04-16 22:11:56 +09004495 scsi_debug_unmap_granularity <=
4496 scsi_debug_unmap_alignment) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004497 pr_err("%s: ERR: unmap_granularity <= unmap_alignment\n",
Martin K. Petersen44d92692009-10-15 14:45:27 -04004498 __func__);
4499 return -EINVAL;
4500 }
4501
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004502 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
4503 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04004504
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004505 pr_info("%s: %lu provisioning blocks\n", __func__, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004506
4507 if (map_storep == NULL) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004508 pr_err("%s: out of mem. (MAP)\n", __func__);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004509 ret = -ENOMEM;
4510 goto free_vm;
4511 }
4512
Akinobu Mitab90ebc32013-04-16 22:11:58 +09004513 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004514
4515 /* Map first 1KB for partition table */
4516 if (scsi_debug_num_parts)
4517 map_region(0, 2);
4518 }
4519
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004520 pseudo_primary = root_device_register("pseudo_0");
4521 if (IS_ERR(pseudo_primary)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004522 pr_warn("%s: root_device_register() error\n", __func__);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004523 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004524 goto free_vm;
4525 }
4526 ret = bus_register(&pseudo_lld_bus);
4527 if (ret < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004528 pr_warn("%s: bus_register error: %d\n", __func__, ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004529 goto dev_unreg;
4530 }
4531 ret = driver_register(&sdebug_driverfs_driver);
4532 if (ret < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004533 pr_warn("%s: driver_register error: %d\n", __func__, ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004534 goto bus_unreg;
4535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 host_to_add = scsi_debug_add_host;
4538 scsi_debug_add_host = 0;
4539
4540 for (k = 0; k < host_to_add; k++) {
4541 if (sdebug_add_adapter()) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004542 pr_err("%s: sdebug_add_adapter failed k=%d\n",
4543 __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 break;
4545 }
4546 }
4547
4548 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004549 pr_info("%s: built %d host(s)\n", __func__,
4550 scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 }
4552 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004553
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004554bus_unreg:
4555 bus_unregister(&pseudo_lld_bus);
4556dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004557 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004558free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04004559 if (map_storep)
4560 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004561 if (dif_storep)
4562 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004563 vfree(fake_storep);
4564
4565 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566}
4567
4568static void __exit scsi_debug_exit(void)
4569{
4570 int k = scsi_debug_add_host;
4571
4572 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004573 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 for (; k; k--)
4575 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 driver_unregister(&sdebug_driverfs_driver);
4577 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004578 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004580 if (dif_storep)
4581 vfree(dif_storep);
4582
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 vfree(fake_storep);
4584}
4585
4586device_initcall(scsi_debug_init);
4587module_exit(scsi_debug_exit);
4588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589static void sdebug_release_adapter(struct device * dev)
4590{
4591 struct sdebug_host_info *sdbg_host;
4592
4593 sdbg_host = to_sdebug_host(dev);
4594 kfree(sdbg_host);
4595}
4596
4597static int sdebug_add_adapter(void)
4598{
4599 int k, devs_per_host;
4600 int error = 0;
4601 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004602 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004604 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 if (NULL == sdbg_host) {
4606 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004607 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 return -ENOMEM;
4609 }
4610
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4612
4613 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
4614 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004615 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4616 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004618 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 error = -ENOMEM;
4620 goto clean;
4621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 }
4623
4624 spin_lock(&sdebug_host_list_lock);
4625 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4626 spin_unlock(&sdebug_host_list_lock);
4627
4628 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004629 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01004631 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632
4633 error = device_register(&sdbg_host->dev);
4634
4635 if (error)
4636 goto clean;
4637
4638 ++scsi_debug_add_host;
4639 return error;
4640
4641clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004642 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4643 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 list_del(&sdbg_devinfo->dev_list);
4645 kfree(sdbg_devinfo);
4646 }
4647
4648 kfree(sdbg_host);
4649 return error;
4650}
4651
4652static void sdebug_remove_adapter(void)
4653{
4654 struct sdebug_host_info * sdbg_host = NULL;
4655
4656 spin_lock(&sdebug_host_list_lock);
4657 if (!list_empty(&sdebug_host_list)) {
4658 sdbg_host = list_entry(sdebug_host_list.prev,
4659 struct sdebug_host_info, host_list);
4660 list_del(&sdbg_host->host_list);
4661 }
4662 spin_unlock(&sdebug_host_list_lock);
4663
4664 if (!sdbg_host)
4665 return;
4666
4667 device_unregister(&sdbg_host->dev);
4668 --scsi_debug_add_host;
4669}
4670
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004671static int
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004672sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
4673{
4674 if (scsi_debug_host_lock) {
4675 unsigned long iflags;
4676 int rc;
4677
4678 spin_lock_irqsave(shost->host_lock, iflags);
4679 rc = scsi_debug_queuecommand(cmd);
4680 spin_unlock_irqrestore(shost->host_lock, iflags);
4681 return rc;
4682 } else
4683 return scsi_debug_queuecommand(cmd);
4684}
4685
4686static int
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004687sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004688{
4689 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004690 unsigned long iflags;
4691 struct sdebug_dev_info *devip;
4692
4693 spin_lock_irqsave(&queued_arr_lock, iflags);
4694 devip = (struct sdebug_dev_info *)sdev->hostdata;
4695 if (NULL == devip) {
4696 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4697 return -ENODEV;
4698 }
4699 num_in_q = atomic_read(&devip->num_in_q);
4700 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004701
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004702 if (qdepth < 1)
4703 qdepth = 1;
4704 /* allow to exceed max host queued_arr elements for testing */
4705 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4706 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004707 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004708
4709 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4710 sdev_printk(KERN_INFO, sdev,
4711 "%s: qdepth=%d, num_in_q=%d\n",
4712 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004713 }
4714 return sdev->queue_depth;
4715}
4716
4717static int
4718sdebug_change_qtype(struct scsi_device *sdev, int qtype)
4719{
Christoph Hellwiga62182f2014-10-02 14:39:55 +02004720 qtype = scsi_change_queue_type(sdev, qtype);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004721 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4722 const char *cp;
4723
4724 switch (qtype) {
4725 case 0:
4726 cp = "untagged";
4727 break;
4728 case MSG_SIMPLE_TAG:
4729 cp = "simple tags";
4730 break;
4731 case MSG_ORDERED_TAG:
4732 cp = "ordered tags";
4733 break;
4734 default:
4735 cp = "unknown";
4736 break;
4737 }
4738 sdev_printk(KERN_INFO, sdev, "%s: to %s\n", __func__, cp);
4739 }
4740 return qtype;
4741}
Jeff Garzikf2812332010-11-16 02:10:29 -05004742
Douglas Gilbert817fd662014-11-24 20:18:02 -05004743static int
4744check_inject(struct scsi_cmnd *scp)
4745{
4746 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4747
4748 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4749
4750 if (atomic_inc_return(&sdebug_cmnd_count) >=
4751 abs(scsi_debug_every_nth)) {
4752 atomic_set(&sdebug_cmnd_count, 0);
4753 if (scsi_debug_every_nth < -1)
4754 scsi_debug_every_nth = -1;
4755 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
4756 return 1; /* ignore command causing timeout */
4757 else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
4758 scsi_medium_access_command(scp))
4759 return 1; /* time out reads and writes */
4760 if (sdebug_any_injecting_opt) {
4761 int opts = scsi_debug_opts;
4762
4763 if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
4764 ep->inj_recovered = true;
4765 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
4766 ep->inj_transport = true;
4767 else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
4768 ep->inj_dif = true;
4769 else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
4770 ep->inj_dix = true;
4771 else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
4772 ep->inj_short = true;
4773 }
4774 }
4775 return 0;
4776}
4777
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004778static int
4779scsi_debug_queuecommand(struct scsi_cmnd *scp)
4780{
4781 u8 sdeb_i;
4782 struct scsi_device *sdp = scp->device;
4783 const struct opcode_info_t *oip;
4784 const struct opcode_info_t *r_oip;
4785 struct sdebug_dev_info *devip;
4786 u8 *cmd = scp->cmnd;
4787 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
4788 int k, na;
4789 int errsts = 0;
4790 int errsts_no_connect = DID_NO_CONNECT << 16;
4791 u32 flags;
4792 u16 sa;
4793 u8 opcode = cmd[0];
4794 bool has_wlun_rl;
4795 bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
4796
4797 scsi_set_resid(scp, 0);
4798 if (debug && !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) {
4799 char b[120];
4800 int n, len, sb;
4801
4802 len = scp->cmd_len;
4803 sb = (int)sizeof(b);
4804 if (len > 32)
4805 strcpy(b, "too long, over 32 bytes");
4806 else {
4807 for (k = 0, n = 0; k < len && n < sb; ++k)
4808 n += scnprintf(b + n, sb - n, "%02x ",
4809 (u32)cmd[k]);
4810 }
4811 sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
4812 }
4813 has_wlun_rl = (sdp->lun == SAM2_WLUN_REPORT_LUNS);
4814 if ((sdp->lun >= scsi_debug_max_luns) && !has_wlun_rl)
4815 return schedule_resp(scp, NULL, errsts_no_connect, 0);
4816
4817 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
4818 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
4819 devip = (struct sdebug_dev_info *)sdp->hostdata;
4820 if (!devip) {
4821 devip = devInfoReg(sdp);
4822 if (NULL == devip)
4823 return schedule_resp(scp, NULL, errsts_no_connect, 0);
4824 }
4825 na = oip->num_attached;
4826 r_pfp = oip->pfp;
4827 if (na) { /* multiple commands with this opcode */
4828 r_oip = oip;
4829 if (FF_SA & r_oip->flags) {
4830 if (F_SA_LOW & oip->flags)
4831 sa = 0x1f & cmd[1];
4832 else
4833 sa = get_unaligned_be16(cmd + 8);
4834 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
4835 if (opcode == oip->opcode && sa == oip->sa)
4836 break;
4837 }
4838 } else { /* since no service action only check opcode */
4839 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
4840 if (opcode == oip->opcode)
4841 break;
4842 }
4843 }
4844 if (k > na) {
4845 if (F_SA_LOW & r_oip->flags)
4846 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
4847 else if (F_SA_HIGH & r_oip->flags)
4848 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
4849 else
4850 mk_sense_invalid_opcode(scp);
4851 goto check_cond;
4852 }
4853 } /* else (when na==0) we assume the oip is a match */
4854 flags = oip->flags;
4855 if (F_INV_OP & flags) {
4856 mk_sense_invalid_opcode(scp);
4857 goto check_cond;
4858 }
4859 if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
4860 if (debug)
4861 sdev_printk(KERN_INFO, sdp, "scsi_debug: Opcode: "
4862 "0x%x not supported for wlun\n", opcode);
4863 mk_sense_invalid_opcode(scp);
4864 goto check_cond;
4865 }
4866 if (scsi_debug_strict) { /* check cdb against mask */
4867 u8 rem;
4868 int j;
4869
4870 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
4871 rem = ~oip->len_mask[k] & cmd[k];
4872 if (rem) {
4873 for (j = 7; j >= 0; --j, rem <<= 1) {
4874 if (0x80 & rem)
4875 break;
4876 }
4877 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
4878 goto check_cond;
4879 }
4880 }
4881 }
4882 if (!(F_SKIP_UA & flags) &&
4883 SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
4884 errsts = check_readiness(scp, UAS_ONLY, devip);
4885 if (errsts)
4886 goto check_cond;
4887 }
4888 if ((F_M_ACCESS & flags) && devip->stopped) {
4889 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
4890 if (debug)
4891 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
4892 "%s\n", my_name, "initializing command "
4893 "required");
4894 errsts = check_condition_result;
4895 goto fini;
4896 }
4897 if (scsi_debug_fake_rw && (F_FAKE_RW & flags))
4898 goto fini;
4899 if (scsi_debug_every_nth) {
4900 if (check_inject(scp))
4901 return 0; /* ignore command: make trouble */
4902 }
4903 if (oip->pfp) /* if this command has a resp_* function, call it */
4904 errsts = oip->pfp(scp, devip);
4905 else if (r_pfp) /* if leaf function ptr NULL, try the root's */
4906 errsts = r_pfp(scp, devip);
4907
4908fini:
4909 return schedule_resp(scp, devip, errsts,
4910 ((F_DELAY_OVERR & flags) ? 0 : scsi_debug_delay));
4911check_cond:
4912 return schedule_resp(scp, devip, check_condition_result, 0);
4913}
4914
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004915static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04004916 .show_info = scsi_debug_show_info,
4917 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004918 .proc_name = sdebug_proc_name,
4919 .name = "SCSI DEBUG",
4920 .info = scsi_debug_info,
4921 .slave_alloc = scsi_debug_slave_alloc,
4922 .slave_configure = scsi_debug_slave_configure,
4923 .slave_destroy = scsi_debug_slave_destroy,
4924 .ioctl = scsi_debug_ioctl,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004925 .queuecommand = sdebug_queuecommand_lock_or_not,
4926 .change_queue_depth = sdebug_change_qdepth,
4927 .change_queue_type = sdebug_change_qtype,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004928 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004929 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004930 .eh_target_reset_handler = scsi_debug_target_reset,
4931 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004932 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004933 .can_queue = SCSI_DEBUG_CANQUEUE,
4934 .this_id = 7,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09004935 .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004936 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09004937 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004938 .use_clustering = DISABLE_CLUSTERING,
4939 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004940 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05004941 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004942};
4943
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944static int sdebug_driver_probe(struct device * dev)
4945{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05004946 int error = 0;
Douglas Gilbert817fd662014-11-24 20:18:02 -05004947 int opts;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05004948 struct sdebug_host_info *sdbg_host;
4949 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004950 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951
4952 sdbg_host = to_sdebug_host(dev);
4953
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004954 sdebug_driver_template.can_queue = scsi_debug_max_queue;
Akinobu Mita0759c662014-02-26 22:57:04 +09004955 if (scsi_debug_clustering)
4956 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004957 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
4958 if (NULL == hpnt) {
Finn Thain17c9ff52014-10-03 11:43:31 +10004959 pr_err("%s: scsi_host_alloc failed\n", __func__);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004960 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963
4964 sdbg_host->shost = hpnt;
4965 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
4966 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
4967 hpnt->max_id = scsi_debug_num_tgts + 1;
4968 else
4969 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004970 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004972 host_prot = 0;
4973
4974 switch (scsi_debug_dif) {
4975
4976 case SD_DIF_TYPE1_PROTECTION:
4977 host_prot = SHOST_DIF_TYPE1_PROTECTION;
4978 if (scsi_debug_dix)
4979 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
4980 break;
4981
4982 case SD_DIF_TYPE2_PROTECTION:
4983 host_prot = SHOST_DIF_TYPE2_PROTECTION;
4984 if (scsi_debug_dix)
4985 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
4986 break;
4987
4988 case SD_DIF_TYPE3_PROTECTION:
4989 host_prot = SHOST_DIF_TYPE3_PROTECTION;
4990 if (scsi_debug_dix)
4991 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
4992 break;
4993
4994 default:
4995 if (scsi_debug_dix)
4996 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
4997 break;
4998 }
4999
5000 scsi_host_set_prot(hpnt, host_prot);
5001
5002 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
5003 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5004 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5005 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5006 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5007 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5008 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5009 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
5010
5011 if (scsi_debug_guard == 1)
5012 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5013 else
5014 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5015
Douglas Gilbert817fd662014-11-24 20:18:02 -05005016 opts = scsi_debug_opts;
5017 if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
5018 sdebug_any_injecting_opt = true;
5019 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
5020 sdebug_any_injecting_opt = true;
5021 else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
5022 sdebug_any_injecting_opt = true;
5023 else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
5024 sdebug_any_injecting_opt = true;
5025 else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
5026 sdebug_any_injecting_opt = true;
5027
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 error = scsi_add_host(hpnt, &sdbg_host->dev);
5029 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005030 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 error = -ENODEV;
5032 scsi_host_put(hpnt);
5033 } else
5034 scsi_scan_host(hpnt);
5035
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005036 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037}
5038
5039static int sdebug_driver_remove(struct device * dev)
5040{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005042 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043
5044 sdbg_host = to_sdebug_host(dev);
5045
5046 if (!sdbg_host) {
5047 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07005048 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 return -ENODEV;
5050 }
5051
5052 scsi_remove_host(sdbg_host->shost);
5053
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09005054 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5055 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 list_del(&sdbg_devinfo->dev_list);
5057 kfree(sdbg_devinfo);
5058 }
5059
5060 scsi_host_put(sdbg_host->shost);
5061 return 0;
5062}
5063
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005064static int pseudo_lld_bus_match(struct device *dev,
5065 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005067 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005069
5070static struct bus_type pseudo_lld_bus = {
5071 .name = "pseudo",
5072 .match = pseudo_lld_bus_match,
5073 .probe = sdebug_driver_probe,
5074 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005075 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005076};