blob: fce4e47becc7c4f9cf1f502a8a7d92995eba20c3 [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 Gilbertcbf67842014-07-26 11:55:35 -040066#define SCSI_DEBUG_VERSION "1.84"
67static const char *scsi_debug_version_date = "20140706";
68
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
Akinobu Mitac5af0db2014-02-26 22:57:01 +090074#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
78#define ADDR_OUT_OF_RANGE 0x21
Martin K. Petersen395cef02009-09-18 17:33:03 -040079#define INVALID_COMMAND_OPCODE 0x20
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040081#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040082#define UA_RESET_ASC 0x29
83#define UA_CHANGED_ASC 0x2a
84#define POWER_ON_RESET_ASCQ 0x0
85#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
86#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050088#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040089#define THRESHOLD_EXCEEDED 0x5d
90#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050092/* Additional Sense Code Qualifier (ASCQ) */
93#define ACK_NAK_TO 0x3
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96/* Default values for driver parameters */
97#define DEF_NUM_HOST 1
98#define DEF_NUM_TGTS 1
99#define DEF_MAX_LUNS 1
100/* With these defaults, this driver will make 1 host with 1 target
101 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
102 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500103#define DEF_ATO 1
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400104#define DEF_DELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500106#define DEF_DIF 0
107#define DEF_DIX 0
108#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500110#define DEF_FAKE_RW 0
111#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400112#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500113#define DEF_LBPU 0
114#define DEF_LBPWS 0
115#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600116#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500117#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400118#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120#define DEF_NUM_PARTS 0
121#define DEF_OPTS 0
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400122#define DEF_OPT_BLKS 64
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500123#define DEF_PHYSBLK_EXP 0
124#define DEF_PTYPE 0
Martin Pittd9867882012-09-06 12:04:33 +0200125#define DEF_REMOVABLE false
Douglas Gilberte46b0342014-08-05 12:21:53 +0200126#define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500127#define DEF_SECTOR_SIZE 512
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400128#define DEF_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500129#define DEF_UNMAP_ALIGNMENT 0
130#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400131#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
132#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500133#define DEF_VIRTUAL_GB 0
134#define DEF_VPD_USE_HOSTNO 1
135#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400136#define DELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138/* bit mask values for scsi_debug_opts */
139#define SCSI_DEBUG_OPT_NOISE 1
140#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
141#define SCSI_DEBUG_OPT_TIMEOUT 4
142#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500143#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500144#define SCSI_DEBUG_OPT_DIF_ERR 32
145#define SCSI_DEBUG_OPT_DIX_ERR 64
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -0500146#define SCSI_DEBUG_OPT_MAC_TIMEOUT 128
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400147#define SCSI_DEBUG_OPT_SHORT_TRANSFER 0x100
148#define SCSI_DEBUG_OPT_Q_NOISE 0x200
149#define SCSI_DEBUG_OPT_ALL_TSF 0x400
150#define SCSI_DEBUG_OPT_RARE_TSF 0x800
151#define SCSI_DEBUG_OPT_N_WCE 0x1000
152#define SCSI_DEBUG_OPT_RESET_NOISE 0x2000
153#define SCSI_DEBUG_OPT_NO_CDB_NOISE 0x4000
154#define SCSI_DEBUG_OPT_ALL_NOISE (0x1 | 0x200 | 0x2000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155/* When "every_nth" > 0 then modulo "every_nth" commands:
156 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
157 * - a RECOVERED_ERROR is simulated on successful read and write
158 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500159 * - a TRANSPORT_ERROR is simulated on successful read and write
160 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 *
162 * When "every_nth" < 0 then after "- every_nth" commands:
163 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
164 * - a RECOVERED_ERROR is simulated on successful read and write
165 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500166 * - a TRANSPORT_ERROR is simulated on successful read and write
167 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 * This will continue until some other action occurs (e.g. the user
169 * writing a new value (other than -1 or 1) to every_nth via sysfs).
170 */
171
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400172/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in
173 * priority order. In the subset implemented here lower numbers have higher
174 * priority. The UA numbers should be a sequence starting from 0 with
175 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
176#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
177#define SDEBUG_UA_BUS_RESET 1
178#define SDEBUG_UA_MODE_CHANGED 2
179#define SDEBUG_NUM_UAS 3
180
181/* for check_readiness() */
182#define UAS_ONLY 1
183#define UAS_TUR 0
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
186 * sector on read commands: */
187#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500188#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
191 * or "peripheral device" addressing (value 0) */
192#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400193#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400195/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
196 * (for response) at one time. Can be reduced by max_queue option. Command
197 * responses are not queued when delay=0 and ndelay=0. The per-device
198 * DEF_CMD_PER_LUN can be changed via sysfs:
199 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
200 * SCSI_DEBUG_CANQUEUE. */
201#define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */
202#define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
203#define DEF_CMD_PER_LUN 255
204
205#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
206#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
207#endif
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static int scsi_debug_add_host = DEF_NUM_HOST;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500210static int scsi_debug_ato = DEF_ATO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211static int scsi_debug_delay = DEF_DELAY;
212static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500213static int scsi_debug_dif = DEF_DIF;
214static int scsi_debug_dix = DEF_DIX;
215static int scsi_debug_dsense = DEF_D_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216static int scsi_debug_every_nth = DEF_EVERY_NTH;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500217static int scsi_debug_fake_rw = DEF_FAKE_RW;
Akinobu Mita68aee7b2013-09-18 21:27:27 +0900218static unsigned int scsi_debug_guard = DEF_GUARD;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500219static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220static int scsi_debug_max_luns = DEF_MAX_LUNS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400221static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400222static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
223static int scsi_debug_ndelay = DEF_NDELAY;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400224static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500225static int scsi_debug_no_uld = 0;
226static int scsi_debug_num_parts = DEF_NUM_PARTS;
227static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400228static int scsi_debug_opt_blks = DEF_OPT_BLKS;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500229static int scsi_debug_opts = DEF_OPTS;
230static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
231static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
232static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
233static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
234static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
235static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
236static unsigned int scsi_debug_lbpu = DEF_LBPU;
237static unsigned int scsi_debug_lbpws = DEF_LBPWS;
238static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600239static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
Martin K. Petersen60147592010-08-19 11:49:00 -0400240static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500241static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
242static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
243static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
244static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
Martin Pittd9867882012-09-06 12:04:33 +0200245static bool scsi_debug_removable = DEF_REMOVABLE;
Akinobu Mita0759c662014-02-26 22:57:04 +0900246static bool scsi_debug_clustering;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400247static bool scsi_debug_host_lock = DEF_HOST_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400249static atomic_t sdebug_cmnd_count;
250static atomic_t sdebug_completions;
251static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253#define DEV_READONLY(TGT) (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400255static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256static sector_t sdebug_capacity; /* in sectors */
257
258/* old BIOS stuff, kernel may get rid of them but some mode sense pages
259 may still need them */
260static int sdebug_heads; /* heads per disk */
261static int sdebug_cylinders_per; /* cylinders per surface */
262static int sdebug_sectors_per; /* sectors per cylinder */
263
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264#define SDEBUG_MAX_PARTS 4
265
Martin K. Petersen395cef02009-09-18 17:33:03 -0400266#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900267
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500268static unsigned int scsi_debug_lbp(void)
269{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400270 return ((0 == scsi_debug_fake_rw) &&
271 (scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10));
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500272}
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274struct sdebug_dev_info {
275 struct list_head dev_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 unsigned int channel;
277 unsigned int target;
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200278 u64 lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 struct sdebug_host_info *sdbg_host;
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200280 u64 wlun;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400281 unsigned long uas_bm[1];
282 atomic_t num_in_q;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400283 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 char used;
285};
286
287struct sdebug_host_info {
288 struct list_head host_list;
289 struct Scsi_Host *shost;
290 struct device dev;
291 struct list_head dev_info_list;
292};
293
294#define to_sdebug_host(d) \
295 container_of(d, struct sdebug_host_info, dev)
296
297static LIST_HEAD(sdebug_host_list);
298static DEFINE_SPINLOCK(sdebug_host_list_lock);
299
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400300
301struct sdebug_hrtimer { /* ... is derived from hrtimer */
302 struct hrtimer hrt; /* must be first element */
303 int qa_indx;
304};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306struct sdebug_queued_cmd {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400307 /* in_use flagged by a bit in queued_in_use_bm[] */
308 struct timer_list *cmnd_timerp;
309 struct tasklet_struct *tletp;
310 struct sdebug_hrtimer *sd_hrtp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 struct scsi_cmnd * a_cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312};
313static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400314static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317static unsigned char * fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900318static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400319static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
Martin K. Petersen44d92692009-10-15 14:45:27 -0400321static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400322static int num_aborts;
323static int num_dev_resets;
324static int num_target_resets;
325static int num_bus_resets;
326static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500327static int dix_writes;
328static int dix_reads;
329static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331static DEFINE_SPINLOCK(queued_arr_lock);
332static DEFINE_RWLOCK(atomic_rw);
333
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400334static char sdebug_proc_name[] = MY_NAME;
335static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337static struct bus_type pseudo_lld_bus;
338
339static struct device_driver sdebug_driverfs_driver = {
340 .name = sdebug_proc_name,
341 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342};
343
344static const int check_condition_result =
345 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
346
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500347static const int illegal_condition_result =
348 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
349
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400350static const int device_qfull_result =
351 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
352
353static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
354 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
355 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400356static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
357 0, 0, 0x2, 0x4b};
358static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
359 0, 0, 0x0, 0x0};
360
Akinobu Mita14faa942013-09-18 21:27:24 +0900361static void *fake_store(unsigned long long lba)
362{
363 lba = do_div(lba, sdebug_store_sectors);
364
365 return fake_storep + lba * scsi_debug_sector_size;
366}
367
368static struct sd_dif_tuple *dif_store(sector_t sector)
369{
370 sector = do_div(sector, sdebug_store_sectors);
371
372 return dif_storep + sector;
373}
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375static int sdebug_add_adapter(void);
376static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900378static void sdebug_max_tgts_luns(void)
379{
380 struct sdebug_host_info *sdbg_host;
381 struct Scsi_Host *hpnt;
382
383 spin_lock(&sdebug_host_list_lock);
384 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
385 hpnt = sdbg_host->shost;
386 if ((hpnt->this_id >= 0) &&
387 (scsi_debug_num_tgts > hpnt->this_id))
388 hpnt->max_id = scsi_debug_num_tgts + 1;
389 else
390 hpnt->max_id = scsi_debug_num_tgts;
391 /* scsi_debug_max_luns; */
392 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
393 }
394 spin_unlock(&sdebug_host_list_lock);
395}
396
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400397static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900398{
399 unsigned char *sbuff;
400
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400401 sbuff = scp->sense_buffer;
402 if (!sbuff) {
403 sdev_printk(KERN_ERR, scp->device,
404 "%s: sense_buffer is NULL\n", __func__);
405 return;
406 }
407 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900408
409 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
410
411 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400412 sdev_printk(KERN_INFO, scp->device,
413 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
414 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900415}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900417static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400418 unsigned long long *lba, unsigned int *num,
419 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900420{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400421 *ei_lba = 0;
422
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900423 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400424 case VARIABLE_LENGTH_CMD:
425 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
426 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
427 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
428 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
429
430 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
431 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
432
433 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
434 (u32)cmd[28] << 24;
435 break;
436
Martin K. Petersen44d92692009-10-15 14:45:27 -0400437 case WRITE_SAME_16:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900438 case WRITE_16:
439 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900440 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
441 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
442 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
443 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
444
445 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
446 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900447 break;
448 case WRITE_12:
449 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900450 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
451 (u32)cmd[2] << 24;
452
453 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
454 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900455 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400456 case WRITE_SAME:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900457 case WRITE_10:
458 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900459 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900460 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
461 (u32)cmd[2] << 24;
462
463 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900464 break;
465 case WRITE_6:
466 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900467 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
468 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900469 *num = (0 == cmd[4]) ? 256 : cmd[4];
470 break;
471 default:
472 break;
473 }
474}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
477{
478 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400479 if (0x1261 == cmd)
480 sdev_printk(KERN_INFO, dev,
481 "%s: BLKFLSBUF [0x1261]\n", __func__);
482 else if (0x5331 == cmd)
483 sdev_printk(KERN_INFO, dev,
484 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
485 __func__);
486 else
487 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
488 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 }
490 return -EINVAL;
491 /* return -ENOTTY; // correct return but upsets fdisk */
492}
493
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400494static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400495 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400497 int k;
498 bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
499
500 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
501 if (k != SDEBUG_NUM_UAS) {
502 const char *cp = NULL;
503
504 switch (k) {
505 case SDEBUG_UA_POR:
506 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
507 UA_RESET_ASC, POWER_ON_RESET_ASCQ);
508 if (debug)
509 cp = "power on reset";
510 break;
511 case SDEBUG_UA_BUS_RESET:
512 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
513 UA_RESET_ASC, BUS_RESET_ASCQ);
514 if (debug)
515 cp = "bus reset";
516 break;
517 case SDEBUG_UA_MODE_CHANGED:
518 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
519 UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
520 if (debug)
521 cp = "mode parameters changed";
522 break;
523 default:
524 pr_warn("%s: unexpected unit attention code=%d\n",
525 __func__, k);
526 if (debug)
527 cp = "unknown";
528 break;
529 }
530 clear_bit(k, devip->uas_bm);
531 if (debug)
532 sdev_printk(KERN_INFO, SCpnt->device,
533 "%s reports: Unit attention: %s\n",
534 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return check_condition_result;
536 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400537 if ((UAS_TUR == uas_only) && devip->stopped) {
538 mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400539 0x2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400540 if (debug)
541 sdev_printk(KERN_INFO, SCpnt->device,
542 "%s reports: Not ready: %s\n", my_name,
543 "initializing command required");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400544 return check_condition_result;
545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 return 0;
547}
548
549/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900550static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 int arr_len)
552{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900553 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900554 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900556 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900558 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900560
561 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
562 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700563 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 return 0;
566}
567
568/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900569static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
570 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900572 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900574 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900576
577 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578}
579
580
581static const char * inq_vendor_id = "Linux ";
582static const char * inq_product_id = "scsi_debug ";
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400583static const char *inq_product_rev = "0184"; /* version less '.' */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400585/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200586static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
587 int target_dev_id, int dev_id_num,
588 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400589 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400591 int num, port_a;
592 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400594 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 /* T10 vendor identifier field format (faked) */
596 arr[0] = 0x2; /* ASCII */
597 arr[1] = 0x1;
598 arr[2] = 0x0;
599 memcpy(&arr[4], inq_vendor_id, 8);
600 memcpy(&arr[12], inq_product_id, 16);
601 memcpy(&arr[28], dev_id_str, dev_id_str_len);
602 num = 8 + 16 + dev_id_str_len;
603 arr[3] = num;
604 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400605 if (dev_id_num >= 0) {
606 /* NAA-5, Logical unit identifier (binary) */
607 arr[num++] = 0x1; /* binary (not necessarily sas) */
608 arr[num++] = 0x3; /* PIV=0, lu, naa */
609 arr[num++] = 0x0;
610 arr[num++] = 0x8;
611 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
612 arr[num++] = 0x33;
613 arr[num++] = 0x33;
614 arr[num++] = 0x30;
615 arr[num++] = (dev_id_num >> 24);
616 arr[num++] = (dev_id_num >> 16) & 0xff;
617 arr[num++] = (dev_id_num >> 8) & 0xff;
618 arr[num++] = dev_id_num & 0xff;
619 /* Target relative port number */
620 arr[num++] = 0x61; /* proto=sas, binary */
621 arr[num++] = 0x94; /* PIV=1, target port, rel port */
622 arr[num++] = 0x0; /* reserved */
623 arr[num++] = 0x4; /* length */
624 arr[num++] = 0x0; /* reserved */
625 arr[num++] = 0x0; /* reserved */
626 arr[num++] = 0x0;
627 arr[num++] = 0x1; /* relative port A */
628 }
629 /* NAA-5, Target port identifier */
630 arr[num++] = 0x61; /* proto=sas, binary */
631 arr[num++] = 0x93; /* piv=1, target port, naa */
632 arr[num++] = 0x0;
633 arr[num++] = 0x8;
634 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
635 arr[num++] = 0x22;
636 arr[num++] = 0x22;
637 arr[num++] = 0x20;
638 arr[num++] = (port_a >> 24);
639 arr[num++] = (port_a >> 16) & 0xff;
640 arr[num++] = (port_a >> 8) & 0xff;
641 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200642 /* NAA-5, Target port group identifier */
643 arr[num++] = 0x61; /* proto=sas, binary */
644 arr[num++] = 0x95; /* piv=1, target port group id */
645 arr[num++] = 0x0;
646 arr[num++] = 0x4;
647 arr[num++] = 0;
648 arr[num++] = 0;
649 arr[num++] = (port_group_id >> 8) & 0xff;
650 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400651 /* NAA-5, Target device identifier */
652 arr[num++] = 0x61; /* proto=sas, binary */
653 arr[num++] = 0xa3; /* piv=1, target device, naa */
654 arr[num++] = 0x0;
655 arr[num++] = 0x8;
656 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
657 arr[num++] = 0x22;
658 arr[num++] = 0x22;
659 arr[num++] = 0x20;
660 arr[num++] = (target_dev_id >> 24);
661 arr[num++] = (target_dev_id >> 16) & 0xff;
662 arr[num++] = (target_dev_id >> 8) & 0xff;
663 arr[num++] = target_dev_id & 0xff;
664 /* SCSI name string: Target device identifier */
665 arr[num++] = 0x63; /* proto=sas, UTF-8 */
666 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
667 arr[num++] = 0x0;
668 arr[num++] = 24;
669 memcpy(arr + num, "naa.52222220", 12);
670 num += 12;
671 snprintf(b, sizeof(b), "%08X", target_dev_id);
672 memcpy(arr + num, b, 8);
673 num += 8;
674 memset(arr + num, 0, 4);
675 num += 4;
676 return num;
677}
678
679
680static unsigned char vpd84_data[] = {
681/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
682 0x22,0x22,0x22,0x0,0xbb,0x1,
683 0x22,0x22,0x22,0x0,0xbb,0x2,
684};
685
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400686/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400687static int inquiry_evpd_84(unsigned char * arr)
688{
689 memcpy(arr, vpd84_data, sizeof(vpd84_data));
690 return sizeof(vpd84_data);
691}
692
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400693/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400694static int inquiry_evpd_85(unsigned char * arr)
695{
696 int num = 0;
697 const char * na1 = "https://www.kernel.org/config";
698 const char * na2 = "http://www.kernel.org/log";
699 int plen, olen;
700
701 arr[num++] = 0x1; /* lu, storage config */
702 arr[num++] = 0x0; /* reserved */
703 arr[num++] = 0x0;
704 olen = strlen(na1);
705 plen = olen + 1;
706 if (plen % 4)
707 plen = ((plen / 4) + 1) * 4;
708 arr[num++] = plen; /* length, null termianted, padded */
709 memcpy(arr + num, na1, olen);
710 memset(arr + num + olen, 0, plen - olen);
711 num += plen;
712
713 arr[num++] = 0x4; /* lu, logging */
714 arr[num++] = 0x0; /* reserved */
715 arr[num++] = 0x0;
716 olen = strlen(na2);
717 plen = olen + 1;
718 if (plen % 4)
719 plen = ((plen / 4) + 1) * 4;
720 arr[num++] = plen; /* length, null terminated, padded */
721 memcpy(arr + num, na2, olen);
722 memset(arr + num + olen, 0, plen - olen);
723 num += plen;
724
725 return num;
726}
727
728/* SCSI ports VPD page */
729static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
730{
731 int num = 0;
732 int port_a, port_b;
733
734 port_a = target_dev_id + 1;
735 port_b = port_a + 1;
736 arr[num++] = 0x0; /* reserved */
737 arr[num++] = 0x0; /* reserved */
738 arr[num++] = 0x0;
739 arr[num++] = 0x1; /* relative port 1 (primary) */
740 memset(arr + num, 0, 6);
741 num += 6;
742 arr[num++] = 0x0;
743 arr[num++] = 12; /* length tp descriptor */
744 /* naa-5 target port identifier (A) */
745 arr[num++] = 0x61; /* proto=sas, binary */
746 arr[num++] = 0x93; /* PIV=1, target port, NAA */
747 arr[num++] = 0x0; /* reserved */
748 arr[num++] = 0x8; /* length */
749 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
750 arr[num++] = 0x22;
751 arr[num++] = 0x22;
752 arr[num++] = 0x20;
753 arr[num++] = (port_a >> 24);
754 arr[num++] = (port_a >> 16) & 0xff;
755 arr[num++] = (port_a >> 8) & 0xff;
756 arr[num++] = port_a & 0xff;
757
758 arr[num++] = 0x0; /* reserved */
759 arr[num++] = 0x0; /* reserved */
760 arr[num++] = 0x0;
761 arr[num++] = 0x2; /* relative port 2 (secondary) */
762 memset(arr + num, 0, 6);
763 num += 6;
764 arr[num++] = 0x0;
765 arr[num++] = 12; /* length tp descriptor */
766 /* naa-5 target port identifier (B) */
767 arr[num++] = 0x61; /* proto=sas, binary */
768 arr[num++] = 0x93; /* PIV=1, target port, NAA */
769 arr[num++] = 0x0; /* reserved */
770 arr[num++] = 0x8; /* length */
771 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
772 arr[num++] = 0x22;
773 arr[num++] = 0x22;
774 arr[num++] = 0x20;
775 arr[num++] = (port_b >> 24);
776 arr[num++] = (port_b >> 16) & 0xff;
777 arr[num++] = (port_b >> 8) & 0xff;
778 arr[num++] = port_b & 0xff;
779
780 return num;
781}
782
783
784static unsigned char vpd89_data[] = {
785/* from 4th byte */ 0,0,0,0,
786'l','i','n','u','x',' ',' ',' ',
787'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
788'1','2','3','4',
7890x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
7900xec,0,0,0,
7910x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
7920,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
7930x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
7940x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
7950x53,0x41,
7960x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
7970x20,0x20,
7980x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
7990x10,0x80,
8000,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8010x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8020x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8030,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8040x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8050x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8060,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
8070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8090,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8100x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
8110,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
8120xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
8130,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
8140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8250,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
826};
827
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400828/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400829static int inquiry_evpd_89(unsigned char * arr)
830{
831 memcpy(arr, vpd89_data, sizeof(vpd89_data));
832 return sizeof(vpd89_data);
833}
834
835
836static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400837 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
838 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
839 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
840 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400841};
842
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400843/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400844static int inquiry_evpd_b0(unsigned char * arr)
845{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400846 unsigned int gran;
847
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400848 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400849
850 /* Optimal transfer length granularity */
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400851 gran = 1 << scsi_debug_physblk_exp;
852 arr[2] = (gran >> 8) & 0xff;
853 arr[3] = gran & 0xff;
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400854
855 /* Maximum Transfer Length */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400856 if (sdebug_store_sectors > 0x400) {
857 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
858 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
859 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
860 arr[7] = sdebug_store_sectors & 0xff;
861 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400862
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400863 /* Optimal Transfer Length */
864 put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
865
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500866 if (scsi_debug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400867 /* Maximum Unmap LBA Count */
Martin K. Petersen60147592010-08-19 11:49:00 -0400868 put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400869
870 /* Maximum Unmap Block Descriptor Count */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400871 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
872 }
873
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400874 /* Unmap Granularity Alignment */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400875 if (scsi_debug_unmap_alignment) {
876 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
877 arr[28] |= 0x80; /* UGAVALID */
878 }
879
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400880 /* Optimal Unmap Granularity */
Martin K. Petersen60147592010-08-19 11:49:00 -0400881 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
882
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500883 /* Maximum WRITE SAME Length */
884 put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
885
886 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400887
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400888 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889}
890
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400891/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600892static int inquiry_evpd_b1(unsigned char *arr)
893{
894 memset(arr, 0, 0x3c);
895 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400896 arr[1] = 1; /* non rotating medium (e.g. solid state) */
897 arr[2] = 0;
898 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600899
900 return 0x3c;
901}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600903/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -0400904static int inquiry_evpd_b2(unsigned char *arr)
905{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -0500906 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -0400907 arr[0] = 0; /* threshold exponent */
908
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500909 if (scsi_debug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -0400910 arr[1] = 1 << 7;
911
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500912 if (scsi_debug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -0400913 arr[1] |= 1 << 6;
914
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500915 if (scsi_debug_lbpws10)
916 arr[1] |= 1 << 5;
917
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600918 if (scsi_debug_lbprz)
919 arr[1] |= 1 << 2;
920
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -0500921 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -0400922}
923
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400925#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400927static int resp_inquiry(struct scsi_cmnd *scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 struct sdebug_dev_info * devip)
929{
930 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200931 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +0200932 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200933 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
935 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500936 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
937 if (! arr)
938 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400939 if (devip->wlun)
940 pq_pdt = 0x1e; /* present, wlun */
941 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
942 pq_pdt = 0x7f; /* not present, no device type */
943 else
944 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 arr[0] = pq_pdt;
946 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400947 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200949 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 return check_condition_result;
951 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200952 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400953 char lu_id_str[6];
954 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200956 port_group_id = (((host_no + 1) & 0x7f) << 8) +
957 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400958 if (0 == scsi_debug_vpd_use_hostno)
959 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400960 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
961 (devip->target * 1000) + devip->lun);
962 target_dev_id = ((host_no + 1) * 2000) +
963 (devip->target * 1000) - 3;
964 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400966 arr[1] = cmd[2]; /*sanity */
967 n = 4;
968 arr[n++] = 0x0; /* this page */
969 arr[n++] = 0x80; /* unit serial number */
970 arr[n++] = 0x83; /* device identification */
971 arr[n++] = 0x84; /* software interface ident. */
972 arr[n++] = 0x85; /* management network addresses */
973 arr[n++] = 0x86; /* extended inquiry */
974 arr[n++] = 0x87; /* mode page policy */
975 arr[n++] = 0x88; /* SCSI ports */
976 arr[n++] = 0x89; /* ATA information */
977 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600978 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500979 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
980 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400981 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400983 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400985 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400987 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200988 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
989 target_dev_id, lu_id_num,
990 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400991 } else if (0x84 == cmd[2]) { /* Software interface ident. */
992 arr[1] = cmd[2]; /*sanity */
993 arr[3] = inquiry_evpd_84(&arr[4]);
994 } else if (0x85 == cmd[2]) { /* Management network addresses */
995 arr[1] = cmd[2]; /*sanity */
996 arr[3] = inquiry_evpd_85(&arr[4]);
997 } else if (0x86 == cmd[2]) { /* extended inquiry */
998 arr[1] = cmd[2]; /*sanity */
999 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001000 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
1001 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
1002 else if (scsi_debug_dif)
1003 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1004 else
1005 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001006 arr[5] = 0x7; /* head of q, ordered + simple q's */
1007 } else if (0x87 == cmd[2]) { /* mode page policy */
1008 arr[1] = cmd[2]; /*sanity */
1009 arr[3] = 0x8; /* number of following entries */
1010 arr[4] = 0x2; /* disconnect-reconnect mp */
1011 arr[6] = 0x80; /* mlus, shared */
1012 arr[8] = 0x18; /* protocol specific lu */
1013 arr[10] = 0x82; /* mlus, per initiator port */
1014 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1015 arr[1] = cmd[2]; /*sanity */
1016 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1017 } else if (0x89 == cmd[2]) { /* ATA information */
1018 arr[1] = cmd[2]; /*sanity */
1019 n = inquiry_evpd_89(&arr[4]);
1020 arr[2] = (n >> 8);
1021 arr[3] = (n & 0xff);
1022 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1023 arr[1] = cmd[2]; /*sanity */
1024 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001025 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1026 arr[1] = cmd[2]; /*sanity */
1027 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001028 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001029 arr[1] = cmd[2]; /*sanity */
1030 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 } else {
1032 /* Illegal request, invalid field in cdb */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001033 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001035 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return check_condition_result;
1037 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001038 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001039 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001040 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001041 kfree(arr);
1042 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 }
1044 /* drops through here for a standard inquiry */
Martin Pittd9867882012-09-06 12:04:33 +02001045 arr[1] = scsi_debug_removable ? 0x80 : 0; /* Removable disk */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 arr[2] = scsi_debug_scsi_level;
1047 arr[3] = 2; /* response_data_format==2 */
1048 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001049 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001050 if (0 == scsi_debug_vpd_use_hostno)
1051 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001052 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001054 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 memcpy(&arr[8], inq_vendor_id, 8);
1056 memcpy(&arr[16], inq_product_id, 16);
1057 memcpy(&arr[32], inq_product_rev, 4);
1058 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001059 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1060 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001061 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 if (scsi_debug_ptype == 0) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001063 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 } else if (scsi_debug_ptype == 1) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001065 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001067 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001068 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001070 kfree(arr);
1071 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072}
1073
1074static int resp_requests(struct scsi_cmnd * scp,
1075 struct sdebug_dev_info * devip)
1076{
1077 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001078 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001079 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001080 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 int len = 18;
1082
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001083 memset(arr, 0, sizeof(arr));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001084 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001085 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001086 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1087 if (want_dsense) {
1088 arr[0] = 0x72;
1089 arr[1] = 0x0; /* NO_SENSE in sense_key */
1090 arr[2] = THRESHOLD_EXCEEDED;
1091 arr[3] = 0xff; /* TEST set and MRIE==6 */
1092 } else {
1093 arr[0] = 0x70;
1094 arr[2] = 0x0; /* NO_SENSE in sense_key */
1095 arr[7] = 0xa; /* 18 byte sense buffer */
1096 arr[12] = THRESHOLD_EXCEEDED;
1097 arr[13] = 0xff; /* TEST set and MRIE==6 */
1098 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001099 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001100 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001101 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1102 /* DESC bit set and sense_buff in fixed format */
1103 memset(arr, 0, sizeof(arr));
1104 arr[0] = 0x72;
1105 arr[1] = sbuff[2]; /* sense key */
1106 arr[2] = sbuff[12]; /* asc */
1107 arr[3] = sbuff[13]; /* ascq */
1108 len = 8;
1109 }
1110 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001111 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 return fill_from_dev_buffer(scp, arr, len);
1113}
1114
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001115static int resp_start_stop(struct scsi_cmnd * scp,
1116 struct sdebug_dev_info * devip)
1117{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001118 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001119 int power_cond, errsts, start;
1120
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001121 errsts = check_readiness(scp, UAS_ONLY, devip);
1122 if (errsts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001123 return errsts;
1124 power_cond = (cmd[4] & 0xf0) >> 4;
1125 if (power_cond) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001126 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001127 0);
1128 return check_condition_result;
1129 }
1130 start = cmd[4] & 1;
1131 if (start == devip->stopped)
1132 devip->stopped = !start;
1133 return 0;
1134}
1135
FUJITA Tomonori28898872008-03-30 00:59:55 +09001136static sector_t get_sdebug_capacity(void)
1137{
1138 if (scsi_debug_virtual_gb > 0)
Douglas Gilbert5447ed62010-04-25 12:30:23 +02001139 return (sector_t)scsi_debug_virtual_gb *
1140 (1073741824 / scsi_debug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001141 else
1142 return sdebug_store_sectors;
1143}
1144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145#define SDEBUG_READCAP_ARR_SZ 8
1146static int resp_readcap(struct scsi_cmnd * scp,
1147 struct sdebug_dev_info * devip)
1148{
1149 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001150 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 int errsts;
1152
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001153 errsts = check_readiness(scp, UAS_ONLY, devip);
1154 if (errsts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001156 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001157 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001159 if (sdebug_capacity < 0xffffffff) {
1160 capac = (unsigned int)sdebug_capacity - 1;
1161 arr[0] = (capac >> 24);
1162 arr[1] = (capac >> 16) & 0xff;
1163 arr[2] = (capac >> 8) & 0xff;
1164 arr[3] = capac & 0xff;
1165 } else {
1166 arr[0] = 0xff;
1167 arr[1] = 0xff;
1168 arr[2] = 0xff;
1169 arr[3] = 0xff;
1170 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001171 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1172 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1174}
1175
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001176#define SDEBUG_READCAP16_ARR_SZ 32
1177static int resp_readcap16(struct scsi_cmnd * scp,
1178 struct sdebug_dev_info * devip)
1179{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001180 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001181 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1182 unsigned long long capac;
1183 int errsts, k, alloc_len;
1184
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001185 errsts = check_readiness(scp, UAS_ONLY, devip);
1186 if (errsts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001187 return errsts;
1188 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1189 + cmd[13]);
1190 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001191 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001192 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1193 capac = sdebug_capacity - 1;
1194 for (k = 0; k < 8; ++k, capac >>= 8)
1195 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001196 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1197 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1198 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1199 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001200 arr[13] = scsi_debug_physblk_exp & 0xf;
1201 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001202
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001203 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001204 arr[14] |= 0x80; /* LBPME */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001205 if (scsi_debug_lbprz)
1206 arr[14] |= 0x40; /* LBPRZ */
1207 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001208
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001209 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001210
1211 if (scsi_debug_dif) {
1212 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1213 arr[12] |= 1; /* PROT_EN */
1214 }
1215
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001216 return fill_from_dev_buffer(scp, arr,
1217 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1218}
1219
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001220#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1221
1222static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1223 struct sdebug_dev_info * devip)
1224{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001225 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001226 unsigned char * arr;
1227 int host_no = devip->sdbg_host->shost->host_no;
1228 int n, ret, alen, rlen;
1229 int port_group_a, port_group_b, port_a, port_b;
1230
1231 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1232 + cmd[9]);
1233
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001234 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1235 if (! arr)
1236 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001237 /*
1238 * EVPD page 0x88 states we have two ports, one
1239 * real and a fake port with no device connected.
1240 * So we create two port groups with one port each
1241 * and set the group with port B to unavailable.
1242 */
1243 port_a = 0x1; /* relative port A */
1244 port_b = 0x2; /* relative port B */
1245 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1246 (devip->channel & 0x7f);
1247 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1248 (devip->channel & 0x7f) + 0x80;
1249
1250 /*
1251 * The asymmetric access state is cycled according to the host_id.
1252 */
1253 n = 4;
1254 if (0 == scsi_debug_vpd_use_hostno) {
1255 arr[n++] = host_no % 3; /* Asymm access state */
1256 arr[n++] = 0x0F; /* claim: all states are supported */
1257 } else {
1258 arr[n++] = 0x0; /* Active/Optimized path */
1259 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1260 }
1261 arr[n++] = (port_group_a >> 8) & 0xff;
1262 arr[n++] = port_group_a & 0xff;
1263 arr[n++] = 0; /* Reserved */
1264 arr[n++] = 0; /* Status code */
1265 arr[n++] = 0; /* Vendor unique */
1266 arr[n++] = 0x1; /* One port per group */
1267 arr[n++] = 0; /* Reserved */
1268 arr[n++] = 0; /* Reserved */
1269 arr[n++] = (port_a >> 8) & 0xff;
1270 arr[n++] = port_a & 0xff;
1271 arr[n++] = 3; /* Port unavailable */
1272 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1273 arr[n++] = (port_group_b >> 8) & 0xff;
1274 arr[n++] = port_group_b & 0xff;
1275 arr[n++] = 0; /* Reserved */
1276 arr[n++] = 0; /* Status code */
1277 arr[n++] = 0; /* Vendor unique */
1278 arr[n++] = 0x1; /* One port per group */
1279 arr[n++] = 0; /* Reserved */
1280 arr[n++] = 0; /* Reserved */
1281 arr[n++] = (port_b >> 8) & 0xff;
1282 arr[n++] = port_b & 0xff;
1283
1284 rlen = n - 4;
1285 arr[0] = (rlen >> 24) & 0xff;
1286 arr[1] = (rlen >> 16) & 0xff;
1287 arr[2] = (rlen >> 8) & 0xff;
1288 arr[3] = rlen & 0xff;
1289
1290 /*
1291 * Return the smallest value of either
1292 * - The allocated length
1293 * - The constructed command length
1294 * - The maximum array size
1295 */
1296 rlen = min(alen,n);
1297 ret = fill_from_dev_buffer(scp, arr,
1298 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1299 kfree(arr);
1300 return ret;
1301}
1302
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303/* <<Following mode page info copied from ST318451LW>> */
1304
1305static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1306{ /* Read-Write Error Recovery page for mode_sense */
1307 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1308 5, 0, 0xff, 0xff};
1309
1310 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1311 if (1 == pcontrol)
1312 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1313 return sizeof(err_recov_pg);
1314}
1315
1316static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1317{ /* Disconnect-Reconnect page for mode_sense */
1318 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1319 0, 0, 0, 0, 0, 0, 0, 0};
1320
1321 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1322 if (1 == pcontrol)
1323 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1324 return sizeof(disconnect_pg);
1325}
1326
1327static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1328{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001329 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1330 0, 0, 0, 0, 0, 0, 0, 0,
1331 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Martin K. Petersen597136a2008-06-05 00:12:59 -04001333 memcpy(p, format_pg, sizeof(format_pg));
1334 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1335 p[11] = sdebug_sectors_per & 0xff;
1336 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1337 p[13] = scsi_debug_sector_size & 0xff;
Martin Pittd9867882012-09-06 12:04:33 +02001338 if (scsi_debug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001339 p[20] |= 0x20; /* should agree with INQUIRY */
1340 if (1 == pcontrol)
1341 memset(p + 2, 0, sizeof(format_pg) - 2);
1342 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343}
1344
1345static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1346{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001347 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1349 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1351
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001352 if (SCSI_DEBUG_OPT_N_WCE & scsi_debug_opts)
1353 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 memcpy(p, caching_pg, sizeof(caching_pg));
1355 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001356 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1357 else if (2 == pcontrol)
1358 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 return sizeof(caching_pg);
1360}
1361
1362static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1363{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001364 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1365 0, 0, 0, 0};
1366 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 0, 0, 0x2, 0x4b};
1368
1369 if (scsi_debug_dsense)
1370 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001371 else
1372 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001373
1374 if (scsi_debug_ato)
1375 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1378 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001379 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1380 else if (2 == pcontrol)
1381 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 return sizeof(ctrl_m_pg);
1383}
1384
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1387{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001388 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1389 0, 0, 0x0, 0x0};
1390 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1391 0, 0, 0x0, 0x0};
1392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1394 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001395 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1396 else if (2 == pcontrol)
1397 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 return sizeof(iec_m_pg);
1399}
1400
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001401static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1402{ /* SAS SSP mode page - short format for mode_sense */
1403 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1404 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1405
1406 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1407 if (1 == pcontrol)
1408 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1409 return sizeof(sas_sf_m_pg);
1410}
1411
1412
1413static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1414 int target_dev_id)
1415{ /* SAS phy control and discover mode page for mode_sense */
1416 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1417 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1418 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1419 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1420 0x2, 0, 0, 0, 0, 0, 0, 0,
1421 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1422 0, 0, 0, 0, 0, 0, 0, 0,
1423 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1424 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1425 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1426 0x3, 0, 0, 0, 0, 0, 0, 0,
1427 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1428 0, 0, 0, 0, 0, 0, 0, 0,
1429 };
1430 int port_a, port_b;
1431
1432 port_a = target_dev_id + 1;
1433 port_b = port_a + 1;
1434 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1435 p[20] = (port_a >> 24);
1436 p[21] = (port_a >> 16) & 0xff;
1437 p[22] = (port_a >> 8) & 0xff;
1438 p[23] = port_a & 0xff;
1439 p[48 + 20] = (port_b >> 24);
1440 p[48 + 21] = (port_b >> 16) & 0xff;
1441 p[48 + 22] = (port_b >> 8) & 0xff;
1442 p[48 + 23] = port_b & 0xff;
1443 if (1 == pcontrol)
1444 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1445 return sizeof(sas_pcd_m_pg);
1446}
1447
1448static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1449{ /* SAS SSP shared protocol specific port mode subpage */
1450 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1451 0, 0, 0, 0, 0, 0, 0, 0,
1452 };
1453
1454 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1455 if (1 == pcontrol)
1456 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1457 return sizeof(sas_sha_m_pg);
1458}
1459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460#define SDEBUG_MAX_MSENSE_SZ 256
1461
1462static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1463 struct sdebug_dev_info * devip)
1464{
Douglas Gilbert23183912006-09-16 20:30:47 -04001465 unsigned char dbd, llbaa;
1466 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001468 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 unsigned char * ap;
1470 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001471 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001473 errsts = check_readiness(scp, UAS_ONLY, devip);
1474 if (errsts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001476 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 pcontrol = (cmd[2] & 0xc0) >> 6;
1478 pcode = cmd[2] & 0x3f;
1479 subpcode = cmd[3];
1480 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001481 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1482 if ((0 == scsi_debug_ptype) && (0 == dbd))
1483 bd_len = llbaa ? 16 : 8;
1484 else
1485 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1487 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1488 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001489 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 return check_condition_result;
1491 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001492 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1493 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001494 /* set DPOFUA bit for disks */
1495 if (0 == scsi_debug_ptype)
1496 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1497 else
1498 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 if (msense_6) {
1500 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001501 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 offset = 4;
1503 } else {
1504 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001505 if (16 == bd_len)
1506 arr[4] = 0x1; /* set LONGLBA bit */
1507 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 offset = 8;
1509 }
1510 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001511 if ((bd_len > 0) && (!sdebug_capacity))
1512 sdebug_capacity = get_sdebug_capacity();
1513
Douglas Gilbert23183912006-09-16 20:30:47 -04001514 if (8 == bd_len) {
1515 if (sdebug_capacity > 0xfffffffe) {
1516 ap[0] = 0xff;
1517 ap[1] = 0xff;
1518 ap[2] = 0xff;
1519 ap[3] = 0xff;
1520 } else {
1521 ap[0] = (sdebug_capacity >> 24) & 0xff;
1522 ap[1] = (sdebug_capacity >> 16) & 0xff;
1523 ap[2] = (sdebug_capacity >> 8) & 0xff;
1524 ap[3] = sdebug_capacity & 0xff;
1525 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001526 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1527 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001528 offset += bd_len;
1529 ap = arr + offset;
1530 } else if (16 == bd_len) {
1531 unsigned long long capac = sdebug_capacity;
1532
1533 for (k = 0; k < 8; ++k, capac >>= 8)
1534 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001535 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1536 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1537 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1538 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001539 offset += bd_len;
1540 ap = arr + offset;
1541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1544 /* TODO: Control Extension page */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001545 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 0);
1547 return check_condition_result;
1548 }
1549 switch (pcode) {
1550 case 0x1: /* Read-Write error recovery page, direct access */
1551 len = resp_err_recov_pg(ap, pcontrol, target);
1552 offset += len;
1553 break;
1554 case 0x2: /* Disconnect-Reconnect page, all devices */
1555 len = resp_disconnect_pg(ap, pcontrol, target);
1556 offset += len;
1557 break;
1558 case 0x3: /* Format device page, direct access */
1559 len = resp_format_pg(ap, pcontrol, target);
1560 offset += len;
1561 break;
1562 case 0x8: /* Caching page, direct access */
1563 len = resp_caching_pg(ap, pcontrol, target);
1564 offset += len;
1565 break;
1566 case 0xa: /* Control Mode page, all devices */
1567 len = resp_ctrl_m_pg(ap, pcontrol, target);
1568 offset += len;
1569 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001570 case 0x19: /* if spc==1 then sas phy, control+discover */
1571 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001572 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001573 INVALID_FIELD_IN_CDB, 0);
1574 return check_condition_result;
1575 }
1576 len = 0;
1577 if ((0x0 == subpcode) || (0xff == subpcode))
1578 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1579 if ((0x1 == subpcode) || (0xff == subpcode))
1580 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1581 target_dev_id);
1582 if ((0x2 == subpcode) || (0xff == subpcode))
1583 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1584 offset += len;
1585 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 case 0x1c: /* Informational Exceptions Mode page, all devices */
1587 len = resp_iec_m_pg(ap, pcontrol, target);
1588 offset += len;
1589 break;
1590 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001591 if ((0 == subpcode) || (0xff == subpcode)) {
1592 len = resp_err_recov_pg(ap, pcontrol, target);
1593 len += resp_disconnect_pg(ap + len, pcontrol, target);
1594 len += resp_format_pg(ap + len, pcontrol, target);
1595 len += resp_caching_pg(ap + len, pcontrol, target);
1596 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1597 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1598 if (0xff == subpcode) {
1599 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1600 target, target_dev_id);
1601 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1602 }
1603 len += resp_iec_m_pg(ap + len, pcontrol, target);
1604 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001605 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001606 INVALID_FIELD_IN_CDB, 0);
1607 return check_condition_result;
1608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 offset += len;
1610 break;
1611 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001612 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 0);
1614 return check_condition_result;
1615 }
1616 if (msense_6)
1617 arr[0] = offset - 1;
1618 else {
1619 arr[0] = ((offset - 2) >> 8) & 0xff;
1620 arr[1] = (offset - 2) & 0xff;
1621 }
1622 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1623}
1624
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001625#define SDEBUG_MAX_MSELECT_SZ 512
1626
1627static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1628 struct sdebug_dev_info * devip)
1629{
1630 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1631 int param_len, res, errsts, mpage;
1632 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001633 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001634
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001635 errsts = check_readiness(scp, UAS_ONLY, devip);
1636 if (errsts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001637 return errsts;
1638 memset(arr, 0, sizeof(arr));
1639 pf = cmd[1] & 0x10;
1640 sp = cmd[1] & 0x1;
1641 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1642 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001643 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001644 INVALID_FIELD_IN_CDB, 0);
1645 return check_condition_result;
1646 }
1647 res = fetch_to_dev_buffer(scp, arr, param_len);
1648 if (-1 == res)
1649 return (DID_ERROR << 16);
1650 else if ((res < param_len) &&
1651 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001652 sdev_printk(KERN_INFO, scp->device,
1653 "%s: cdb indicated=%d, IO sent=%d bytes\n",
1654 __func__, param_len, res);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001655 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1656 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001657 if (md_len > 2) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001658 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001659 INVALID_FIELD_IN_PARAM_LIST, 0);
1660 return check_condition_result;
1661 }
1662 off = bd_len + (mselect6 ? 4 : 8);
1663 mpage = arr[off] & 0x3f;
1664 ps = !!(arr[off] & 0x80);
1665 if (ps) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001666 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001667 INVALID_FIELD_IN_PARAM_LIST, 0);
1668 return check_condition_result;
1669 }
1670 spf = !!(arr[off] & 0x40);
1671 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1672 (arr[off + 1] + 2);
1673 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001674 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001675 PARAMETER_LIST_LENGTH_ERR, 0);
1676 return check_condition_result;
1677 }
1678 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001679 case 0x8: /* Caching Mode page */
1680 if (caching_pg[1] == arr[off + 1]) {
1681 memcpy(caching_pg + 2, arr + off + 2,
1682 sizeof(caching_pg) - 2);
1683 goto set_mode_changed_ua;
1684 }
1685 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001686 case 0xa: /* Control Mode page */
1687 if (ctrl_m_pg[1] == arr[off + 1]) {
1688 memcpy(ctrl_m_pg + 2, arr + off + 2,
1689 sizeof(ctrl_m_pg) - 2);
1690 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001691 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001692 }
1693 break;
1694 case 0x1c: /* Informational Exceptions Mode page */
1695 if (iec_m_pg[1] == arr[off + 1]) {
1696 memcpy(iec_m_pg + 2, arr + off + 2,
1697 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001698 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001699 }
1700 break;
1701 default:
1702 break;
1703 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001704 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001705 INVALID_FIELD_IN_PARAM_LIST, 0);
1706 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001707set_mode_changed_ua:
1708 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
1709 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001710}
1711
1712static int resp_temp_l_pg(unsigned char * arr)
1713{
1714 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1715 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1716 };
1717
1718 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1719 return sizeof(temp_l_pg);
1720}
1721
1722static int resp_ie_l_pg(unsigned char * arr)
1723{
1724 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1725 };
1726
1727 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1728 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1729 arr[4] = THRESHOLD_EXCEEDED;
1730 arr[5] = 0xff;
1731 }
1732 return sizeof(ie_l_pg);
1733}
1734
1735#define SDEBUG_MAX_LSENSE_SZ 512
1736
1737static int resp_log_sense(struct scsi_cmnd * scp,
1738 struct sdebug_dev_info * devip)
1739{
Douglas Gilbert23183912006-09-16 20:30:47 -04001740 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001741 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001742 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001743
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001744 errsts = check_readiness(scp, UAS_ONLY, devip);
1745 if (errsts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001746 return errsts;
1747 memset(arr, 0, sizeof(arr));
1748 ppc = cmd[1] & 0x2;
1749 sp = cmd[1] & 0x1;
1750 if (ppc || sp) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001751 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001752 INVALID_FIELD_IN_CDB, 0);
1753 return check_condition_result;
1754 }
1755 pcontrol = (cmd[2] & 0xc0) >> 6;
1756 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001757 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001758 alloc_len = (cmd[7] << 8) + cmd[8];
1759 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001760 if (0 == subpcode) {
1761 switch (pcode) {
1762 case 0x0: /* Supported log pages log page */
1763 n = 4;
1764 arr[n++] = 0x0; /* this page */
1765 arr[n++] = 0xd; /* Temperature */
1766 arr[n++] = 0x2f; /* Informational exceptions */
1767 arr[3] = n - 4;
1768 break;
1769 case 0xd: /* Temperature log page */
1770 arr[3] = resp_temp_l_pg(arr + 4);
1771 break;
1772 case 0x2f: /* Informational exceptions log page */
1773 arr[3] = resp_ie_l_pg(arr + 4);
1774 break;
1775 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001776 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbert23183912006-09-16 20:30:47 -04001777 INVALID_FIELD_IN_CDB, 0);
1778 return check_condition_result;
1779 }
1780 } else if (0xff == subpcode) {
1781 arr[0] |= 0x40;
1782 arr[1] = subpcode;
1783 switch (pcode) {
1784 case 0x0: /* Supported log pages and subpages log page */
1785 n = 4;
1786 arr[n++] = 0x0;
1787 arr[n++] = 0x0; /* 0,0 page */
1788 arr[n++] = 0x0;
1789 arr[n++] = 0xff; /* this page */
1790 arr[n++] = 0xd;
1791 arr[n++] = 0x0; /* Temperature */
1792 arr[n++] = 0x2f;
1793 arr[n++] = 0x0; /* Informational exceptions */
1794 arr[3] = n - 4;
1795 break;
1796 case 0xd: /* Temperature subpages */
1797 n = 4;
1798 arr[n++] = 0xd;
1799 arr[n++] = 0x0; /* Temperature */
1800 arr[3] = n - 4;
1801 break;
1802 case 0x2f: /* Informational exceptions subpages */
1803 n = 4;
1804 arr[n++] = 0x2f;
1805 arr[n++] = 0x0; /* Informational exceptions */
1806 arr[3] = n - 4;
1807 break;
1808 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001809 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbert23183912006-09-16 20:30:47 -04001810 INVALID_FIELD_IN_CDB, 0);
1811 return check_condition_result;
1812 }
1813 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001814 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001815 INVALID_FIELD_IN_CDB, 0);
1816 return check_condition_result;
1817 }
1818 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1819 return fill_from_dev_buffer(scp, arr,
1820 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1821}
1822
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001823static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09001824 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001826 if (lba + num > sdebug_capacity) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001827 mk_sense_buffer(scp, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 return check_condition_result;
1829 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001830 /* transfer length excessive (tie in to block limits VPD page) */
1831 if (num > sdebug_store_sectors) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001832 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001833 return check_condition_result;
1834 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001835 return 0;
1836}
1837
Akinobu Mitaa4517512013-07-08 16:01:57 -07001838/* Returns number of bytes copied or -1 if error. */
FUJITA Tomonori19789102008-03-30 00:59:56 +09001839static int do_device_access(struct scsi_cmnd *scmd,
FUJITA Tomonori19789102008-03-30 00:59:56 +09001840 unsigned long long lba, unsigned int num, int write)
1841{
1842 int ret;
Darrick J. Wonga361cc02011-01-31 18:47:54 -08001843 unsigned long long block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07001844 struct scsi_data_buffer *sdb;
1845 enum dma_data_direction dir;
1846 size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
1847 off_t);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001848
Akinobu Mitaa4517512013-07-08 16:01:57 -07001849 if (write) {
1850 sdb = scsi_out(scmd);
1851 dir = DMA_TO_DEVICE;
1852 func = sg_pcopy_to_buffer;
1853 } else {
1854 sdb = scsi_in(scmd);
1855 dir = DMA_FROM_DEVICE;
1856 func = sg_pcopy_from_buffer;
1857 }
1858
1859 if (!sdb->length)
1860 return 0;
1861 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
1862 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001863
1864 block = do_div(lba, sdebug_store_sectors);
1865 if (block + num > sdebug_store_sectors)
1866 rest = block + num - sdebug_store_sectors;
1867
Akinobu Mitaa4517512013-07-08 16:01:57 -07001868 ret = func(sdb->table.sgl, sdb->table.nents,
1869 fake_storep + (block * scsi_debug_sector_size),
1870 (num - rest) * scsi_debug_sector_size, 0);
1871 if (ret != (num - rest) * scsi_debug_sector_size)
1872 return ret;
1873
1874 if (rest) {
1875 ret += func(sdb->table.sgl, sdb->table.nents,
1876 fake_storep, rest * scsi_debug_sector_size,
1877 (num - rest) * scsi_debug_sector_size);
1878 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001879
1880 return ret;
1881}
1882
Akinobu Mita51d648a2013-09-18 21:27:28 +09001883static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001884{
Akinobu Mita51d648a2013-09-18 21:27:28 +09001885 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001886
Akinobu Mita51d648a2013-09-18 21:27:28 +09001887 if (scsi_debug_guard)
1888 csum = (__force __be16)ip_compute_csum(buf, len);
1889 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001890 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09001891
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001892 return csum;
1893}
1894
1895static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
1896 sector_t sector, u32 ei_lba)
1897{
Akinobu Mita51d648a2013-09-18 21:27:28 +09001898 __be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001899
1900 if (sdt->guard_tag != csum) {
1901 pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
1902 __func__,
1903 (unsigned long)sector,
1904 be16_to_cpu(sdt->guard_tag),
1905 be16_to_cpu(csum));
1906 return 0x01;
1907 }
1908 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1909 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
1910 pr_err("%s: REF check failed on sector %lu\n",
1911 __func__, (unsigned long)sector);
1912 return 0x03;
1913 }
1914 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1915 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1916 pr_err("%s: REF check failed on sector %lu\n",
1917 __func__, (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001918 return 0x03;
1919 }
1920 return 0;
1921}
1922
Akinobu Mitabb8c0632013-09-18 21:27:25 +09001923static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09001924 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001925{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001926 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001927 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09001928 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001929 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001930
Akinobu Mitae18d8be2013-06-29 17:59:18 +09001931 /* Bytes of protection data to copy into sgl */
1932 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001933
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001934 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
1935 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
1936 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
1937
1938 while (sg_miter_next(&miter) && resid > 0) {
1939 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09001940 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001941 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09001942
1943 if (dif_store_end < start + len)
1944 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001945
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001946 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09001947
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09001948 if (read)
1949 memcpy(paddr, start, len - rest);
1950 else
1951 memcpy(start, paddr, len - rest);
1952
1953 if (rest) {
1954 if (read)
1955 memcpy(paddr + len - rest, dif_storep, rest);
1956 else
1957 memcpy(dif_storep, paddr + len - rest, rest);
1958 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001959
Akinobu Mitae18d8be2013-06-29 17:59:18 +09001960 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001961 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001962 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001963 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09001964}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001965
Akinobu Mitabb8c0632013-09-18 21:27:25 +09001966static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1967 unsigned int sectors, u32 ei_lba)
1968{
1969 unsigned int i;
1970 struct sd_dif_tuple *sdt;
1971 sector_t sector;
1972
Akinobu Mitac45eabec2014-02-26 22:56:58 +09001973 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09001974 int ret;
1975
1976 sector = start_sec + i;
1977 sdt = dif_store(sector);
1978
Akinobu Mita51d648a2013-09-18 21:27:28 +09001979 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09001980 continue;
1981
1982 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
1983 if (ret) {
1984 dif_errors++;
1985 return ret;
1986 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09001987 }
1988
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09001989 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001990 dix_reads++;
1991
1992 return 0;
1993}
1994
FUJITA Tomonori19789102008-03-30 00:59:56 +09001995static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001996 unsigned int num, u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001997{
1998 unsigned long iflags;
1999 int ret;
2000
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002001 ret = check_device_access_params(SCpnt, lba, num);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002002 if (ret)
2003 return ret;
2004
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002006 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002007 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2008 /* claim unrecoverable read error */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002009 mk_sense_buffer(SCpnt, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002010 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002011 if (0x70 == (SCpnt->sense_buffer[0] & 0x7f)) {
2012 SCpnt->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002013 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2014 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002015 SCpnt->sense_buffer[3] = (ret >> 24) & 0xff;
2016 SCpnt->sense_buffer[4] = (ret >> 16) & 0xff;
2017 SCpnt->sense_buffer[5] = (ret >> 8) & 0xff;
2018 SCpnt->sense_buffer[6] = ret & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002019 }
Douglas Gilberta87e3a62010-12-17 19:16:06 -05002020 scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 return check_condition_result;
2022 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002023
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002024 read_lock_irqsave(&atomic_rw, iflags);
2025
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002026 /* DIX + T10 DIF */
2027 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002028 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002029
2030 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002031 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002032 mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002033 return illegal_condition_result;
2034 }
2035 }
2036
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002037 ret = do_device_access(SCpnt, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 read_unlock_irqrestore(&atomic_rw, iflags);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002039 if (ret == -1)
2040 return DID_ERROR << 16;
2041
2042 scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret;
2043
2044 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045}
2046
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002047void dump_sector(unsigned char *buf, int len)
2048{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002049 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002050
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002051 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002052 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002053 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002054
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002055 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002056 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002057
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002058 if (c >= 0x20 && c < 0x7e)
2059 n += scnprintf(b + n, sizeof(b) - n,
2060 " %c ", buf[i+j]);
2061 else
2062 n += scnprintf(b + n, sizeof(b) - n,
2063 "%02x ", buf[i+j]);
2064 }
2065 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002066 }
2067}
2068
2069static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002070 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002071{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002072 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002073 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002074 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002075 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002076 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002077 int dpage_offset;
2078 struct sg_mapping_iter diter;
2079 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002080
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002081 BUG_ON(scsi_sg_count(SCpnt) == 0);
2082 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2083
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002084 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2085 scsi_prot_sg_count(SCpnt),
2086 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2087 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2088 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002089
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002090 /* For each protection page */
2091 while (sg_miter_next(&piter)) {
2092 dpage_offset = 0;
2093 if (WARN_ON(!sg_miter_next(&diter))) {
2094 ret = 0x01;
2095 goto out;
2096 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002097
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002098 for (ppage_offset = 0; ppage_offset < piter.length;
2099 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002100 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002101 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002102 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002103 if (dpage_offset >= diter.length) {
2104 if (WARN_ON(!sg_miter_next(&diter))) {
2105 ret = 0x01;
2106 goto out;
2107 }
2108 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002109 }
2110
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002111 sdt = piter.addr + ppage_offset;
2112 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002113
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002114 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002115 if (ret) {
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002116 dump_sector(daddr, scsi_debug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002117 goto out;
2118 }
2119
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002120 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002121 ei_lba++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002122 dpage_offset += scsi_debug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002123 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002124 diter.consumed = dpage_offset;
2125 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002126 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002127 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002128
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002129 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002130 dix_writes++;
2131
2132 return 0;
2133
2134out:
2135 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002136 sg_miter_stop(&diter);
2137 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002138 return ret;
2139}
2140
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002141static unsigned long lba_to_map_index(sector_t lba)
2142{
2143 if (scsi_debug_unmap_alignment) {
2144 lba += scsi_debug_unmap_granularity -
2145 scsi_debug_unmap_alignment;
2146 }
2147 do_div(lba, scsi_debug_unmap_granularity);
2148
2149 return lba;
2150}
2151
2152static sector_t map_index_to_lba(unsigned long index)
2153{
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002154 sector_t lba = index * scsi_debug_unmap_granularity;
2155
2156 if (scsi_debug_unmap_alignment) {
2157 lba -= scsi_debug_unmap_granularity -
2158 scsi_debug_unmap_alignment;
2159 }
2160
2161 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002162}
2163
Martin K. Petersen44d92692009-10-15 14:45:27 -04002164static unsigned int map_state(sector_t lba, unsigned int *num)
2165{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002166 sector_t end;
2167 unsigned int mapped;
2168 unsigned long index;
2169 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002170
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002171 index = lba_to_map_index(lba);
2172 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002173
2174 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002175 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002176 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002177 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002178
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002179 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002180 *num = end - lba;
2181
2182 return mapped;
2183}
2184
2185static void map_region(sector_t lba, unsigned int len)
2186{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002187 sector_t end = lba + len;
2188
Martin K. Petersen44d92692009-10-15 14:45:27 -04002189 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002190 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002191
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002192 if (index < map_size)
2193 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002194
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002195 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002196 }
2197}
2198
2199static void unmap_region(sector_t lba, unsigned int len)
2200{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002201 sector_t end = lba + len;
2202
Martin K. Petersen44d92692009-10-15 14:45:27 -04002203 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002204 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002205
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002206 if (lba == map_index_to_lba(index) &&
2207 lba + scsi_debug_unmap_granularity <= end &&
2208 index < map_size) {
2209 clear_bit(index, map_storep);
2210 if (scsi_debug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002211 memset(fake_storep +
Akinobu Mitacc34a8e2013-04-16 22:11:57 +09002212 lba * scsi_debug_sector_size, 0,
2213 scsi_debug_sector_size *
2214 scsi_debug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002215 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002216 if (dif_storep) {
2217 memset(dif_storep + lba, 0xff,
2218 sizeof(*dif_storep) *
2219 scsi_debug_unmap_granularity);
2220 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002221 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002222 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002223 }
2224}
2225
FUJITA Tomonori19789102008-03-30 00:59:56 +09002226static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002227 unsigned int num, u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228{
2229 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002230 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002232 ret = check_device_access_params(SCpnt, lba, num);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002233 if (ret)
2234 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002236 write_lock_irqsave(&atomic_rw, iflags);
2237
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002238 /* DIX + T10 DIF */
2239 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002240 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002241
2242 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002243 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002244 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10,
2245 prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002246 return illegal_condition_result;
2247 }
2248 }
2249
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002250 ret = do_device_access(SCpnt, lba, num, 1);
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002251 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002252 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002254 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002256 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002258 sdev_printk(KERN_INFO, SCpnt->device,
2259 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2260 my_name, num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002261
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 return 0;
2263}
2264
Martin K. Petersen44d92692009-10-15 14:45:27 -04002265static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002266 unsigned int num, u32 ei_lba, unsigned int unmap)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002267{
2268 unsigned long iflags;
2269 unsigned long long i;
2270 int ret;
2271
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002272 ret = check_device_access_params(scmd, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002273 if (ret)
2274 return ret;
2275
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002276 if (num > scsi_debug_write_same_length) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002277 mk_sense_buffer(scmd, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002278 0);
2279 return check_condition_result;
2280 }
2281
Martin K. Petersen44d92692009-10-15 14:45:27 -04002282 write_lock_irqsave(&atomic_rw, iflags);
2283
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002284 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002285 unmap_region(lba, num);
2286 goto out;
2287 }
2288
2289 /* Else fetch one logical block */
2290 ret = fetch_to_dev_buffer(scmd,
2291 fake_storep + (lba * scsi_debug_sector_size),
2292 scsi_debug_sector_size);
2293
2294 if (-1 == ret) {
2295 write_unlock_irqrestore(&atomic_rw, iflags);
2296 return (DID_ERROR << 16);
2297 } else if ((ret < (num * scsi_debug_sector_size)) &&
2298 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002299 sdev_printk(KERN_INFO, scmd->device,
2300 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2301 my_name, "write same",
2302 num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002303
2304 /* Copy first sector to remaining blocks */
2305 for (i = 1 ; i < num ; i++)
2306 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2307 fake_storep + (lba * scsi_debug_sector_size),
2308 scsi_debug_sector_size);
2309
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002310 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002311 map_region(lba, num);
2312out:
2313 write_unlock_irqrestore(&atomic_rw, iflags);
2314
2315 return 0;
2316}
2317
2318struct unmap_block_desc {
2319 __be64 lba;
2320 __be32 blocks;
2321 __be32 __reserved;
2322};
2323
2324static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2325{
2326 unsigned char *buf;
2327 struct unmap_block_desc *desc;
2328 unsigned int i, payload_len, descriptors;
2329 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002330 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002331
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002332 ret = check_readiness(scmd, UAS_ONLY, devip);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002333 if (ret)
2334 return ret;
2335
2336 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2337 BUG_ON(scsi_bufflen(scmd) != payload_len);
2338
2339 descriptors = (payload_len - 8) / 16;
2340
2341 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2342 if (!buf)
2343 return check_condition_result;
2344
2345 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2346
2347 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2348 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2349
2350 desc = (void *)&buf[8];
2351
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002352 write_lock_irqsave(&atomic_rw, iflags);
2353
Martin K. Petersen44d92692009-10-15 14:45:27 -04002354 for (i = 0 ; i < descriptors ; i++) {
2355 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2356 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2357
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002358 ret = check_device_access_params(scmd, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002359 if (ret)
2360 goto out;
2361
2362 unmap_region(lba, num);
2363 }
2364
2365 ret = 0;
2366
2367out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002368 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002369 kfree(buf);
2370
2371 return ret;
2372}
2373
2374#define SDEBUG_GET_LBA_STATUS_LEN 32
2375
2376static int resp_get_lba_status(struct scsi_cmnd * scmd,
2377 struct sdebug_dev_info * devip)
2378{
2379 unsigned long long lba;
2380 unsigned int alloc_len, mapped, num;
2381 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2382 int ret;
2383
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002384 ret = check_readiness(scmd, UAS_ONLY, devip);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002385 if (ret)
2386 return ret;
2387
2388 lba = get_unaligned_be64(&scmd->cmnd[2]);
2389 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2390
2391 if (alloc_len < 24)
2392 return 0;
2393
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002394 ret = check_device_access_params(scmd, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002395 if (ret)
2396 return ret;
2397
2398 mapped = map_state(lba, &num);
2399
2400 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertde13e962012-01-19 19:30:00 -05002401 put_unaligned_be32(20, &arr[0]); /* Parameter Data Length */
Martin K. Petersen44d92692009-10-15 14:45:27 -04002402 put_unaligned_be64(lba, &arr[8]); /* LBA */
2403 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2404 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2405
2406 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2407}
2408
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002409#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
2411static int resp_report_luns(struct scsi_cmnd * scp,
2412 struct sdebug_dev_info * devip)
2413{
2414 unsigned int alloc_len;
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02002415 int lun_cnt, i, upper, num, n;
2416 u64 wlun, lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002417 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 int select_report = (int)cmd[2];
2419 struct scsi_lun *one_lun;
2420 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002421 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422
2423 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002424 if ((alloc_len < 4) || (select_report > 2)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002425 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 0);
2427 return check_condition_result;
2428 }
2429 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2430 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2431 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002432 if (1 == select_report)
2433 lun_cnt = 0;
2434 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2435 --lun_cnt;
2436 wlun = (select_report > 0) ? 1 : 0;
2437 num = lun_cnt + wlun;
2438 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2439 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2440 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2441 sizeof(struct scsi_lun)), num);
2442 if (n < num) {
2443 wlun = 0;
2444 lun_cnt = n;
2445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002447 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2448 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2449 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2450 i++, lun++) {
2451 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 if (upper)
2453 one_lun[i].scsi_lun[0] =
2454 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002455 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002457 if (wlun) {
2458 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2459 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2460 i++;
2461 }
2462 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 return fill_from_dev_buffer(scp, arr,
2464 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2465}
2466
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002467static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2468 unsigned int num, struct sdebug_dev_info *devip)
2469{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002470 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002471 unsigned char *kaddr, *buf;
2472 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002473 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002474 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002475
2476 /* better not to use temporary buffer. */
2477 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09002478 if (!buf) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002479 mk_sense_buffer(scp, NOT_READY,
Akinobu Mitac5af0db2014-02-26 22:57:01 +09002480 LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
2481 return check_condition_result;
2482 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002483
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002484 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002485
2486 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002487 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
2488 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002489
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002490 while (sg_miter_next(&miter)) {
2491 kaddr = miter.addr;
2492 for (j = 0; j < miter.length; j++)
2493 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002494
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002495 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002496 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002497 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002498 kfree(buf);
2499
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002500 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002501}
2502
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002503/* When timer or tasklet goes off this function is called. */
2504static void sdebug_q_cmd_complete(unsigned long indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002506 int qa_indx;
2507 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002509 struct sdebug_queued_cmd *sqcp;
2510 struct scsi_cmnd *scp;
2511 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002513 atomic_inc(&sdebug_completions);
2514 qa_indx = indx;
2515 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
2516 pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 return;
2518 }
2519 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002520 sqcp = &queued_arr[qa_indx];
2521 scp = sqcp->a_cmnd;
2522 if (NULL == scp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002524 pr_err("%s: scp is NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 return;
2526 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002527 devip = (struct sdebug_dev_info *)scp->device->hostdata;
2528 if (devip)
2529 atomic_dec(&devip->num_in_q);
2530 else
2531 pr_err("%s: devip=NULL\n", __func__);
2532 if (atomic_read(&retired_max_queue) > 0)
2533 retiring = 1;
2534
2535 sqcp->a_cmnd = NULL;
2536 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
2537 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2538 pr_err("%s: Unexpected completion\n", __func__);
2539 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002541
2542 if (unlikely(retiring)) { /* user has reduced max_queue */
2543 int k, retval;
2544
2545 retval = atomic_read(&retired_max_queue);
2546 if (qa_indx >= retval) {
2547 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2548 pr_err("%s: index %d too large\n", __func__, retval);
2549 return;
2550 }
2551 k = find_last_bit(queued_in_use_bm, retval);
2552 if ((k < scsi_debug_max_queue) || (k == retval))
2553 atomic_set(&retired_max_queue, 0);
2554 else
2555 atomic_set(&retired_max_queue, k + 1);
2556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002558 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559}
2560
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002561/* When high resolution timer goes off this function is called. */
2562static enum hrtimer_restart
2563sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
2564{
2565 int qa_indx;
2566 int retiring = 0;
2567 unsigned long iflags;
2568 struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
2569 struct sdebug_queued_cmd *sqcp;
2570 struct scsi_cmnd *scp;
2571 struct sdebug_dev_info *devip;
2572
2573 atomic_inc(&sdebug_completions);
2574 qa_indx = sd_hrtp->qa_indx;
2575 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
2576 pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
2577 goto the_end;
2578 }
2579 spin_lock_irqsave(&queued_arr_lock, iflags);
2580 sqcp = &queued_arr[qa_indx];
2581 scp = sqcp->a_cmnd;
2582 if (NULL == scp) {
2583 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2584 pr_err("%s: scp is NULL\n", __func__);
2585 goto the_end;
2586 }
2587 devip = (struct sdebug_dev_info *)scp->device->hostdata;
2588 if (devip)
2589 atomic_dec(&devip->num_in_q);
2590 else
2591 pr_err("%s: devip=NULL\n", __func__);
2592 if (atomic_read(&retired_max_queue) > 0)
2593 retiring = 1;
2594
2595 sqcp->a_cmnd = NULL;
2596 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
2597 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2598 pr_err("%s: Unexpected completion\n", __func__);
2599 goto the_end;
2600 }
2601
2602 if (unlikely(retiring)) { /* user has reduced max_queue */
2603 int k, retval;
2604
2605 retval = atomic_read(&retired_max_queue);
2606 if (qa_indx >= retval) {
2607 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2608 pr_err("%s: index %d too large\n", __func__, retval);
2609 goto the_end;
2610 }
2611 k = find_last_bit(queued_in_use_bm, retval);
2612 if ((k < scsi_debug_max_queue) || (k == retval))
2613 atomic_set(&retired_max_queue, 0);
2614 else
2615 atomic_set(&retired_max_queue, k + 1);
2616 }
2617 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2618 scp->scsi_done(scp); /* callback to mid level */
2619the_end:
2620 return HRTIMER_NORESTART;
2621}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002623static struct sdebug_dev_info *
2624sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002625{
2626 struct sdebug_dev_info *devip;
2627
2628 devip = kzalloc(sizeof(*devip), flags);
2629 if (devip) {
2630 devip->sdbg_host = sdbg_host;
2631 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2632 }
2633 return devip;
2634}
2635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2637{
2638 struct sdebug_host_info * sdbg_host;
2639 struct sdebug_dev_info * open_devip = NULL;
2640 struct sdebug_dev_info * devip =
2641 (struct sdebug_dev_info *)sdev->hostdata;
2642
2643 if (devip)
2644 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002645 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2646 if (!sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002647 pr_err("%s: Host info NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 return NULL;
2649 }
2650 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2651 if ((devip->used) && (devip->channel == sdev->channel) &&
2652 (devip->target == sdev->id) &&
2653 (devip->lun == sdev->lun))
2654 return devip;
2655 else {
2656 if ((!devip->used) && (!open_devip))
2657 open_devip = devip;
2658 }
2659 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002660 if (!open_devip) { /* try and make a new one */
2661 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2662 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002664 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 return NULL;
2666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002668
2669 open_devip->channel = sdev->channel;
2670 open_devip->target = sdev->id;
2671 open_devip->lun = sdev->lun;
2672 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002673 atomic_set(&open_devip->num_in_q, 0);
2674 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002675 open_devip->used = 1;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002676 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2677 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2678
2679 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680}
2681
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002682static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002684 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02002685 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002686 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002687 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002688 return 0;
2689}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002691static int scsi_debug_slave_configure(struct scsi_device *sdp)
2692{
2693 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002694
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02002696 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002697 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2698 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2699 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2700 devip = devInfoReg(sdp);
2701 if (NULL == devip)
2702 return 1; /* no resources, will be marked offline */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002703 sdp->tagged_supported = 1;
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01002704 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09002705 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002706 if (scsi_debug_no_uld)
2707 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002708 return 0;
2709}
2710
2711static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2712{
2713 struct sdebug_dev_info *devip =
2714 (struct sdebug_dev_info *)sdp->hostdata;
2715
2716 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02002717 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002718 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2719 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002720 /* make this slot available for re-use */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002721 devip->used = 0;
2722 sdp->hostdata = NULL;
2723 }
2724}
2725
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002726/* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002727static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2728{
2729 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002730 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002731 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002732 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002733
2734 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002735 qmax = scsi_debug_max_queue;
2736 r_qmax = atomic_read(&retired_max_queue);
2737 if (r_qmax > qmax)
2738 qmax = r_qmax;
2739 for (k = 0; k < qmax; ++k) {
2740 if (test_bit(k, queued_in_use_bm)) {
2741 sqcp = &queued_arr[k];
2742 if (cmnd == sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002743 devip = (struct sdebug_dev_info *)
2744 cmnd->device->hostdata;
2745 if (devip)
2746 atomic_dec(&devip->num_in_q);
2747 sqcp->a_cmnd = NULL;
2748 spin_unlock_irqrestore(&queued_arr_lock,
2749 iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002750 if (scsi_debug_ndelay > 0) {
2751 if (sqcp->sd_hrtp)
2752 hrtimer_cancel(
2753 &sqcp->sd_hrtp->hrt);
2754 } else if (scsi_debug_delay > 0) {
2755 if (sqcp->cmnd_timerp)
2756 del_timer_sync(
2757 sqcp->cmnd_timerp);
2758 } else if (scsi_debug_delay < 0) {
2759 if (sqcp->tletp)
2760 tasklet_kill(sqcp->tletp);
2761 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002762 clear_bit(k, queued_in_use_bm);
2763 return 1;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002764 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002765 }
2766 }
2767 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002768 return 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002769}
2770
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002771/* Deletes (stops) timers or tasklets of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002772static void stop_all_queued(void)
2773{
2774 unsigned long iflags;
2775 int k;
2776 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002777 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002778
2779 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002780 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2781 if (test_bit(k, queued_in_use_bm)) {
2782 sqcp = &queued_arr[k];
2783 if (sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002784 devip = (struct sdebug_dev_info *)
2785 sqcp->a_cmnd->device->hostdata;
2786 if (devip)
2787 atomic_dec(&devip->num_in_q);
2788 sqcp->a_cmnd = NULL;
2789 spin_unlock_irqrestore(&queued_arr_lock,
2790 iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002791 if (scsi_debug_ndelay > 0) {
2792 if (sqcp->sd_hrtp)
2793 hrtimer_cancel(
2794 &sqcp->sd_hrtp->hrt);
2795 } else if (scsi_debug_delay > 0) {
2796 if (sqcp->cmnd_timerp)
2797 del_timer_sync(
2798 sqcp->cmnd_timerp);
2799 } else if (scsi_debug_delay < 0) {
2800 if (sqcp->tletp)
2801 tasklet_kill(sqcp->tletp);
2802 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002803 clear_bit(k, queued_in_use_bm);
2804 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002805 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002806 }
2807 }
2808 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809}
2810
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002811/* Free queued command memory on heap */
2812static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002814 unsigned long iflags;
2815 int k;
2816 struct sdebug_queued_cmd *sqcp;
2817
2818 spin_lock_irqsave(&queued_arr_lock, iflags);
2819 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2820 sqcp = &queued_arr[k];
2821 kfree(sqcp->cmnd_timerp);
2822 sqcp->cmnd_timerp = NULL;
2823 kfree(sqcp->tletp);
2824 sqcp->tletp = NULL;
2825 kfree(sqcp->sd_hrtp);
2826 sqcp->sd_hrtp = NULL;
2827 }
2828 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829}
2830
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002831static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002833 ++num_aborts;
2834 if (SCpnt) {
2835 if (SCpnt->device &&
2836 (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
2837 sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
2838 __func__);
2839 stop_queued_cmnd(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002841 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842}
2843
2844static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2845{
2846 struct sdebug_dev_info * devip;
2847
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002849 if (SCpnt && SCpnt->device) {
2850 struct scsi_device *sdp = SCpnt->device;
2851
2852 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2853 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2854 devip = devInfoReg(sdp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002856 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 }
2858 return SUCCESS;
2859}
2860
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002861static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
2862{
2863 struct sdebug_host_info *sdbg_host;
2864 struct sdebug_dev_info *devip;
2865 struct scsi_device *sdp;
2866 struct Scsi_Host *hp;
2867 int k = 0;
2868
2869 ++num_target_resets;
2870 if (!SCpnt)
2871 goto lie;
2872 sdp = SCpnt->device;
2873 if (!sdp)
2874 goto lie;
2875 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2876 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2877 hp = sdp->host;
2878 if (!hp)
2879 goto lie;
2880 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
2881 if (sdbg_host) {
2882 list_for_each_entry(devip,
2883 &sdbg_host->dev_info_list,
2884 dev_list)
2885 if (devip->target == sdp->id) {
2886 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2887 ++k;
2888 }
2889 }
2890 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2891 sdev_printk(KERN_INFO, sdp,
2892 "%s: %d device(s) found in target\n", __func__, k);
2893lie:
2894 return SUCCESS;
2895}
2896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2898{
2899 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002900 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 struct scsi_device * sdp;
2902 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002903 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002906 if (!(SCpnt && SCpnt->device))
2907 goto lie;
2908 sdp = SCpnt->device;
2909 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2910 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2911 hp = sdp->host;
2912 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002913 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002915 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002917 dev_list) {
2918 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2919 ++k;
2920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 }
2922 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002923 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2924 sdev_printk(KERN_INFO, sdp,
2925 "%s: %d device(s) found in host\n", __func__, k);
2926lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 return SUCCESS;
2928}
2929
2930static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2931{
2932 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002933 struct sdebug_dev_info *devip;
2934 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 ++num_host_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002937 if ((SCpnt->device) && (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
2938 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 spin_lock(&sdebug_host_list_lock);
2940 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002941 list_for_each_entry(devip, &sdbg_host->dev_info_list,
2942 dev_list) {
2943 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2944 ++k;
2945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 }
2947 spin_unlock(&sdebug_host_list_lock);
2948 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002949 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2950 sdev_printk(KERN_INFO, SCpnt->device,
2951 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 return SUCCESS;
2953}
2954
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002955static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002956 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957{
2958 struct partition * pp;
2959 int starts[SDEBUG_MAX_PARTS + 2];
2960 int sectors_per_part, num_sectors, k;
2961 int heads_by_sects, start_sec, end_sec;
2962
2963 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002964 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 return;
2966 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2967 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002968 pr_warn("%s: reducing partitions to %d\n", __func__,
2969 SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002971 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 sectors_per_part = (num_sectors - sdebug_sectors_per)
2973 / scsi_debug_num_parts;
2974 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2975 starts[0] = sdebug_sectors_per;
2976 for (k = 1; k < scsi_debug_num_parts; ++k)
2977 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2978 * heads_by_sects;
2979 starts[scsi_debug_num_parts] = num_sectors;
2980 starts[scsi_debug_num_parts + 1] = 0;
2981
2982 ramp[510] = 0x55; /* magic partition markings */
2983 ramp[511] = 0xAA;
2984 pp = (struct partition *)(ramp + 0x1be);
2985 for (k = 0; starts[k + 1]; ++k, ++pp) {
2986 start_sec = starts[k];
2987 end_sec = starts[k + 1] - 1;
2988 pp->boot_ind = 0;
2989
2990 pp->cyl = start_sec / heads_by_sects;
2991 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2992 / sdebug_sectors_per;
2993 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2994
2995 pp->end_cyl = end_sec / heads_by_sects;
2996 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2997 / sdebug_sectors_per;
2998 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2999
Akinobu Mita150c3542013-08-26 22:08:40 +09003000 pp->start_sect = cpu_to_le32(start_sec);
3001 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 pp->sys_ind = 0x83; /* plain Linux partition */
3003 }
3004}
3005
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003006static int
3007schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3008 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003010 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003011 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003012 struct sdebug_queued_cmd *sqcp = NULL;
3013 struct scsi_device *sdp = cmnd->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003015 if (NULL == cmnd || NULL == devip) {
3016 pr_warn("%s: called with NULL cmnd or devip pointer\n",
3017 __func__);
3018 /* no particularly good error to report back */
3019 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003021 if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
3022 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3023 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003024 if (delta_jiff == 0)
3025 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003027 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003028 spin_lock_irqsave(&queued_arr_lock, iflags);
3029 num_in_q = atomic_read(&devip->num_in_q);
3030 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003031 inject = 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003032 if ((qdepth > 0) && (num_in_q >= qdepth)) {
3033 if (scsi_result) {
3034 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3035 goto respond_in_thread;
3036 } else
3037 scsi_result = device_qfull_result;
3038 } else if ((scsi_debug_every_nth != 0) &&
3039 (SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) &&
3040 (scsi_result == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003041 if ((num_in_q == (qdepth - 1)) &&
3042 (atomic_inc_return(&sdebug_a_tsf) >=
3043 abs(scsi_debug_every_nth))) {
3044 atomic_set(&sdebug_a_tsf, 0);
3045 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003046 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003048 }
3049
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003050 k = find_first_zero_bit(queued_in_use_bm, scsi_debug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003051 if (k >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003053 if (scsi_result)
3054 goto respond_in_thread;
3055 else if (SCSI_DEBUG_OPT_ALL_TSF & scsi_debug_opts)
3056 scsi_result = device_qfull_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003057 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts)
3058 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003059 "%s: max_queue=%d exceeded, %s\n",
3060 __func__, scsi_debug_max_queue,
3061 (scsi_result ? "status: TASK SET FULL" :
3062 "report: host busy"));
3063 if (scsi_result)
3064 goto respond_in_thread;
3065 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003066 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003068 __set_bit(k, queued_in_use_bm);
3069 atomic_inc(&devip->num_in_q);
3070 sqcp = &queued_arr[k];
3071 sqcp->a_cmnd = cmnd;
3072 cmnd->result = scsi_result;
3073 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3074 if (delta_jiff > 0) {
3075 if (NULL == sqcp->cmnd_timerp) {
3076 sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list),
3077 GFP_ATOMIC);
3078 if (NULL == sqcp->cmnd_timerp)
3079 return SCSI_MLQUEUE_HOST_BUSY;
3080 init_timer(sqcp->cmnd_timerp);
3081 }
3082 sqcp->cmnd_timerp->function = sdebug_q_cmd_complete;
3083 sqcp->cmnd_timerp->data = k;
3084 sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff;
3085 add_timer(sqcp->cmnd_timerp);
3086 } else if (scsi_debug_ndelay > 0) {
3087 ktime_t kt = ktime_set(0, scsi_debug_ndelay);
3088 struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
3089
3090 if (NULL == sd_hp) {
3091 sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC);
3092 if (NULL == sd_hp)
3093 return SCSI_MLQUEUE_HOST_BUSY;
3094 sqcp->sd_hrtp = sd_hp;
3095 hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
3096 HRTIMER_MODE_REL);
3097 sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
3098 sd_hp->qa_indx = k;
3099 }
3100 hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
3101 } else { /* delay < 0 */
3102 if (NULL == sqcp->tletp) {
3103 sqcp->tletp = kmalloc(sizeof(*sqcp->tletp),
3104 GFP_ATOMIC);
3105 if (NULL == sqcp->tletp)
3106 return SCSI_MLQUEUE_HOST_BUSY;
3107 tasklet_init(sqcp->tletp,
3108 sdebug_q_cmd_complete, k);
3109 }
3110 if (-1 == delta_jiff)
3111 tasklet_hi_schedule(sqcp->tletp);
3112 else
3113 tasklet_schedule(sqcp->tletp);
3114 }
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003115 if ((SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) &&
3116 (scsi_result == device_qfull_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003117 sdev_printk(KERN_INFO, sdp,
3118 "%s: num_in_q=%d +1, %s%s\n", __func__,
3119 num_in_q, (inject ? "<inject> " : ""),
3120 "status: TASK SET FULL");
3121 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003122
3123respond_in_thread: /* call back to mid-layer using invocation thread */
3124 cmnd->result = scsi_result;
3125 cmnd->scsi_done(cmnd);
3126 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003128
Douglas Gilbert23183912006-09-16 20:30:47 -04003129/* Note: The following macros create attribute files in the
3130 /sys/module/scsi_debug/parameters directory. Unfortunately this
3131 driver is unaware of a change and cannot trigger auxiliary actions
3132 as it can when the corresponding attribute in the
3133 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3134 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003135module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003136module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Akinobu Mita0759c662014-02-26 22:57:04 +09003137module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003138module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
3139module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003140module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
3141module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003142module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
3143module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04003144module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Akinobu Mita68aee7b2013-09-18 21:27:27 +09003145module_param_named(guard, scsi_debug_guard, uint, S_IRUGO);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003146module_param_named(host_lock, scsi_debug_host_lock, bool, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003147module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
3148module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
3149module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003150module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003151module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003152module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003153module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003154module_param_named(ndelay, scsi_debug_ndelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003155module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003156module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003157module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
3158module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003159module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003160module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003161module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003162module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
Martin Pittd9867882012-09-06 12:04:33 +02003163module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003164module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003165module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
3166module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
3167module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
3168module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
3169module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003170module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04003171module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
3172 S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003173module_param_named(write_same_length, scsi_debug_write_same_length, int,
3174 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
3176MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
3177MODULE_DESCRIPTION("SCSI debug adapter driver");
3178MODULE_LICENSE("GPL");
3179MODULE_VERSION(SCSI_DEBUG_VERSION);
3180
3181MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003182MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09003183MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003184MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003185MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003186MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
3187MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003188MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07003189MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04003190MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003191MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003192MODULE_PARM_DESC(host_lock, "use host_lock around all commands (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003193MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
3194MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
3195MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003196MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003197MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003198MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003199MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3200MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003201MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003202MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003204MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003205MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05003206MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003207MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02003209MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02003210MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003211MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003212MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
3213MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04003214MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
3215MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003216MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
3217MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
3218MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
3220static char sdebug_info[256];
3221
3222static const char * scsi_debug_info(struct Scsi_Host * shp)
3223{
3224 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
3225 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
3226 scsi_debug_version_date, scsi_debug_dev_size_mb,
3227 scsi_debug_opts);
3228 return sdebug_info;
3229}
3230
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003231/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Al Viroc8ed5552013-03-31 01:46:06 -04003232static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
Al Viroc8ed5552013-03-31 01:46:06 -04003234 char arr[16];
3235 int opts;
3236 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237
Al Viroc8ed5552013-03-31 01:46:06 -04003238 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
3239 return -EACCES;
3240 memcpy(arr, buffer, minLen);
3241 arr[minLen] = '\0';
3242 if (1 != sscanf(arr, "%d", &opts))
3243 return -EINVAL;
3244 scsi_debug_opts = opts;
3245 if (scsi_debug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003246 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04003247 return length;
3248}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003250/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
3251 * same for each scsi_debug host (if more than one). Some of the counters
3252 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04003253static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
3254{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003255 int f, l;
3256 char b[32];
3257
3258 if (scsi_debug_every_nth > 0)
3259 snprintf(b, sizeof(b), " (curr:%d)",
3260 ((SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) ?
3261 atomic_read(&sdebug_a_tsf) :
3262 atomic_read(&sdebug_cmnd_count)));
3263 else
3264 b[0] = '\0';
3265
3266 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
3267 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
3268 "every_nth=%d%s\n"
3269 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
3270 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
3271 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
3272 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
3273 "usec_in_jiffy=%lu\n",
3274 SCSI_DEBUG_VERSION, scsi_debug_version_date,
3275 scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts,
3276 scsi_debug_every_nth, b, scsi_debug_delay, scsi_debug_ndelay,
3277 scsi_debug_max_luns, atomic_read(&sdebug_completions),
3278 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
3279 sdebug_sectors_per, num_aborts, num_dev_resets,
3280 num_target_resets, num_bus_resets, num_host_resets,
3281 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
3282
3283 f = find_first_bit(queued_in_use_bm, scsi_debug_max_queue);
3284 if (f != scsi_debug_max_queue) {
3285 l = find_last_bit(queued_in_use_bm, scsi_debug_max_queue);
3286 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
3287 "queued_in_use_bm", f, l);
3288 }
Al Viroc8ed5552013-03-31 01:46:06 -04003289 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290}
3291
Akinobu Mita82069372013-10-14 22:48:04 +09003292static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293{
3294 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
3295}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003296/* Returns -EBUSY if delay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09003297static ssize_t delay_store(struct device_driver *ddp, const char *buf,
3298 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003300 int delay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003302 if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
3303 res = count;
3304 if (scsi_debug_delay != delay) {
3305 unsigned long iflags;
3306 int k;
3307
3308 spin_lock_irqsave(&queued_arr_lock, iflags);
3309 k = find_first_bit(queued_in_use_bm,
3310 scsi_debug_max_queue);
3311 if (k != scsi_debug_max_queue)
3312 res = -EBUSY; /* have queued commands */
3313 else {
3314 scsi_debug_delay = delay;
3315 scsi_debug_ndelay = 0;
3316 }
3317 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003319 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 }
3321 return -EINVAL;
3322}
Akinobu Mita82069372013-10-14 22:48:04 +09003323static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003325static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
3326{
3327 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ndelay);
3328}
3329/* Returns -EBUSY if ndelay is being changed and commands are queued */
3330/* If > 0 and accepted then scsi_debug_delay is set to DELAY_OVERRIDDEN */
3331static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
3332 size_t count)
3333{
3334 unsigned long iflags;
3335 int ndelay, res, k;
3336
3337 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
3338 (ndelay >= 0) && (ndelay < 1000000000)) {
3339 res = count;
3340 if (scsi_debug_ndelay != ndelay) {
3341 spin_lock_irqsave(&queued_arr_lock, iflags);
3342 k = find_first_bit(queued_in_use_bm,
3343 scsi_debug_max_queue);
3344 if (k != scsi_debug_max_queue)
3345 res = -EBUSY; /* have queued commands */
3346 else {
3347 scsi_debug_ndelay = ndelay;
3348 scsi_debug_delay = ndelay ? DELAY_OVERRIDDEN
3349 : DEF_DELAY;
3350 }
3351 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3352 }
3353 return res;
3354 }
3355 return -EINVAL;
3356}
3357static DRIVER_ATTR_RW(ndelay);
3358
Akinobu Mita82069372013-10-14 22:48:04 +09003359static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360{
3361 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
3362}
3363
Akinobu Mita82069372013-10-14 22:48:04 +09003364static ssize_t opts_store(struct device_driver *ddp, const char *buf,
3365 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366{
3367 int opts;
3368 char work[20];
3369
3370 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07003371 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 if (1 == sscanf(&work[2], "%x", &opts))
3373 goto opts_done;
3374 } else {
3375 if (1 == sscanf(work, "%d", &opts))
3376 goto opts_done;
3377 }
3378 }
3379 return -EINVAL;
3380opts_done:
3381 scsi_debug_opts = opts;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003382 atomic_set(&sdebug_cmnd_count, 0);
3383 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 return count;
3385}
Akinobu Mita82069372013-10-14 22:48:04 +09003386static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
Akinobu Mita82069372013-10-14 22:48:04 +09003388static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389{
3390 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
3391}
Akinobu Mita82069372013-10-14 22:48:04 +09003392static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
3393 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394{
3395 int n;
3396
3397 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3398 scsi_debug_ptype = n;
3399 return count;
3400 }
3401 return -EINVAL;
3402}
Akinobu Mita82069372013-10-14 22:48:04 +09003403static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404
Akinobu Mita82069372013-10-14 22:48:04 +09003405static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406{
3407 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
3408}
Akinobu Mita82069372013-10-14 22:48:04 +09003409static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
3410 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411{
3412 int n;
3413
3414 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3415 scsi_debug_dsense = n;
3416 return count;
3417 }
3418 return -EINVAL;
3419}
Akinobu Mita82069372013-10-14 22:48:04 +09003420static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
Akinobu Mita82069372013-10-14 22:48:04 +09003422static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04003423{
3424 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
3425}
Akinobu Mita82069372013-10-14 22:48:04 +09003426static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
3427 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04003428{
3429 int n;
3430
3431 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003432 n = (n > 0);
3433 scsi_debug_fake_rw = (scsi_debug_fake_rw > 0);
3434 if (scsi_debug_fake_rw != n) {
3435 if ((0 == n) && (NULL == fake_storep)) {
3436 unsigned long sz =
3437 (unsigned long)scsi_debug_dev_size_mb *
3438 1048576;
3439
3440 fake_storep = vmalloc(sz);
3441 if (NULL == fake_storep) {
3442 pr_err("%s: out of memory, 9\n",
3443 __func__);
3444 return -ENOMEM;
3445 }
3446 memset(fake_storep, 0, sz);
3447 }
3448 scsi_debug_fake_rw = n;
3449 }
Douglas Gilbert23183912006-09-16 20:30:47 -04003450 return count;
3451 }
3452 return -EINVAL;
3453}
Akinobu Mita82069372013-10-14 22:48:04 +09003454static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04003455
Akinobu Mita82069372013-10-14 22:48:04 +09003456static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003457{
3458 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
3459}
Akinobu Mita82069372013-10-14 22:48:04 +09003460static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
3461 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003462{
3463 int n;
3464
3465 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3466 scsi_debug_no_lun_0 = n;
3467 return count;
3468 }
3469 return -EINVAL;
3470}
Akinobu Mita82069372013-10-14 22:48:04 +09003471static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003472
Akinobu Mita82069372013-10-14 22:48:04 +09003473static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474{
3475 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
3476}
Akinobu Mita82069372013-10-14 22:48:04 +09003477static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
3478 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479{
3480 int n;
3481
3482 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3483 scsi_debug_num_tgts = n;
3484 sdebug_max_tgts_luns();
3485 return count;
3486 }
3487 return -EINVAL;
3488}
Akinobu Mita82069372013-10-14 22:48:04 +09003489static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
Akinobu Mita82069372013-10-14 22:48:04 +09003491static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492{
3493 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
3494}
Akinobu Mita82069372013-10-14 22:48:04 +09003495static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496
Akinobu Mita82069372013-10-14 22:48:04 +09003497static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498{
3499 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
3500}
Akinobu Mita82069372013-10-14 22:48:04 +09003501static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
Akinobu Mita82069372013-10-14 22:48:04 +09003503static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504{
3505 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
3506}
Akinobu Mita82069372013-10-14 22:48:04 +09003507static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
3508 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509{
3510 int nth;
3511
3512 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
3513 scsi_debug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003514 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 return count;
3516 }
3517 return -EINVAL;
3518}
Akinobu Mita82069372013-10-14 22:48:04 +09003519static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520
Akinobu Mita82069372013-10-14 22:48:04 +09003521static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522{
3523 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
3524}
Akinobu Mita82069372013-10-14 22:48:04 +09003525static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
3526 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527{
3528 int n;
3529
3530 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3531 scsi_debug_max_luns = n;
3532 sdebug_max_tgts_luns();
3533 return count;
3534 }
3535 return -EINVAL;
3536}
Akinobu Mita82069372013-10-14 22:48:04 +09003537static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538
Akinobu Mita82069372013-10-14 22:48:04 +09003539static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003540{
3541 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
3542}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003543/* N.B. max_queue can be changed while there are queued commands. In flight
3544 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09003545static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
3546 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003547{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003548 unsigned long iflags;
3549 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003550
3551 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
3552 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003553 spin_lock_irqsave(&queued_arr_lock, iflags);
3554 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003555 scsi_debug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003556 if (SCSI_DEBUG_CANQUEUE == k)
3557 atomic_set(&retired_max_queue, 0);
3558 else if (k >= n)
3559 atomic_set(&retired_max_queue, k + 1);
3560 else
3561 atomic_set(&retired_max_queue, 0);
3562 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003563 return count;
3564 }
3565 return -EINVAL;
3566}
Akinobu Mita82069372013-10-14 22:48:04 +09003567static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003568
Akinobu Mita82069372013-10-14 22:48:04 +09003569static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003570{
3571 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
3572}
Akinobu Mita82069372013-10-14 22:48:04 +09003573static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003574
Akinobu Mita82069372013-10-14 22:48:04 +09003575static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576{
3577 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
3578}
Akinobu Mita82069372013-10-14 22:48:04 +09003579static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
Akinobu Mita82069372013-10-14 22:48:04 +09003581static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003582{
3583 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3584}
Akinobu Mita82069372013-10-14 22:48:04 +09003585static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
3586 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003587{
3588 int n;
3589
3590 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3591 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003592
3593 sdebug_capacity = get_sdebug_capacity();
3594
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003595 return count;
3596 }
3597 return -EINVAL;
3598}
Akinobu Mita82069372013-10-14 22:48:04 +09003599static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003600
Akinobu Mita82069372013-10-14 22:48:04 +09003601static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602{
3603 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
3604}
3605
Akinobu Mita82069372013-10-14 22:48:04 +09003606static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
3607 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003609 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003611 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 if (delta_hosts > 0) {
3614 do {
3615 sdebug_add_adapter();
3616 } while (--delta_hosts);
3617 } else if (delta_hosts < 0) {
3618 do {
3619 sdebug_remove_adapter();
3620 } while (++delta_hosts);
3621 }
3622 return count;
3623}
Akinobu Mita82069372013-10-14 22:48:04 +09003624static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625
Akinobu Mita82069372013-10-14 22:48:04 +09003626static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04003627{
3628 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3629}
Akinobu Mita82069372013-10-14 22:48:04 +09003630static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
3631 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04003632{
3633 int n;
3634
3635 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3636 scsi_debug_vpd_use_hostno = n;
3637 return count;
3638 }
3639 return -EINVAL;
3640}
Akinobu Mita82069372013-10-14 22:48:04 +09003641static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04003642
Akinobu Mita82069372013-10-14 22:48:04 +09003643static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04003644{
3645 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3646}
Akinobu Mita82069372013-10-14 22:48:04 +09003647static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003648
Akinobu Mita82069372013-10-14 22:48:04 +09003649static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003650{
3651 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3652}
Akinobu Mita82069372013-10-14 22:48:04 +09003653static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003654
Akinobu Mita82069372013-10-14 22:48:04 +09003655static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003656{
3657 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3658}
Akinobu Mita82069372013-10-14 22:48:04 +09003659static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003660
Akinobu Mita82069372013-10-14 22:48:04 +09003661static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003662{
Akinobu Mita68aee7b2013-09-18 21:27:27 +09003663 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003664}
Akinobu Mita82069372013-10-14 22:48:04 +09003665static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003666
Akinobu Mita82069372013-10-14 22:48:04 +09003667static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003668{
3669 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3670}
Akinobu Mita82069372013-10-14 22:48:04 +09003671static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003672
Akinobu Mita82069372013-10-14 22:48:04 +09003673static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003674{
3675 ssize_t count;
3676
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003677 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003678 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3679 sdebug_store_sectors);
3680
3681 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3682
3683 buf[count++] = '\n';
3684 buf[count++] = 0;
3685
3686 return count;
3687}
Akinobu Mita82069372013-10-14 22:48:04 +09003688static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003689
Akinobu Mita82069372013-10-14 22:48:04 +09003690static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02003691{
3692 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
3693}
Akinobu Mita82069372013-10-14 22:48:04 +09003694static ssize_t removable_store(struct device_driver *ddp, const char *buf,
3695 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02003696{
3697 int n;
3698
3699 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3700 scsi_debug_removable = (n > 0);
3701 return count;
3702 }
3703 return -EINVAL;
3704}
Akinobu Mita82069372013-10-14 22:48:04 +09003705static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02003706
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003707static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
3708{
3709 return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_host_lock);
3710}
3711/* Returns -EBUSY if host_lock is being changed and commands are queued */
3712static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
3713 size_t count)
3714{
3715 int n, res;
3716
3717 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3718 bool new_host_lock = (n > 0);
3719
3720 res = count;
3721 if (new_host_lock != scsi_debug_host_lock) {
3722 unsigned long iflags;
3723 int k;
3724
3725 spin_lock_irqsave(&queued_arr_lock, iflags);
3726 k = find_first_bit(queued_in_use_bm,
3727 scsi_debug_max_queue);
3728 if (k != scsi_debug_max_queue)
3729 res = -EBUSY; /* have queued commands */
3730 else
3731 scsi_debug_host_lock = new_host_lock;
3732 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3733 }
3734 return res;
3735 }
3736 return -EINVAL;
3737}
3738static DRIVER_ATTR_RW(host_lock);
3739
3740
Akinobu Mita82069372013-10-14 22:48:04 +09003741/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04003742 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3743 files (over those found in the /sys/module/scsi_debug/parameters
3744 directory) is that auxiliary actions can be triggered when an attribute
3745 is changed. For example see: sdebug_add_host_store() above.
3746 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003747
Akinobu Mita82069372013-10-14 22:48:04 +09003748static struct attribute *sdebug_drv_attrs[] = {
3749 &driver_attr_delay.attr,
3750 &driver_attr_opts.attr,
3751 &driver_attr_ptype.attr,
3752 &driver_attr_dsense.attr,
3753 &driver_attr_fake_rw.attr,
3754 &driver_attr_no_lun_0.attr,
3755 &driver_attr_num_tgts.attr,
3756 &driver_attr_dev_size_mb.attr,
3757 &driver_attr_num_parts.attr,
3758 &driver_attr_every_nth.attr,
3759 &driver_attr_max_luns.attr,
3760 &driver_attr_max_queue.attr,
3761 &driver_attr_no_uld.attr,
3762 &driver_attr_scsi_level.attr,
3763 &driver_attr_virtual_gb.attr,
3764 &driver_attr_add_host.attr,
3765 &driver_attr_vpd_use_hostno.attr,
3766 &driver_attr_sector_size.attr,
3767 &driver_attr_dix.attr,
3768 &driver_attr_dif.attr,
3769 &driver_attr_guard.attr,
3770 &driver_attr_ato.attr,
3771 &driver_attr_map.attr,
3772 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003773 &driver_attr_host_lock.attr,
3774 &driver_attr_ndelay.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09003775 NULL,
3776};
3777ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
Akinobu Mita11ddcec2014-02-26 22:56:59 +09003779static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003780
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781static int __init scsi_debug_init(void)
3782{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003783 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 int host_to_add;
3785 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003786 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003788 atomic_set(&sdebug_cmnd_count, 0);
3789 atomic_set(&sdebug_completions, 0);
3790 atomic_set(&retired_max_queue, 0);
3791
3792 if (scsi_debug_ndelay >= 1000000000) {
3793 pr_warn("%s: ndelay must be less than 1 second, ignored\n",
3794 __func__);
3795 scsi_debug_ndelay = 0;
3796 } else if (scsi_debug_ndelay > 0)
3797 scsi_debug_delay = DELAY_OVERRIDDEN;
3798
Martin K. Petersen597136a2008-06-05 00:12:59 -04003799 switch (scsi_debug_sector_size) {
3800 case 512:
3801 case 1024:
3802 case 2048:
3803 case 4096:
3804 break;
3805 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003806 pr_err("%s: invalid sector_size %d\n", __func__,
Martin K. Petersen597136a2008-06-05 00:12:59 -04003807 scsi_debug_sector_size);
3808 return -EINVAL;
3809 }
3810
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003811 switch (scsi_debug_dif) {
3812
3813 case SD_DIF_TYPE0_PROTECTION:
3814 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003815 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003816 case SD_DIF_TYPE3_PROTECTION:
3817 break;
3818
3819 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003820 pr_err("%s: dif must be 0, 1, 2 or 3\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003821 return -EINVAL;
3822 }
3823
3824 if (scsi_debug_guard > 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003825 pr_err("%s: guard must be 0 or 1\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003826 return -EINVAL;
3827 }
3828
3829 if (scsi_debug_ato > 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003830 pr_err("%s: ato must be 0 or 1\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003831 return -EINVAL;
3832 }
3833
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003834 if (scsi_debug_physblk_exp > 15) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003835 pr_err("%s: invalid physblk_exp %u\n", __func__,
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003836 scsi_debug_physblk_exp);
3837 return -EINVAL;
3838 }
3839
3840 if (scsi_debug_lowest_aligned > 0x3fff) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003841 pr_err("%s: lowest_aligned too big: %u\n", __func__,
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003842 scsi_debug_lowest_aligned);
3843 return -EINVAL;
3844 }
3845
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 if (scsi_debug_dev_size_mb < 1)
3847 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003848 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003849 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003850 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851
3852 /* play around with geometry, don't waste too much on track 0 */
3853 sdebug_heads = 8;
3854 sdebug_sectors_per = 32;
3855 if (scsi_debug_dev_size_mb >= 16)
3856 sdebug_heads = 32;
3857 else if (scsi_debug_dev_size_mb >= 256)
3858 sdebug_heads = 64;
3859 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3860 (sdebug_sectors_per * sdebug_heads);
3861 if (sdebug_cylinders_per >= 1024) {
3862 /* other LLDs do this; implies >= 1GB ram disk ... */
3863 sdebug_heads = 255;
3864 sdebug_sectors_per = 63;
3865 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3866 (sdebug_sectors_per * sdebug_heads);
3867 }
3868
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003869 if (0 == scsi_debug_fake_rw) {
3870 fake_storep = vmalloc(sz);
3871 if (NULL == fake_storep) {
3872 pr_err("%s: out of memory, 1\n", __func__);
3873 return -ENOMEM;
3874 }
3875 memset(fake_storep, 0, sz);
3876 if (scsi_debug_num_parts > 0)
3877 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879
Akinobu Mita7cb69d02013-06-29 17:59:16 +09003880 if (scsi_debug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003881 int dif_size;
3882
3883 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3884 dif_storep = vmalloc(dif_size);
3885
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003886 pr_err("%s: dif_storep %u bytes @ %p\n", __func__, dif_size,
3887 dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003888
3889 if (dif_storep == NULL) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003890 pr_err("%s: out of mem. (DIX)\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003891 ret = -ENOMEM;
3892 goto free_vm;
3893 }
3894
3895 memset(dif_storep, 0xff, dif_size);
3896 }
3897
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003898 /* Logical Block Provisioning */
3899 if (scsi_debug_lbp()) {
Martin K. Petersen60147592010-08-19 11:49:00 -04003900 scsi_debug_unmap_max_blocks =
3901 clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
3902
3903 scsi_debug_unmap_max_desc =
3904 clamp(scsi_debug_unmap_max_desc, 0U, 256U);
3905
3906 scsi_debug_unmap_granularity =
3907 clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
3908
3909 if (scsi_debug_unmap_alignment &&
Akinobu Mitaac170782013-04-16 22:11:56 +09003910 scsi_debug_unmap_granularity <=
3911 scsi_debug_unmap_alignment) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003912 pr_err("%s: ERR: unmap_granularity <= unmap_alignment\n",
Martin K. Petersen44d92692009-10-15 14:45:27 -04003913 __func__);
3914 return -EINVAL;
3915 }
3916
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003917 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
3918 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003919
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003920 pr_info("%s: %lu provisioning blocks\n", __func__, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003921
3922 if (map_storep == NULL) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003923 pr_err("%s: out of mem. (MAP)\n", __func__);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003924 ret = -ENOMEM;
3925 goto free_vm;
3926 }
3927
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003928 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003929
3930 /* Map first 1KB for partition table */
3931 if (scsi_debug_num_parts)
3932 map_region(0, 2);
3933 }
3934
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003935 pseudo_primary = root_device_register("pseudo_0");
3936 if (IS_ERR(pseudo_primary)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003937 pr_warn("%s: root_device_register() error\n", __func__);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003938 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003939 goto free_vm;
3940 }
3941 ret = bus_register(&pseudo_lld_bus);
3942 if (ret < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003943 pr_warn("%s: bus_register error: %d\n", __func__, ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003944 goto dev_unreg;
3945 }
3946 ret = driver_register(&sdebug_driverfs_driver);
3947 if (ret < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003948 pr_warn("%s: driver_register error: %d\n", __func__, ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003949 goto bus_unreg;
3950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 host_to_add = scsi_debug_add_host;
3953 scsi_debug_add_host = 0;
3954
3955 for (k = 0; k < host_to_add; k++) {
3956 if (sdebug_add_adapter()) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003957 pr_err("%s: sdebug_add_adapter failed k=%d\n",
3958 __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 break;
3960 }
3961 }
3962
3963 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003964 pr_info("%s: built %d host(s)\n", __func__,
3965 scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 }
3967 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003968
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003969bus_unreg:
3970 bus_unregister(&pseudo_lld_bus);
3971dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003972 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003973free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003974 if (map_storep)
3975 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003976 if (dif_storep)
3977 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003978 vfree(fake_storep);
3979
3980 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981}
3982
3983static void __exit scsi_debug_exit(void)
3984{
3985 int k = scsi_debug_add_host;
3986
3987 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003988 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 for (; k; k--)
3990 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 driver_unregister(&sdebug_driverfs_driver);
3992 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003993 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003995 if (dif_storep)
3996 vfree(dif_storep);
3997
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 vfree(fake_storep);
3999}
4000
4001device_initcall(scsi_debug_init);
4002module_exit(scsi_debug_exit);
4003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004static void sdebug_release_adapter(struct device * dev)
4005{
4006 struct sdebug_host_info *sdbg_host;
4007
4008 sdbg_host = to_sdebug_host(dev);
4009 kfree(sdbg_host);
4010}
4011
4012static int sdebug_add_adapter(void)
4013{
4014 int k, devs_per_host;
4015 int error = 0;
4016 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004017 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004019 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 if (NULL == sdbg_host) {
4021 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004022 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 return -ENOMEM;
4024 }
4025
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4027
4028 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
4029 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004030 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4031 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004033 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 error = -ENOMEM;
4035 goto clean;
4036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 }
4038
4039 spin_lock(&sdebug_host_list_lock);
4040 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4041 spin_unlock(&sdebug_host_list_lock);
4042
4043 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004044 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01004046 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047
4048 error = device_register(&sdbg_host->dev);
4049
4050 if (error)
4051 goto clean;
4052
4053 ++scsi_debug_add_host;
4054 return error;
4055
4056clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004057 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4058 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 list_del(&sdbg_devinfo->dev_list);
4060 kfree(sdbg_devinfo);
4061 }
4062
4063 kfree(sdbg_host);
4064 return error;
4065}
4066
4067static void sdebug_remove_adapter(void)
4068{
4069 struct sdebug_host_info * sdbg_host = NULL;
4070
4071 spin_lock(&sdebug_host_list_lock);
4072 if (!list_empty(&sdebug_host_list)) {
4073 sdbg_host = list_entry(sdebug_host_list.prev,
4074 struct sdebug_host_info, host_list);
4075 list_del(&sdbg_host->host_list);
4076 }
4077 spin_unlock(&sdebug_host_list_lock);
4078
4079 if (!sdbg_host)
4080 return;
4081
4082 device_unregister(&sdbg_host->dev);
4083 --scsi_debug_add_host;
4084}
4085
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004086static int
4087scsi_debug_queuecommand(struct scsi_cmnd *SCpnt)
FUJITA Tomonori639db472008-03-20 11:09:19 +09004088{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02004089 unsigned char *cmd = SCpnt->cmnd;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004090 int len, k;
4091 unsigned int num;
4092 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004093 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004094 int errsts = 0;
4095 int target = SCpnt->device->id;
4096 struct sdebug_dev_info *devip = NULL;
4097 int inj_recovered = 0;
4098 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004099 int inj_dif = 0;
4100 int inj_dix = 0;
Christoph Hellwigb57d7c02014-05-01 16:51:51 +02004101 int inj_short = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004102 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004103 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004104
4105 scsi_set_resid(SCpnt, 0);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004106 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) &&
Douglas Gilbert01123ef2014-08-05 12:20:02 +02004107 !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004108 char b[120];
4109 int n;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004110
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004111 len = SCpnt->cmd_len;
4112 if (len > 32)
4113 strcpy(b, "too long, over 32 bytes");
4114 else {
4115 for (k = 0, n = 0; k < len; ++k)
4116 n += scnprintf(b + n, sizeof(b) - n, "%02x ",
4117 (unsigned int)cmd[k]);
4118 }
4119 sdev_printk(KERN_INFO, SCpnt->device, "%s: cmd %s\n", my_name,
4120 b);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004121 }
4122
4123 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
4124 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004125 return schedule_resp(SCpnt, NULL, DID_NO_CONNECT << 16, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004126 devip = devInfoReg(SCpnt->device);
4127 if (NULL == devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004128 return schedule_resp(SCpnt, NULL, DID_NO_CONNECT << 16, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004129
4130 if ((scsi_debug_every_nth != 0) &&
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004131 (atomic_inc_return(&sdebug_cmnd_count) >=
4132 abs(scsi_debug_every_nth))) {
4133 atomic_set(&sdebug_cmnd_count, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004134 if (scsi_debug_every_nth < -1)
4135 scsi_debug_every_nth = -1;
4136 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
4137 return 0; /* ignore command causing timeout */
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -05004138 else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
4139 scsi_medium_access_command(SCpnt))
4140 return 0; /* time out reads and writes */
FUJITA Tomonori639db472008-03-20 11:09:19 +09004141 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
4142 inj_recovered = 1; /* to reads and writes below */
4143 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
4144 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004145 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
4146 inj_dif = 1; /* to reads and writes below */
4147 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
4148 inj_dix = 1; /* to reads and writes below */
Christoph Hellwigb57d7c02014-05-01 16:51:51 +02004149 else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & scsi_debug_opts)
4150 inj_short = 1;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004151 }
4152
4153 if (devip->wlun) {
4154 switch (*cmd) {
4155 case INQUIRY:
4156 case REQUEST_SENSE:
4157 case TEST_UNIT_READY:
4158 case REPORT_LUNS:
4159 break; /* only allowable wlun commands */
4160 default:
4161 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4162 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
4163 "not supported for wlun\n", *cmd);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004164 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004165 INVALID_OPCODE, 0);
4166 errsts = check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004167 return schedule_resp(SCpnt, devip, errsts, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004168 }
4169 }
4170
4171 switch (*cmd) {
4172 case INQUIRY: /* mandatory, ignore unit attention */
4173 delay_override = 1;
4174 errsts = resp_inquiry(SCpnt, target, devip);
4175 break;
4176 case REQUEST_SENSE: /* mandatory, ignore unit attention */
4177 delay_override = 1;
4178 errsts = resp_requests(SCpnt, devip);
4179 break;
4180 case REZERO_UNIT: /* actually this is REWIND for SSC */
4181 case START_STOP:
4182 errsts = resp_start_stop(SCpnt, devip);
4183 break;
4184 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004185 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004186 if (errsts)
4187 break;
4188 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4189 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
4190 cmd[4] ? "inhibited" : "enabled");
4191 break;
4192 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004193 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004194 break;
4195 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004196 /* delay_override = 1; */
4197 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004198 break;
4199 case RESERVE:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004200 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004201 break;
4202 case RESERVE_10:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004203 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004204 break;
4205 case RELEASE:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004206 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004207 break;
4208 case RELEASE_10:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004209 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004210 break;
4211 case READ_CAPACITY:
4212 errsts = resp_readcap(SCpnt, devip);
4213 break;
4214 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04004215 if (cmd[1] == SAI_READ_CAPACITY_16)
4216 errsts = resp_readcap16(SCpnt, devip);
4217 else if (cmd[1] == SAI_GET_LBA_STATUS) {
4218
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004219 if (scsi_debug_lbp() == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004220 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen44d92692009-10-15 14:45:27 -04004221 INVALID_COMMAND_OPCODE, 0);
4222 errsts = check_condition_result;
4223 } else
4224 errsts = resp_get_lba_status(SCpnt, devip);
4225 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004226 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004227 INVALID_OPCODE, 0);
4228 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004229 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09004230 break;
4231 case MAINTENANCE_IN:
4232 if (MI_REPORT_TARGET_PGS != cmd[1]) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004233 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004234 INVALID_OPCODE, 0);
4235 errsts = check_condition_result;
4236 break;
4237 }
4238 errsts = resp_report_tgtpgs(SCpnt, devip);
4239 break;
4240 case READ_16:
4241 case READ_12:
4242 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004243 /* READ{10,12,16} and DIF Type 2 are natural enemies */
4244 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
4245 cmd[1] & 0xe0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004246 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen395cef02009-09-18 17:33:03 -04004247 INVALID_COMMAND_OPCODE, 0);
4248 errsts = check_condition_result;
4249 break;
4250 }
4251
4252 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
4253 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
4254 (cmd[1] & 0xe0) == 0)
4255 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
4256
4257 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09004258 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004259read:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004260 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004261 if (errsts)
4262 break;
4263 if (scsi_debug_fake_rw)
4264 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004265 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
Christoph Hellwigb57d7c02014-05-01 16:51:51 +02004266
4267 if (inj_short)
4268 num /= 2;
4269
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004270 errsts = resp_read(SCpnt, lba, num, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004271 if (inj_recovered && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004272 mk_sense_buffer(SCpnt, RECOVERED_ERROR,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004273 THRESHOLD_EXCEEDED, 0);
4274 errsts = check_condition_result;
4275 } else if (inj_transport && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004276 mk_sense_buffer(SCpnt, ABORTED_COMMAND,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004277 TRANSPORT_PROBLEM, ACK_NAK_TO);
4278 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004279 } else if (inj_dif && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004280 /* Logical block guard check failed */
4281 mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, 1);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004282 errsts = illegal_condition_result;
4283 } else if (inj_dix && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004284 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10, 1);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004285 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004286 }
4287 break;
4288 case REPORT_LUNS: /* mandatory, ignore unit attention */
4289 delay_override = 1;
4290 errsts = resp_report_luns(SCpnt, devip);
4291 break;
4292 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004293 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004294 break;
4295 case WRITE_16:
4296 case WRITE_12:
4297 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004298 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
4299 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
4300 cmd[1] & 0xe0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004301 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen395cef02009-09-18 17:33:03 -04004302 INVALID_COMMAND_OPCODE, 0);
4303 errsts = check_condition_result;
4304 break;
4305 }
4306
4307 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
4308 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
4309 (cmd[1] & 0xe0) == 0)
4310 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
4311
4312 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09004313 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004314write:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004315 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004316 if (errsts)
4317 break;
4318 if (scsi_debug_fake_rw)
4319 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004320 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004321 errsts = resp_write(SCpnt, lba, num, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004322 if (inj_recovered && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004323 mk_sense_buffer(SCpnt, RECOVERED_ERROR,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004324 THRESHOLD_EXCEEDED, 0);
4325 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004326 } else if (inj_dif && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004327 mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, 1);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004328 errsts = illegal_condition_result;
4329 } else if (inj_dix && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004330 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10, 1);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004331 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004332 }
4333 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004334 case WRITE_SAME_16:
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004335 case WRITE_SAME:
Martin K. Petersen60147592010-08-19 11:49:00 -04004336 if (cmd[1] & 0x8) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004337 if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
4338 (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004339 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen60147592010-08-19 11:49:00 -04004340 INVALID_FIELD_IN_CDB, 0);
4341 errsts = check_condition_result;
4342 } else
4343 unmap = 1;
4344 }
4345 if (errsts)
4346 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004347 errsts = check_readiness(SCpnt, UAS_TUR, devip);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004348 if (errsts)
4349 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004350 if (scsi_debug_fake_rw)
4351 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004352 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004353 errsts = resp_write_same(SCpnt, lba, num, ei_lba, unmap);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004354 break;
4355 case UNMAP:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004356 errsts = check_readiness(SCpnt, UAS_TUR, devip);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004357 if (errsts)
4358 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004359 if (scsi_debug_fake_rw)
4360 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004361
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004362 if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004363 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen44d92692009-10-15 14:45:27 -04004364 INVALID_COMMAND_OPCODE, 0);
4365 errsts = check_condition_result;
4366 } else
4367 errsts = resp_unmap(SCpnt, devip);
4368 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004369 case MODE_SENSE:
4370 case MODE_SENSE_10:
4371 errsts = resp_mode_sense(SCpnt, target, devip);
4372 break;
4373 case MODE_SELECT:
4374 errsts = resp_mode_select(SCpnt, 1, devip);
4375 break;
4376 case MODE_SELECT_10:
4377 errsts = resp_mode_select(SCpnt, 0, devip);
4378 break;
4379 case LOG_SENSE:
4380 errsts = resp_log_sense(SCpnt, devip);
4381 break;
4382 case SYNCHRONIZE_CACHE:
4383 delay_override = 1;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004384 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004385 break;
4386 case WRITE_BUFFER:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004387 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004388 break;
4389 case XDWRITEREAD_10:
4390 if (!scsi_bidi_cmnd(SCpnt)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004391 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004392 INVALID_FIELD_IN_CDB, 0);
4393 errsts = check_condition_result;
4394 break;
4395 }
4396
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004397 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004398 if (errsts)
4399 break;
4400 if (scsi_debug_fake_rw)
4401 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004402 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004403 errsts = resp_read(SCpnt, lba, num, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004404 if (errsts)
4405 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004406 errsts = resp_write(SCpnt, lba, num, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004407 if (errsts)
4408 break;
4409 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
4410 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004411 case VARIABLE_LENGTH_CMD:
4412 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
4413
4414 if ((cmd[10] & 0xe0) == 0)
4415 printk(KERN_ERR
4416 "Unprotected RD/WR to DIF device\n");
4417
4418 if (cmd[9] == READ_32) {
4419 BUG_ON(SCpnt->cmd_len < 32);
4420 goto read;
4421 }
4422
4423 if (cmd[9] == WRITE_32) {
4424 BUG_ON(SCpnt->cmd_len < 32);
4425 goto write;
4426 }
4427 }
4428
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004429 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen395cef02009-09-18 17:33:03 -04004430 INVALID_FIELD_IN_CDB, 0);
4431 errsts = check_condition_result;
4432 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004433 case 0x85:
4434 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4435 sdev_printk(KERN_INFO, SCpnt->device,
4436 "%s: ATA PASS-THROUGH(16) not supported\n", my_name);
4437 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4438 INVALID_OPCODE, 0);
4439 errsts = check_condition_result;
4440 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004441 default:
4442 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004443 sdev_printk(KERN_INFO, SCpnt->device,
4444 "%s: Opcode: 0x%x not supported\n",
4445 my_name, *cmd);
4446 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004447 if (errsts)
4448 break; /* Unit attention takes precedence */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004449 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004450 errsts = check_condition_result;
4451 break;
4452 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004453 return schedule_resp(SCpnt, devip, errsts,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004454 (delay_override ? 0 : scsi_debug_delay));
4455}
4456
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004457static int
4458sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
4459{
4460 if (scsi_debug_host_lock) {
4461 unsigned long iflags;
4462 int rc;
4463
4464 spin_lock_irqsave(shost->host_lock, iflags);
4465 rc = scsi_debug_queuecommand(cmd);
4466 spin_unlock_irqrestore(shost->host_lock, iflags);
4467 return rc;
4468 } else
4469 return scsi_debug_queuecommand(cmd);
4470}
4471
4472static int
4473sdebug_change_qdepth(struct scsi_device *sdev, int qdepth, int reason)
4474{
4475 int num_in_q = 0;
4476 int bad = 0;
4477 unsigned long iflags;
4478 struct sdebug_dev_info *devip;
4479
4480 spin_lock_irqsave(&queued_arr_lock, iflags);
4481 devip = (struct sdebug_dev_info *)sdev->hostdata;
4482 if (NULL == devip) {
4483 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4484 return -ENODEV;
4485 }
4486 num_in_q = atomic_read(&devip->num_in_q);
4487 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4488 if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) {
4489 if (qdepth < 1)
4490 qdepth = 1;
4491 /* allow to exceed max host queued_arr elements for testing */
4492 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4493 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01004494 scsi_adjust_queue_depth(sdev, qdepth);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004495 } else if (reason == SCSI_QDEPTH_QFULL)
4496 scsi_track_queue_full(sdev, qdepth);
4497 else
4498 bad = 1;
4499 if (bad)
4500 sdev_printk(KERN_WARNING, sdev,
4501 "%s: unknown reason=0x%x\n", __func__, reason);
4502 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4503 if (SCSI_QDEPTH_QFULL == reason)
4504 sdev_printk(KERN_INFO, sdev,
4505 "%s: -> %d, num_in_q=%d, reason: queue full\n",
4506 __func__, qdepth, num_in_q);
4507 else {
4508 const char *cp;
4509
4510 switch (reason) {
4511 case SCSI_QDEPTH_DEFAULT:
4512 cp = "default (sysfs ?)";
4513 break;
4514 case SCSI_QDEPTH_RAMP_UP:
4515 cp = "ramp up";
4516 break;
4517 default:
4518 cp = "unknown";
4519 break;
4520 }
4521 sdev_printk(KERN_INFO, sdev,
4522 "%s: qdepth=%d, num_in_q=%d, reason: %s\n",
4523 __func__, qdepth, num_in_q, cp);
4524 }
4525 }
4526 return sdev->queue_depth;
4527}
4528
4529static int
4530sdebug_change_qtype(struct scsi_device *sdev, int qtype)
4531{
Christoph Hellwiga62182f2014-10-02 14:39:55 +02004532 qtype = scsi_change_queue_type(sdev, qtype);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004533 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4534 const char *cp;
4535
4536 switch (qtype) {
4537 case 0:
4538 cp = "untagged";
4539 break;
4540 case MSG_SIMPLE_TAG:
4541 cp = "simple tags";
4542 break;
4543 case MSG_ORDERED_TAG:
4544 cp = "ordered tags";
4545 break;
4546 default:
4547 cp = "unknown";
4548 break;
4549 }
4550 sdev_printk(KERN_INFO, sdev, "%s: to %s\n", __func__, cp);
4551 }
4552 return qtype;
4553}
Jeff Garzikf2812332010-11-16 02:10:29 -05004554
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004555static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04004556 .show_info = scsi_debug_show_info,
4557 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004558 .proc_name = sdebug_proc_name,
4559 .name = "SCSI DEBUG",
4560 .info = scsi_debug_info,
4561 .slave_alloc = scsi_debug_slave_alloc,
4562 .slave_configure = scsi_debug_slave_configure,
4563 .slave_destroy = scsi_debug_slave_destroy,
4564 .ioctl = scsi_debug_ioctl,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004565 .queuecommand = sdebug_queuecommand_lock_or_not,
4566 .change_queue_depth = sdebug_change_qdepth,
4567 .change_queue_type = sdebug_change_qtype,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004568 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004569 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004570 .eh_target_reset_handler = scsi_debug_target_reset,
4571 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004572 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004573 .can_queue = SCSI_DEBUG_CANQUEUE,
4574 .this_id = 7,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09004575 .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004576 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09004577 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004578 .use_clustering = DISABLE_CLUSTERING,
4579 .module = THIS_MODULE,
4580};
4581
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582static int sdebug_driver_probe(struct device * dev)
4583{
4584 int error = 0;
4585 struct sdebug_host_info *sdbg_host;
4586 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004587 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
4589 sdbg_host = to_sdebug_host(dev);
4590
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004591 sdebug_driver_template.can_queue = scsi_debug_max_queue;
Akinobu Mita0759c662014-02-26 22:57:04 +09004592 if (scsi_debug_clustering)
4593 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004594 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
4595 if (NULL == hpnt) {
4596 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
4597 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600
4601 sdbg_host->shost = hpnt;
4602 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
4603 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
4604 hpnt->max_id = scsi_debug_num_tgts + 1;
4605 else
4606 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004607 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004609 host_prot = 0;
4610
4611 switch (scsi_debug_dif) {
4612
4613 case SD_DIF_TYPE1_PROTECTION:
4614 host_prot = SHOST_DIF_TYPE1_PROTECTION;
4615 if (scsi_debug_dix)
4616 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
4617 break;
4618
4619 case SD_DIF_TYPE2_PROTECTION:
4620 host_prot = SHOST_DIF_TYPE2_PROTECTION;
4621 if (scsi_debug_dix)
4622 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
4623 break;
4624
4625 case SD_DIF_TYPE3_PROTECTION:
4626 host_prot = SHOST_DIF_TYPE3_PROTECTION;
4627 if (scsi_debug_dix)
4628 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
4629 break;
4630
4631 default:
4632 if (scsi_debug_dix)
4633 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
4634 break;
4635 }
4636
4637 scsi_host_set_prot(hpnt, host_prot);
4638
4639 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
4640 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
4641 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
4642 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4643 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4644 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4645 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4646 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4647
4648 if (scsi_debug_guard == 1)
4649 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4650 else
4651 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4652
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 error = scsi_add_host(hpnt, &sdbg_host->dev);
4654 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004655 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 error = -ENODEV;
4657 scsi_host_put(hpnt);
4658 } else
4659 scsi_scan_host(hpnt);
4660
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004661 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662}
4663
4664static int sdebug_driver_remove(struct device * dev)
4665{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004667 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668
4669 sdbg_host = to_sdebug_host(dev);
4670
4671 if (!sdbg_host) {
4672 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004673 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 return -ENODEV;
4675 }
4676
4677 scsi_remove_host(sdbg_host->shost);
4678
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004679 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4680 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 list_del(&sdbg_devinfo->dev_list);
4682 kfree(sdbg_devinfo);
4683 }
4684
4685 scsi_host_put(sdbg_host->shost);
4686 return 0;
4687}
4688
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004689static int pseudo_lld_bus_match(struct device *dev,
4690 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004692 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004694
4695static struct bus_type pseudo_lld_bus = {
4696 .name = "pseudo",
4697 .match = pseudo_lld_bus_match,
4698 .probe = sdebug_driver_probe,
4699 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09004700 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004701};