blob: d337eaa128d0db7f77ccec956bad6d542713551e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040015 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/types.h>
35#include <linux/string.h>
36#include <linux/genhd.h>
37#include <linux/fs.h>
38#include <linux/init.h>
39#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/vmalloc.h>
41#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020042#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050044#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040045#include <linux/spinlock.h>
46#include <linux/interrupt.h>
47#include <linux/atomic.h>
48#include <linux/hrtimer.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050049
50#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090051
Martin K. Petersen44d92692009-10-15 14:45:27 -040052#include <asm/unaligned.h>
53
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090054#include <scsi/scsi.h>
55#include <scsi/scsi_cmnd.h>
56#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <scsi/scsi_host.h>
58#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090059#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040060#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040061#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Martin K. Petersenc6a44282009-01-04 03:08:19 -050063#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Douglas Gilbert22017ed2014-11-24 23:04:47 -050066#define SCSI_DEBUG_VERSION "1.85"
67static const char *scsi_debug_version_date = "20141022";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040068
69#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050071/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040072#define NO_ADDITIONAL_SENSE 0x0
73#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040075#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#define INVALID_OPCODE 0x20
Martin K. Petersen395cef02009-09-18 17:33:03 -040077#define INVALID_COMMAND_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050078#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070079#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040080#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040081#define UA_RESET_ASC 0x29
82#define UA_CHANGED_ASC 0x2a
Douglas Gilbert22017ed2014-11-24 23:04:47 -050083#define INSUFF_RES_ASC 0x55
84#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040085#define POWER_ON_RESET_ASCQ 0x0
86#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
87#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050088#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050090#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define THRESHOLD_EXCEEDED 0x5d
92#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050093#define MISCOMPARE_VERIFY_ASC 0x1d
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050095/* Additional Sense Code Qualifier (ASCQ) */
96#define ACK_NAK_TO 0x3
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99/* Default values for driver parameters */
100#define DEF_NUM_HOST 1
101#define DEF_NUM_TGTS 1
102#define DEF_MAX_LUNS 1
103/* With these defaults, this driver will make 1 host with 1 target
104 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
105 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500106#define DEF_ATO 1
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400107#define DEF_DELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500109#define DEF_DIF 0
110#define DEF_DIX 0
111#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500113#define DEF_FAKE_RW 0
114#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400115#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500116#define DEF_LBPU 0
117#define DEF_LBPWS 0
118#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600119#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500120#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400121#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500122#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define DEF_NUM_PARTS 0
124#define DEF_OPTS 0
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400125#define DEF_OPT_BLKS 64
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500126#define DEF_PHYSBLK_EXP 0
127#define DEF_PTYPE 0
Martin Pittd9867882012-09-06 12:04:33 +0200128#define DEF_REMOVABLE false
Douglas Gilberte46b0342014-08-05 12:21:53 +0200129#define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500130#define DEF_SECTOR_SIZE 512
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400131#define DEF_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500132#define DEF_UNMAP_ALIGNMENT 0
133#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400134#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
135#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500136#define DEF_VIRTUAL_GB 0
137#define DEF_VPD_USE_HOSTNO 1
138#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400139#define DELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141/* bit mask values for scsi_debug_opts */
142#define SCSI_DEBUG_OPT_NOISE 1
143#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
144#define SCSI_DEBUG_OPT_TIMEOUT 4
145#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500146#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500147#define SCSI_DEBUG_OPT_DIF_ERR 32
148#define SCSI_DEBUG_OPT_DIX_ERR 64
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -0500149#define SCSI_DEBUG_OPT_MAC_TIMEOUT 128
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400150#define SCSI_DEBUG_OPT_SHORT_TRANSFER 0x100
151#define SCSI_DEBUG_OPT_Q_NOISE 0x200
152#define SCSI_DEBUG_OPT_ALL_TSF 0x400
153#define SCSI_DEBUG_OPT_RARE_TSF 0x800
154#define SCSI_DEBUG_OPT_N_WCE 0x1000
155#define SCSI_DEBUG_OPT_RESET_NOISE 0x2000
156#define SCSI_DEBUG_OPT_NO_CDB_NOISE 0x4000
157#define SCSI_DEBUG_OPT_ALL_NOISE (0x1 | 0x200 | 0x2000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158/* When "every_nth" > 0 then modulo "every_nth" commands:
159 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
160 * - a RECOVERED_ERROR is simulated on successful read and write
161 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500162 * - a TRANSPORT_ERROR is simulated on successful read and write
163 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 *
165 * When "every_nth" < 0 then after "- every_nth" commands:
166 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
167 * - a RECOVERED_ERROR is simulated on successful read and write
168 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500169 * - a TRANSPORT_ERROR is simulated on successful read and write
170 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 * This will continue until some other action occurs (e.g. the user
172 * writing a new value (other than -1 or 1) to every_nth via sysfs).
173 */
174
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400175/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in
176 * priority order. In the subset implemented here lower numbers have higher
177 * priority. The UA numbers should be a sequence starting from 0 with
178 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
179#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
180#define SDEBUG_UA_BUS_RESET 1
181#define SDEBUG_UA_MODE_CHANGED 2
182#define SDEBUG_NUM_UAS 3
183
184/* for check_readiness() */
185#define UAS_ONLY 1
186#define UAS_TUR 0
187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
189 * sector on read commands: */
190#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500191#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
193/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
194 * or "peripheral device" addressing (value 0) */
195#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400196#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400198/* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued
199 * (for response) at one time. Can be reduced by max_queue option. Command
200 * responses are not queued when delay=0 and ndelay=0. The per-device
201 * DEF_CMD_PER_LUN can be changed via sysfs:
202 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed
203 * SCSI_DEBUG_CANQUEUE. */
204#define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */
205#define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
206#define DEF_CMD_PER_LUN 255
207
208#if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE
209#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
210#endif
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400211
Douglas Gilbert817fd662014-11-24 20:18:02 -0500212struct sdebug_scmd_extra_t {
213 bool inj_recovered;
214 bool inj_transport;
215 bool inj_dif;
216 bool inj_dix;
217 bool inj_short;
218};
219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220static int scsi_debug_add_host = DEF_NUM_HOST;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500221static int scsi_debug_ato = DEF_ATO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222static int scsi_debug_delay = DEF_DELAY;
223static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500224static int scsi_debug_dif = DEF_DIF;
225static int scsi_debug_dix = DEF_DIX;
226static int scsi_debug_dsense = DEF_D_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227static int scsi_debug_every_nth = DEF_EVERY_NTH;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500228static int scsi_debug_fake_rw = DEF_FAKE_RW;
Akinobu Mita68aee7b2013-09-18 21:27:27 +0900229static unsigned int scsi_debug_guard = DEF_GUARD;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500230static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231static int scsi_debug_max_luns = DEF_MAX_LUNS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400232static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400233static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
234static int scsi_debug_ndelay = DEF_NDELAY;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400235static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500236static int scsi_debug_no_uld = 0;
237static int scsi_debug_num_parts = DEF_NUM_PARTS;
238static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400239static int scsi_debug_opt_blks = DEF_OPT_BLKS;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500240static int scsi_debug_opts = DEF_OPTS;
241static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
242static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
243static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
244static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
245static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
246static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
247static unsigned int scsi_debug_lbpu = DEF_LBPU;
248static unsigned int scsi_debug_lbpws = DEF_LBPWS;
249static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600250static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
Martin K. Petersen60147592010-08-19 11:49:00 -0400251static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500252static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
253static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
254static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
255static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
Martin Pittd9867882012-09-06 12:04:33 +0200256static bool scsi_debug_removable = DEF_REMOVABLE;
Akinobu Mita0759c662014-02-26 22:57:04 +0900257static bool scsi_debug_clustering;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400258static bool scsi_debug_host_lock = DEF_HOST_LOCK;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500259static bool sdebug_any_injecting_opt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400261static atomic_t sdebug_cmnd_count;
262static atomic_t sdebug_completions;
263static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265#define DEV_READONLY(TGT) (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400267static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268static sector_t sdebug_capacity; /* in sectors */
269
270/* old BIOS stuff, kernel may get rid of them but some mode sense pages
271 may still need them */
272static int sdebug_heads; /* heads per disk */
273static int sdebug_cylinders_per; /* cylinders per surface */
274static int sdebug_sectors_per; /* sectors per cylinder */
275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276#define SDEBUG_MAX_PARTS 4
277
Martin K. Petersen395cef02009-09-18 17:33:03 -0400278#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900279
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500280static unsigned int scsi_debug_lbp(void)
281{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400282 return ((0 == scsi_debug_fake_rw) &&
283 (scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10));
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500284}
285
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286struct sdebug_dev_info {
287 struct list_head dev_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 unsigned int channel;
289 unsigned int target;
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200290 u64 lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 struct sdebug_host_info *sdbg_host;
Hannes Reinecke9cb78c12014-06-25 15:27:36 +0200292 u64 wlun;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400293 unsigned long uas_bm[1];
294 atomic_t num_in_q;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400295 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 char used;
297};
298
299struct sdebug_host_info {
300 struct list_head host_list;
301 struct Scsi_Host *shost;
302 struct device dev;
303 struct list_head dev_info_list;
304};
305
306#define to_sdebug_host(d) \
307 container_of(d, struct sdebug_host_info, dev)
308
309static LIST_HEAD(sdebug_host_list);
310static DEFINE_SPINLOCK(sdebug_host_list_lock);
311
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400312
313struct sdebug_hrtimer { /* ... is derived from hrtimer */
314 struct hrtimer hrt; /* must be first element */
315 int qa_indx;
316};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318struct sdebug_queued_cmd {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400319 /* in_use flagged by a bit in queued_in_use_bm[] */
320 struct timer_list *cmnd_timerp;
321 struct tasklet_struct *tletp;
322 struct sdebug_hrtimer *sd_hrtp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 struct scsi_cmnd * a_cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324};
325static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400326static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS];
327
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329static unsigned char * fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900330static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400331static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Martin K. Petersen44d92692009-10-15 14:45:27 -0400333static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400334static int num_aborts;
335static int num_dev_resets;
336static int num_target_resets;
337static int num_bus_resets;
338static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500339static int dix_writes;
340static int dix_reads;
341static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343static DEFINE_SPINLOCK(queued_arr_lock);
344static DEFINE_RWLOCK(atomic_rw);
345
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400346static char sdebug_proc_name[] = MY_NAME;
347static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349static struct bus_type pseudo_lld_bus;
350
351static struct device_driver sdebug_driverfs_driver = {
352 .name = sdebug_proc_name,
353 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354};
355
356static const int check_condition_result =
357 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
358
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500359static const int illegal_condition_result =
360 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
361
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400362static const int device_qfull_result =
363 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
364
365static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
366 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
367 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400368static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
369 0, 0, 0x2, 0x4b};
370static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
371 0, 0, 0x0, 0x0};
372
Akinobu Mita14faa942013-09-18 21:27:24 +0900373static void *fake_store(unsigned long long lba)
374{
375 lba = do_div(lba, sdebug_store_sectors);
376
377 return fake_storep + lba * scsi_debug_sector_size;
378}
379
380static struct sd_dif_tuple *dif_store(sector_t sector)
381{
382 sector = do_div(sector, sdebug_store_sectors);
383
384 return dif_storep + sector;
385}
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387static int sdebug_add_adapter(void);
388static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900390static void sdebug_max_tgts_luns(void)
391{
392 struct sdebug_host_info *sdbg_host;
393 struct Scsi_Host *hpnt;
394
395 spin_lock(&sdebug_host_list_lock);
396 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
397 hpnt = sdbg_host->shost;
398 if ((hpnt->this_id >= 0) &&
399 (scsi_debug_num_tgts > hpnt->this_id))
400 hpnt->max_id = scsi_debug_num_tgts + 1;
401 else
402 hpnt->max_id = scsi_debug_num_tgts;
403 /* scsi_debug_max_luns; */
404 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
405 }
406 spin_unlock(&sdebug_host_list_lock);
407}
408
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500409enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
410
411/* Set in_bit to -1 to indicate no bit position of invalid field */
412static void
413mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
414 int in_byte, int in_bit)
415{
416 unsigned char *sbuff;
417 u8 sks[4];
418 int sl, asc;
419
420 sbuff = scp->sense_buffer;
421 if (!sbuff) {
422 sdev_printk(KERN_ERR, scp->device,
423 "%s: sense_buffer is NULL\n", __func__);
424 return;
425 }
426 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
427 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
428 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, ILLEGAL_REQUEST,
429 asc, 0);
430 memset(sks, 0, sizeof(sks));
431 sks[0] = 0x80;
432 if (c_d)
433 sks[0] |= 0x40;
434 if (in_bit >= 0) {
435 sks[0] |= 0x8;
436 sks[0] |= 0x7 & in_bit;
437 }
438 put_unaligned_be16(in_byte, sks + 1);
439 if (scsi_debug_dsense) {
440 sl = sbuff[7] + 8;
441 sbuff[7] = sl;
442 sbuff[sl] = 0x2;
443 sbuff[sl + 1] = 0x6;
444 memcpy(sbuff + sl + 4, sks, 3);
445 } else
446 memcpy(sbuff + 15, sks, 3);
447 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
448 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
449 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
450 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
451}
452
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400453static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900454{
455 unsigned char *sbuff;
456
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400457 sbuff = scp->sense_buffer;
458 if (!sbuff) {
459 sdev_printk(KERN_ERR, scp->device,
460 "%s: sense_buffer is NULL\n", __func__);
461 return;
462 }
463 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900464
465 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
466
467 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400468 sdev_printk(KERN_INFO, scp->device,
469 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
470 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900471}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500473static void
474mk_sense_invalid_opcode(struct scsi_cmnd *scp)
475{
476 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
477}
478
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900479static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400480 unsigned long long *lba, unsigned int *num,
481 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900482{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400483 *ei_lba = 0;
484
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900485 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400486 case VARIABLE_LENGTH_CMD:
487 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
488 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
489 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
490 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
491
492 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
493 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
494
495 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
496 (u32)cmd[28] << 24;
497 break;
498
Martin K. Petersen44d92692009-10-15 14:45:27 -0400499 case WRITE_SAME_16:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900500 case WRITE_16:
501 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900502 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
503 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
504 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
505 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
506
507 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
508 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900509 break;
510 case WRITE_12:
511 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900512 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
513 (u32)cmd[2] << 24;
514
515 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
516 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900517 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400518 case WRITE_SAME:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900519 case WRITE_10:
520 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900521 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900522 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
523 (u32)cmd[2] << 24;
524
525 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900526 break;
527 case WRITE_6:
528 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900529 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
530 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900531 *num = (0 == cmd[4]) ? 256 : cmd[4];
532 break;
533 default:
534 break;
535 }
536}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
539{
540 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400541 if (0x1261 == cmd)
542 sdev_printk(KERN_INFO, dev,
543 "%s: BLKFLSBUF [0x1261]\n", __func__);
544 else if (0x5331 == cmd)
545 sdev_printk(KERN_INFO, dev,
546 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
547 __func__);
548 else
549 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
550 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
552 return -EINVAL;
553 /* return -ENOTTY; // correct return but upsets fdisk */
554}
555
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400556static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400557 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400559 int k;
560 bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
561
562 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
563 if (k != SDEBUG_NUM_UAS) {
564 const char *cp = NULL;
565
566 switch (k) {
567 case SDEBUG_UA_POR:
568 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
569 UA_RESET_ASC, POWER_ON_RESET_ASCQ);
570 if (debug)
571 cp = "power on reset";
572 break;
573 case SDEBUG_UA_BUS_RESET:
574 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
575 UA_RESET_ASC, BUS_RESET_ASCQ);
576 if (debug)
577 cp = "bus reset";
578 break;
579 case SDEBUG_UA_MODE_CHANGED:
580 mk_sense_buffer(SCpnt, UNIT_ATTENTION,
581 UA_CHANGED_ASC, MODE_CHANGED_ASCQ);
582 if (debug)
583 cp = "mode parameters changed";
584 break;
585 default:
586 pr_warn("%s: unexpected unit attention code=%d\n",
587 __func__, k);
588 if (debug)
589 cp = "unknown";
590 break;
591 }
592 clear_bit(k, devip->uas_bm);
593 if (debug)
594 sdev_printk(KERN_INFO, SCpnt->device,
595 "%s reports: Unit attention: %s\n",
596 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 return check_condition_result;
598 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400599 if ((UAS_TUR == uas_only) && devip->stopped) {
600 mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400601 0x2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400602 if (debug)
603 sdev_printk(KERN_INFO, SCpnt->device,
604 "%s reports: Not ready: %s\n", my_name,
605 "initializing command required");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400606 return check_condition_result;
607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 return 0;
609}
610
611/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900612static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 int arr_len)
614{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900615 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900616 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900618 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900620 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900622
623 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
624 arr, arr_len);
Akinobu Mitaa4517512013-07-08 16:01:57 -0700625 sdb->resid = scsi_bufflen(scp) - act_len;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 return 0;
628}
629
630/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900631static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
632 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900634 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900636 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900638
639 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640}
641
642
643static const char * inq_vendor_id = "Linux ";
644static const char * inq_product_id = "scsi_debug ";
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400645static const char *inq_product_rev = "0184"; /* version less '.' */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400647/* Device identification VPD page. Returns number of bytes placed in arr */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200648static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
649 int target_dev_id, int dev_id_num,
650 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400651 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400653 int num, port_a;
654 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400656 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 /* T10 vendor identifier field format (faked) */
658 arr[0] = 0x2; /* ASCII */
659 arr[1] = 0x1;
660 arr[2] = 0x0;
661 memcpy(&arr[4], inq_vendor_id, 8);
662 memcpy(&arr[12], inq_product_id, 16);
663 memcpy(&arr[28], dev_id_str, dev_id_str_len);
664 num = 8 + 16 + dev_id_str_len;
665 arr[3] = num;
666 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400667 if (dev_id_num >= 0) {
668 /* NAA-5, Logical unit identifier (binary) */
669 arr[num++] = 0x1; /* binary (not necessarily sas) */
670 arr[num++] = 0x3; /* PIV=0, lu, naa */
671 arr[num++] = 0x0;
672 arr[num++] = 0x8;
673 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
674 arr[num++] = 0x33;
675 arr[num++] = 0x33;
676 arr[num++] = 0x30;
677 arr[num++] = (dev_id_num >> 24);
678 arr[num++] = (dev_id_num >> 16) & 0xff;
679 arr[num++] = (dev_id_num >> 8) & 0xff;
680 arr[num++] = dev_id_num & 0xff;
681 /* Target relative port number */
682 arr[num++] = 0x61; /* proto=sas, binary */
683 arr[num++] = 0x94; /* PIV=1, target port, rel port */
684 arr[num++] = 0x0; /* reserved */
685 arr[num++] = 0x4; /* length */
686 arr[num++] = 0x0; /* reserved */
687 arr[num++] = 0x0; /* reserved */
688 arr[num++] = 0x0;
689 arr[num++] = 0x1; /* relative port A */
690 }
691 /* NAA-5, Target port identifier */
692 arr[num++] = 0x61; /* proto=sas, binary */
693 arr[num++] = 0x93; /* piv=1, target port, naa */
694 arr[num++] = 0x0;
695 arr[num++] = 0x8;
696 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
697 arr[num++] = 0x22;
698 arr[num++] = 0x22;
699 arr[num++] = 0x20;
700 arr[num++] = (port_a >> 24);
701 arr[num++] = (port_a >> 16) & 0xff;
702 arr[num++] = (port_a >> 8) & 0xff;
703 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200704 /* NAA-5, Target port group identifier */
705 arr[num++] = 0x61; /* proto=sas, binary */
706 arr[num++] = 0x95; /* piv=1, target port group id */
707 arr[num++] = 0x0;
708 arr[num++] = 0x4;
709 arr[num++] = 0;
710 arr[num++] = 0;
711 arr[num++] = (port_group_id >> 8) & 0xff;
712 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400713 /* NAA-5, Target device identifier */
714 arr[num++] = 0x61; /* proto=sas, binary */
715 arr[num++] = 0xa3; /* piv=1, target device, naa */
716 arr[num++] = 0x0;
717 arr[num++] = 0x8;
718 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
719 arr[num++] = 0x22;
720 arr[num++] = 0x22;
721 arr[num++] = 0x20;
722 arr[num++] = (target_dev_id >> 24);
723 arr[num++] = (target_dev_id >> 16) & 0xff;
724 arr[num++] = (target_dev_id >> 8) & 0xff;
725 arr[num++] = target_dev_id & 0xff;
726 /* SCSI name string: Target device identifier */
727 arr[num++] = 0x63; /* proto=sas, UTF-8 */
728 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
729 arr[num++] = 0x0;
730 arr[num++] = 24;
731 memcpy(arr + num, "naa.52222220", 12);
732 num += 12;
733 snprintf(b, sizeof(b), "%08X", target_dev_id);
734 memcpy(arr + num, b, 8);
735 num += 8;
736 memset(arr + num, 0, 4);
737 num += 4;
738 return num;
739}
740
741
742static unsigned char vpd84_data[] = {
743/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
744 0x22,0x22,0x22,0x0,0xbb,0x1,
745 0x22,0x22,0x22,0x0,0xbb,0x2,
746};
747
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400748/* Software interface identification VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400749static int inquiry_evpd_84(unsigned char * arr)
750{
751 memcpy(arr, vpd84_data, sizeof(vpd84_data));
752 return sizeof(vpd84_data);
753}
754
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400755/* Management network addresses VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400756static int inquiry_evpd_85(unsigned char * arr)
757{
758 int num = 0;
759 const char * na1 = "https://www.kernel.org/config";
760 const char * na2 = "http://www.kernel.org/log";
761 int plen, olen;
762
763 arr[num++] = 0x1; /* lu, storage config */
764 arr[num++] = 0x0; /* reserved */
765 arr[num++] = 0x0;
766 olen = strlen(na1);
767 plen = olen + 1;
768 if (plen % 4)
769 plen = ((plen / 4) + 1) * 4;
770 arr[num++] = plen; /* length, null termianted, padded */
771 memcpy(arr + num, na1, olen);
772 memset(arr + num + olen, 0, plen - olen);
773 num += plen;
774
775 arr[num++] = 0x4; /* lu, logging */
776 arr[num++] = 0x0; /* reserved */
777 arr[num++] = 0x0;
778 olen = strlen(na2);
779 plen = olen + 1;
780 if (plen % 4)
781 plen = ((plen / 4) + 1) * 4;
782 arr[num++] = plen; /* length, null terminated, padded */
783 memcpy(arr + num, na2, olen);
784 memset(arr + num + olen, 0, plen - olen);
785 num += plen;
786
787 return num;
788}
789
790/* SCSI ports VPD page */
791static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
792{
793 int num = 0;
794 int port_a, port_b;
795
796 port_a = target_dev_id + 1;
797 port_b = port_a + 1;
798 arr[num++] = 0x0; /* reserved */
799 arr[num++] = 0x0; /* reserved */
800 arr[num++] = 0x0;
801 arr[num++] = 0x1; /* relative port 1 (primary) */
802 memset(arr + num, 0, 6);
803 num += 6;
804 arr[num++] = 0x0;
805 arr[num++] = 12; /* length tp descriptor */
806 /* naa-5 target port identifier (A) */
807 arr[num++] = 0x61; /* proto=sas, binary */
808 arr[num++] = 0x93; /* PIV=1, target port, NAA */
809 arr[num++] = 0x0; /* reserved */
810 arr[num++] = 0x8; /* length */
811 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
812 arr[num++] = 0x22;
813 arr[num++] = 0x22;
814 arr[num++] = 0x20;
815 arr[num++] = (port_a >> 24);
816 arr[num++] = (port_a >> 16) & 0xff;
817 arr[num++] = (port_a >> 8) & 0xff;
818 arr[num++] = port_a & 0xff;
819
820 arr[num++] = 0x0; /* reserved */
821 arr[num++] = 0x0; /* reserved */
822 arr[num++] = 0x0;
823 arr[num++] = 0x2; /* relative port 2 (secondary) */
824 memset(arr + num, 0, 6);
825 num += 6;
826 arr[num++] = 0x0;
827 arr[num++] = 12; /* length tp descriptor */
828 /* naa-5 target port identifier (B) */
829 arr[num++] = 0x61; /* proto=sas, binary */
830 arr[num++] = 0x93; /* PIV=1, target port, NAA */
831 arr[num++] = 0x0; /* reserved */
832 arr[num++] = 0x8; /* length */
833 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
834 arr[num++] = 0x22;
835 arr[num++] = 0x22;
836 arr[num++] = 0x20;
837 arr[num++] = (port_b >> 24);
838 arr[num++] = (port_b >> 16) & 0xff;
839 arr[num++] = (port_b >> 8) & 0xff;
840 arr[num++] = port_b & 0xff;
841
842 return num;
843}
844
845
846static unsigned char vpd89_data[] = {
847/* from 4th byte */ 0,0,0,0,
848'l','i','n','u','x',' ',' ',' ',
849'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
850'1','2','3','4',
8510x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8520xec,0,0,0,
8530x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
8540,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
8550x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
8560x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
8570x53,0x41,
8580x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8590x20,0x20,
8600x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8610x10,0x80,
8620,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8630x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8640x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8650,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8660x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8670x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8680,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
8690,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8720x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
8730,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
8740xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
8750,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
8760,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8770,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8870,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
888};
889
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400890/* ATA Information VPD page */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400891static int inquiry_evpd_89(unsigned char * arr)
892{
893 memcpy(arr, vpd89_data, sizeof(vpd89_data));
894 return sizeof(vpd89_data);
895}
896
897
898static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400899 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
900 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
901 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
902 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400903};
904
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400905/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400906static int inquiry_evpd_b0(unsigned char * arr)
907{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400908 unsigned int gran;
909
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400910 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400911
912 /* Optimal transfer length granularity */
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400913 gran = 1 << scsi_debug_physblk_exp;
914 arr[2] = (gran >> 8) & 0xff;
915 arr[3] = gran & 0xff;
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400916
917 /* Maximum Transfer Length */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400918 if (sdebug_store_sectors > 0x400) {
919 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
920 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
921 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
922 arr[7] = sdebug_store_sectors & 0xff;
923 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400924
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400925 /* Optimal Transfer Length */
926 put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
927
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500928 if (scsi_debug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400929 /* Maximum Unmap LBA Count */
Martin K. Petersen60147592010-08-19 11:49:00 -0400930 put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400931
932 /* Maximum Unmap Block Descriptor Count */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400933 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
934 }
935
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400936 /* Unmap Granularity Alignment */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400937 if (scsi_debug_unmap_alignment) {
938 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
939 arr[28] |= 0x80; /* UGAVALID */
940 }
941
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400942 /* Optimal Unmap Granularity */
Martin K. Petersen60147592010-08-19 11:49:00 -0400943 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
944
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500945 /* Maximum WRITE SAME Length */
946 put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
947
948 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400949
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400950 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951}
952
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400953/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600954static int inquiry_evpd_b1(unsigned char *arr)
955{
956 memset(arr, 0, 0x3c);
957 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400958 arr[1] = 1; /* non rotating medium (e.g. solid state) */
959 arr[2] = 0;
960 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600961
962 return 0x3c;
963}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600965/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -0400966static int inquiry_evpd_b2(unsigned char *arr)
967{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -0500968 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -0400969 arr[0] = 0; /* threshold exponent */
970
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500971 if (scsi_debug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -0400972 arr[1] = 1 << 7;
973
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500974 if (scsi_debug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -0400975 arr[1] |= 1 << 6;
976
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500977 if (scsi_debug_lbpws10)
978 arr[1] |= 1 << 5;
979
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600980 if (scsi_debug_lbprz)
981 arr[1] |= 1 << 2;
982
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -0500983 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -0400984}
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400987#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400989static int resp_inquiry(struct scsi_cmnd *scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 struct sdebug_dev_info * devip)
991{
992 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200993 unsigned char * arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +0200994 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200995 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
997 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500998 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
999 if (! arr)
1000 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001001 if (devip->wlun)
1002 pq_pdt = 0x1e; /* present, wlun */
1003 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
1004 pq_pdt = 0x7f; /* not present, no device type */
1005 else
1006 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 arr[0] = pq_pdt;
1008 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001009 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001010 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return check_condition_result;
1012 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001013 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001014 char lu_id_str[6];
1015 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001017 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1018 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -04001019 if (0 == scsi_debug_vpd_use_hostno)
1020 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001021 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
1022 (devip->target * 1000) + devip->lun);
1023 target_dev_id = ((host_no + 1) * 2000) +
1024 (devip->target * 1000) - 3;
1025 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001027 arr[1] = cmd[2]; /*sanity */
1028 n = 4;
1029 arr[n++] = 0x0; /* this page */
1030 arr[n++] = 0x80; /* unit serial number */
1031 arr[n++] = 0x83; /* device identification */
1032 arr[n++] = 0x84; /* software interface ident. */
1033 arr[n++] = 0x85; /* management network addresses */
1034 arr[n++] = 0x86; /* extended inquiry */
1035 arr[n++] = 0x87; /* mode page policy */
1036 arr[n++] = 0x88; /* SCSI ports */
1037 arr[n++] = 0x89; /* ATA information */
1038 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001039 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001040 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
1041 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001042 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001044 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001046 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001048 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001049 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1050 target_dev_id, lu_id_num,
1051 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001052 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1053 arr[1] = cmd[2]; /*sanity */
1054 arr[3] = inquiry_evpd_84(&arr[4]);
1055 } else if (0x85 == cmd[2]) { /* Management network addresses */
1056 arr[1] = cmd[2]; /*sanity */
1057 arr[3] = inquiry_evpd_85(&arr[4]);
1058 } else if (0x86 == cmd[2]) { /* extended inquiry */
1059 arr[1] = cmd[2]; /*sanity */
1060 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001061 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
1062 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
1063 else if (scsi_debug_dif)
1064 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1065 else
1066 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001067 arr[5] = 0x7; /* head of q, ordered + simple q's */
1068 } else if (0x87 == cmd[2]) { /* mode page policy */
1069 arr[1] = cmd[2]; /*sanity */
1070 arr[3] = 0x8; /* number of following entries */
1071 arr[4] = 0x2; /* disconnect-reconnect mp */
1072 arr[6] = 0x80; /* mlus, shared */
1073 arr[8] = 0x18; /* protocol specific lu */
1074 arr[10] = 0x82; /* mlus, per initiator port */
1075 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1076 arr[1] = cmd[2]; /*sanity */
1077 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1078 } else if (0x89 == cmd[2]) { /* ATA information */
1079 arr[1] = cmd[2]; /*sanity */
1080 n = inquiry_evpd_89(&arr[4]);
1081 arr[2] = (n >> 8);
1082 arr[3] = (n & 0xff);
1083 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1084 arr[1] = cmd[2]; /*sanity */
1085 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001086 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
1087 arr[1] = cmd[2]; /*sanity */
1088 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001089 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -04001090 arr[1] = cmd[2]; /*sanity */
1091 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001093 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001094 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 return check_condition_result;
1096 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001097 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001098 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001099 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001100 kfree(arr);
1101 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 }
1103 /* drops through here for a standard inquiry */
Martin Pittd9867882012-09-06 12:04:33 +02001104 arr[1] = scsi_debug_removable ? 0x80 : 0; /* Removable disk */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 arr[2] = scsi_debug_scsi_level;
1106 arr[3] = 2; /* response_data_format==2 */
1107 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001108 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001109 if (0 == scsi_debug_vpd_use_hostno)
1110 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001111 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001113 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 memcpy(&arr[8], inq_vendor_id, 8);
1115 memcpy(&arr[16], inq_product_id, 16);
1116 memcpy(&arr[32], inq_product_rev, 4);
1117 /* version descriptors (2 bytes each) follow */
Douglas Gilberte46b0342014-08-05 12:21:53 +02001118 arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */
1119 arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001120 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 if (scsi_debug_ptype == 0) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001122 arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 } else if (scsi_debug_ptype == 1) {
Douglas Gilberte46b0342014-08-05 12:21:53 +02001124 arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
Douglas Gilberte46b0342014-08-05 12:21:53 +02001126 arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001127 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001129 kfree(arr);
1130 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131}
1132
1133static int resp_requests(struct scsi_cmnd * scp,
1134 struct sdebug_dev_info * devip)
1135{
1136 unsigned char * sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001137 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001138 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001139 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 int len = 18;
1141
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001142 memset(arr, 0, sizeof(arr));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001143 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001144 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001145 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1146 if (want_dsense) {
1147 arr[0] = 0x72;
1148 arr[1] = 0x0; /* NO_SENSE in sense_key */
1149 arr[2] = THRESHOLD_EXCEEDED;
1150 arr[3] = 0xff; /* TEST set and MRIE==6 */
1151 } else {
1152 arr[0] = 0x70;
1153 arr[2] = 0x0; /* NO_SENSE in sense_key */
1154 arr[7] = 0xa; /* 18 byte sense buffer */
1155 arr[12] = THRESHOLD_EXCEEDED;
1156 arr[13] = 0xff; /* TEST set and MRIE==6 */
1157 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001158 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001159 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001160 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1161 /* DESC bit set and sense_buff in fixed format */
1162 memset(arr, 0, sizeof(arr));
1163 arr[0] = 0x72;
1164 arr[1] = sbuff[2]; /* sense key */
1165 arr[2] = sbuff[12]; /* asc */
1166 arr[3] = sbuff[13]; /* ascq */
1167 len = 8;
1168 }
1169 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001170 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 return fill_from_dev_buffer(scp, arr, len);
1172}
1173
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001174static int resp_start_stop(struct scsi_cmnd * scp,
1175 struct sdebug_dev_info * devip)
1176{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001177 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001178 int power_cond, errsts, start;
1179
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001180 errsts = check_readiness(scp, UAS_ONLY, devip);
1181 if (errsts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001182 return errsts;
1183 power_cond = (cmd[4] & 0xf0) >> 4;
1184 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001185 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001186 return check_condition_result;
1187 }
1188 start = cmd[4] & 1;
1189 if (start == devip->stopped)
1190 devip->stopped = !start;
1191 return 0;
1192}
1193
FUJITA Tomonori28898872008-03-30 00:59:55 +09001194static sector_t get_sdebug_capacity(void)
1195{
1196 if (scsi_debug_virtual_gb > 0)
Douglas Gilbert5447ed62010-04-25 12:30:23 +02001197 return (sector_t)scsi_debug_virtual_gb *
1198 (1073741824 / scsi_debug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001199 else
1200 return sdebug_store_sectors;
1201}
1202
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203#define SDEBUG_READCAP_ARR_SZ 8
1204static int resp_readcap(struct scsi_cmnd * scp,
1205 struct sdebug_dev_info * devip)
1206{
1207 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001208 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 int errsts;
1210
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001211 errsts = check_readiness(scp, UAS_ONLY, devip);
1212 if (errsts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001214 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001215 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001217 if (sdebug_capacity < 0xffffffff) {
1218 capac = (unsigned int)sdebug_capacity - 1;
1219 arr[0] = (capac >> 24);
1220 arr[1] = (capac >> 16) & 0xff;
1221 arr[2] = (capac >> 8) & 0xff;
1222 arr[3] = capac & 0xff;
1223 } else {
1224 arr[0] = 0xff;
1225 arr[1] = 0xff;
1226 arr[2] = 0xff;
1227 arr[3] = 0xff;
1228 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001229 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1230 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1232}
1233
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001234#define SDEBUG_READCAP16_ARR_SZ 32
1235static int resp_readcap16(struct scsi_cmnd * scp,
1236 struct sdebug_dev_info * devip)
1237{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001238 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001239 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1240 unsigned long long capac;
1241 int errsts, k, alloc_len;
1242
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001243 errsts = check_readiness(scp, UAS_ONLY, devip);
1244 if (errsts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001245 return errsts;
1246 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1247 + cmd[13]);
1248 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001249 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001250 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1251 capac = sdebug_capacity - 1;
1252 for (k = 0; k < 8; ++k, capac >>= 8)
1253 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001254 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1255 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1256 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1257 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001258 arr[13] = scsi_debug_physblk_exp & 0xf;
1259 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001260
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001261 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001262 arr[14] |= 0x80; /* LBPME */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001263 if (scsi_debug_lbprz)
1264 arr[14] |= 0x40; /* LBPRZ */
1265 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001266
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001267 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001268
1269 if (scsi_debug_dif) {
1270 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1271 arr[12] |= 1; /* PROT_EN */
1272 }
1273
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001274 return fill_from_dev_buffer(scp, arr,
1275 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1276}
1277
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001278#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1279
1280static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1281 struct sdebug_dev_info * devip)
1282{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001283 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001284 unsigned char * arr;
1285 int host_no = devip->sdbg_host->shost->host_no;
1286 int n, ret, alen, rlen;
1287 int port_group_a, port_group_b, port_a, port_b;
1288
1289 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1290 + cmd[9]);
1291
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001292 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1293 if (! arr)
1294 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001295 /*
1296 * EVPD page 0x88 states we have two ports, one
1297 * real and a fake port with no device connected.
1298 * So we create two port groups with one port each
1299 * and set the group with port B to unavailable.
1300 */
1301 port_a = 0x1; /* relative port A */
1302 port_b = 0x2; /* relative port B */
1303 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1304 (devip->channel & 0x7f);
1305 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1306 (devip->channel & 0x7f) + 0x80;
1307
1308 /*
1309 * The asymmetric access state is cycled according to the host_id.
1310 */
1311 n = 4;
1312 if (0 == scsi_debug_vpd_use_hostno) {
1313 arr[n++] = host_no % 3; /* Asymm access state */
1314 arr[n++] = 0x0F; /* claim: all states are supported */
1315 } else {
1316 arr[n++] = 0x0; /* Active/Optimized path */
1317 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1318 }
1319 arr[n++] = (port_group_a >> 8) & 0xff;
1320 arr[n++] = port_group_a & 0xff;
1321 arr[n++] = 0; /* Reserved */
1322 arr[n++] = 0; /* Status code */
1323 arr[n++] = 0; /* Vendor unique */
1324 arr[n++] = 0x1; /* One port per group */
1325 arr[n++] = 0; /* Reserved */
1326 arr[n++] = 0; /* Reserved */
1327 arr[n++] = (port_a >> 8) & 0xff;
1328 arr[n++] = port_a & 0xff;
1329 arr[n++] = 3; /* Port unavailable */
1330 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1331 arr[n++] = (port_group_b >> 8) & 0xff;
1332 arr[n++] = port_group_b & 0xff;
1333 arr[n++] = 0; /* Reserved */
1334 arr[n++] = 0; /* Status code */
1335 arr[n++] = 0; /* Vendor unique */
1336 arr[n++] = 0x1; /* One port per group */
1337 arr[n++] = 0; /* Reserved */
1338 arr[n++] = 0; /* Reserved */
1339 arr[n++] = (port_b >> 8) & 0xff;
1340 arr[n++] = port_b & 0xff;
1341
1342 rlen = n - 4;
1343 arr[0] = (rlen >> 24) & 0xff;
1344 arr[1] = (rlen >> 16) & 0xff;
1345 arr[2] = (rlen >> 8) & 0xff;
1346 arr[3] = rlen & 0xff;
1347
1348 /*
1349 * Return the smallest value of either
1350 * - The allocated length
1351 * - The constructed command length
1352 * - The maximum array size
1353 */
1354 rlen = min(alen,n);
1355 ret = fill_from_dev_buffer(scp, arr,
1356 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1357 kfree(arr);
1358 return ret;
1359}
1360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361/* <<Following mode page info copied from ST318451LW>> */
1362
1363static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1364{ /* Read-Write Error Recovery page for mode_sense */
1365 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1366 5, 0, 0xff, 0xff};
1367
1368 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1369 if (1 == pcontrol)
1370 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1371 return sizeof(err_recov_pg);
1372}
1373
1374static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1375{ /* Disconnect-Reconnect page for mode_sense */
1376 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1377 0, 0, 0, 0, 0, 0, 0, 0};
1378
1379 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1380 if (1 == pcontrol)
1381 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1382 return sizeof(disconnect_pg);
1383}
1384
1385static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1386{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001387 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1388 0, 0, 0, 0, 0, 0, 0, 0,
1389 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
Martin K. Petersen597136a2008-06-05 00:12:59 -04001391 memcpy(p, format_pg, sizeof(format_pg));
1392 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1393 p[11] = sdebug_sectors_per & 0xff;
1394 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1395 p[13] = scsi_debug_sector_size & 0xff;
Martin Pittd9867882012-09-06 12:04:33 +02001396 if (scsi_debug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001397 p[20] |= 0x20; /* should agree with INQUIRY */
1398 if (1 == pcontrol)
1399 memset(p + 2, 0, sizeof(format_pg) - 2);
1400 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401}
1402
1403static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1404{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001405 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1406 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1407 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1409
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001410 if (SCSI_DEBUG_OPT_N_WCE & scsi_debug_opts)
1411 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 memcpy(p, caching_pg, sizeof(caching_pg));
1413 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001414 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
1415 else if (2 == pcontrol)
1416 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 return sizeof(caching_pg);
1418}
1419
1420static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1421{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001422 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1423 0, 0, 0, 0};
1424 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 0, 0, 0x2, 0x4b};
1426
1427 if (scsi_debug_dsense)
1428 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001429 else
1430 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001431
1432 if (scsi_debug_ato)
1433 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1436 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001437 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1438 else if (2 == pcontrol)
1439 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 return sizeof(ctrl_m_pg);
1441}
1442
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001443
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1445{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001446 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1447 0, 0, 0x0, 0x0};
1448 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1449 0, 0, 0x0, 0x0};
1450
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1452 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001453 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1454 else if (2 == pcontrol)
1455 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 return sizeof(iec_m_pg);
1457}
1458
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001459static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1460{ /* SAS SSP mode page - short format for mode_sense */
1461 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1462 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1463
1464 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1465 if (1 == pcontrol)
1466 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1467 return sizeof(sas_sf_m_pg);
1468}
1469
1470
1471static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1472 int target_dev_id)
1473{ /* SAS phy control and discover mode page for mode_sense */
1474 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1475 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1476 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1477 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1478 0x2, 0, 0, 0, 0, 0, 0, 0,
1479 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1480 0, 0, 0, 0, 0, 0, 0, 0,
1481 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1482 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1483 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1484 0x3, 0, 0, 0, 0, 0, 0, 0,
1485 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1486 0, 0, 0, 0, 0, 0, 0, 0,
1487 };
1488 int port_a, port_b;
1489
1490 port_a = target_dev_id + 1;
1491 port_b = port_a + 1;
1492 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1493 p[20] = (port_a >> 24);
1494 p[21] = (port_a >> 16) & 0xff;
1495 p[22] = (port_a >> 8) & 0xff;
1496 p[23] = port_a & 0xff;
1497 p[48 + 20] = (port_b >> 24);
1498 p[48 + 21] = (port_b >> 16) & 0xff;
1499 p[48 + 22] = (port_b >> 8) & 0xff;
1500 p[48 + 23] = port_b & 0xff;
1501 if (1 == pcontrol)
1502 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1503 return sizeof(sas_pcd_m_pg);
1504}
1505
1506static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1507{ /* SAS SSP shared protocol specific port mode subpage */
1508 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1509 0, 0, 0, 0, 0, 0, 0, 0,
1510 };
1511
1512 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1513 if (1 == pcontrol)
1514 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1515 return sizeof(sas_sha_m_pg);
1516}
1517
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518#define SDEBUG_MAX_MSENSE_SZ 256
1519
1520static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1521 struct sdebug_dev_info * devip)
1522{
Douglas Gilbert23183912006-09-16 20:30:47 -04001523 unsigned char dbd, llbaa;
1524 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001526 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 unsigned char * ap;
1528 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001529 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001531 errsts = check_readiness(scp, UAS_ONLY, devip);
1532 if (errsts)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001534 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 pcontrol = (cmd[2] & 0xc0) >> 6;
1536 pcode = cmd[2] & 0x3f;
1537 subpcode = cmd[3];
1538 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001539 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1540 if ((0 == scsi_debug_ptype) && (0 == dbd))
1541 bd_len = llbaa ? 16 : 8;
1542 else
1543 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1545 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1546 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001547 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 return check_condition_result;
1549 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001550 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1551 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001552 /* set DPOFUA bit for disks */
1553 if (0 == scsi_debug_ptype)
1554 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1555 else
1556 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 if (msense_6) {
1558 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001559 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 offset = 4;
1561 } else {
1562 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001563 if (16 == bd_len)
1564 arr[4] = 0x1; /* set LONGLBA bit */
1565 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 offset = 8;
1567 }
1568 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001569 if ((bd_len > 0) && (!sdebug_capacity))
1570 sdebug_capacity = get_sdebug_capacity();
1571
Douglas Gilbert23183912006-09-16 20:30:47 -04001572 if (8 == bd_len) {
1573 if (sdebug_capacity > 0xfffffffe) {
1574 ap[0] = 0xff;
1575 ap[1] = 0xff;
1576 ap[2] = 0xff;
1577 ap[3] = 0xff;
1578 } else {
1579 ap[0] = (sdebug_capacity >> 24) & 0xff;
1580 ap[1] = (sdebug_capacity >> 16) & 0xff;
1581 ap[2] = (sdebug_capacity >> 8) & 0xff;
1582 ap[3] = sdebug_capacity & 0xff;
1583 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001584 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1585 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001586 offset += bd_len;
1587 ap = arr + offset;
1588 } else if (16 == bd_len) {
1589 unsigned long long capac = sdebug_capacity;
1590
1591 for (k = 0; k < 8; ++k, capac >>= 8)
1592 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001593 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1594 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1595 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1596 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001597 offset += bd_len;
1598 ap = arr + offset;
1599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001601 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1602 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001603 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 return check_condition_result;
1605 }
1606 switch (pcode) {
1607 case 0x1: /* Read-Write error recovery page, direct access */
1608 len = resp_err_recov_pg(ap, pcontrol, target);
1609 offset += len;
1610 break;
1611 case 0x2: /* Disconnect-Reconnect page, all devices */
1612 len = resp_disconnect_pg(ap, pcontrol, target);
1613 offset += len;
1614 break;
1615 case 0x3: /* Format device page, direct access */
1616 len = resp_format_pg(ap, pcontrol, target);
1617 offset += len;
1618 break;
1619 case 0x8: /* Caching page, direct access */
1620 len = resp_caching_pg(ap, pcontrol, target);
1621 offset += len;
1622 break;
1623 case 0xa: /* Control Mode page, all devices */
1624 len = resp_ctrl_m_pg(ap, pcontrol, target);
1625 offset += len;
1626 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627 case 0x19: /* if spc==1 then sas phy, control+discover */
1628 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001629 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001630 return check_condition_result;
1631 }
1632 len = 0;
1633 if ((0x0 == subpcode) || (0xff == subpcode))
1634 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1635 if ((0x1 == subpcode) || (0xff == subpcode))
1636 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1637 target_dev_id);
1638 if ((0x2 == subpcode) || (0xff == subpcode))
1639 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1640 offset += len;
1641 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 case 0x1c: /* Informational Exceptions Mode page, all devices */
1643 len = resp_iec_m_pg(ap, pcontrol, target);
1644 offset += len;
1645 break;
1646 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001647 if ((0 == subpcode) || (0xff == subpcode)) {
1648 len = resp_err_recov_pg(ap, pcontrol, target);
1649 len += resp_disconnect_pg(ap + len, pcontrol, target);
1650 len += resp_format_pg(ap + len, pcontrol, target);
1651 len += resp_caching_pg(ap + len, pcontrol, target);
1652 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1653 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1654 if (0xff == subpcode) {
1655 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1656 target, target_dev_id);
1657 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1658 }
1659 len += resp_iec_m_pg(ap + len, pcontrol, target);
1660 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001661 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001662 return check_condition_result;
1663 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 offset += len;
1665 break;
1666 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001667 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 return check_condition_result;
1669 }
1670 if (msense_6)
1671 arr[0] = offset - 1;
1672 else {
1673 arr[0] = ((offset - 2) >> 8) & 0xff;
1674 arr[1] = (offset - 2) & 0xff;
1675 }
1676 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1677}
1678
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001679#define SDEBUG_MAX_MSELECT_SZ 512
1680
1681static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1682 struct sdebug_dev_info * devip)
1683{
1684 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1685 int param_len, res, errsts, mpage;
1686 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001687 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001688
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001689 errsts = check_readiness(scp, UAS_ONLY, devip);
1690 if (errsts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001691 return errsts;
1692 memset(arr, 0, sizeof(arr));
1693 pf = cmd[1] & 0x10;
1694 sp = cmd[1] & 0x1;
1695 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1696 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001697 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001698 return check_condition_result;
1699 }
1700 res = fetch_to_dev_buffer(scp, arr, param_len);
1701 if (-1 == res)
1702 return (DID_ERROR << 16);
1703 else if ((res < param_len) &&
1704 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001705 sdev_printk(KERN_INFO, scp->device,
1706 "%s: cdb indicated=%d, IO sent=%d bytes\n",
1707 __func__, param_len, res);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001708 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1709 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001710 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001711 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001712 return check_condition_result;
1713 }
1714 off = bd_len + (mselect6 ? 4 : 8);
1715 mpage = arr[off] & 0x3f;
1716 ps = !!(arr[off] & 0x80);
1717 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001718 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001719 return check_condition_result;
1720 }
1721 spf = !!(arr[off] & 0x40);
1722 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1723 (arr[off + 1] + 2);
1724 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001725 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001726 PARAMETER_LIST_LENGTH_ERR, 0);
1727 return check_condition_result;
1728 }
1729 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001730 case 0x8: /* Caching Mode page */
1731 if (caching_pg[1] == arr[off + 1]) {
1732 memcpy(caching_pg + 2, arr + off + 2,
1733 sizeof(caching_pg) - 2);
1734 goto set_mode_changed_ua;
1735 }
1736 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001737 case 0xa: /* Control Mode page */
1738 if (ctrl_m_pg[1] == arr[off + 1]) {
1739 memcpy(ctrl_m_pg + 2, arr + off + 2,
1740 sizeof(ctrl_m_pg) - 2);
1741 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001742 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001743 }
1744 break;
1745 case 0x1c: /* Informational Exceptions Mode page */
1746 if (iec_m_pg[1] == arr[off + 1]) {
1747 memcpy(iec_m_pg + 2, arr + off + 2,
1748 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001749 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001750 }
1751 break;
1752 default:
1753 break;
1754 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001755 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001756 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001757set_mode_changed_ua:
1758 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
1759 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001760}
1761
1762static int resp_temp_l_pg(unsigned char * arr)
1763{
1764 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1765 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1766 };
1767
1768 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1769 return sizeof(temp_l_pg);
1770}
1771
1772static int resp_ie_l_pg(unsigned char * arr)
1773{
1774 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1775 };
1776
1777 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1778 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1779 arr[4] = THRESHOLD_EXCEEDED;
1780 arr[5] = 0xff;
1781 }
1782 return sizeof(ie_l_pg);
1783}
1784
1785#define SDEBUG_MAX_LSENSE_SZ 512
1786
1787static int resp_log_sense(struct scsi_cmnd * scp,
1788 struct sdebug_dev_info * devip)
1789{
Douglas Gilbert23183912006-09-16 20:30:47 -04001790 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001791 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001792 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001793
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001794 errsts = check_readiness(scp, UAS_ONLY, devip);
1795 if (errsts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001796 return errsts;
1797 memset(arr, 0, sizeof(arr));
1798 ppc = cmd[1] & 0x2;
1799 sp = cmd[1] & 0x1;
1800 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001801 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001802 return check_condition_result;
1803 }
1804 pcontrol = (cmd[2] & 0xc0) >> 6;
1805 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001806 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001807 alloc_len = (cmd[7] << 8) + cmd[8];
1808 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001809 if (0 == subpcode) {
1810 switch (pcode) {
1811 case 0x0: /* Supported log pages log page */
1812 n = 4;
1813 arr[n++] = 0x0; /* this page */
1814 arr[n++] = 0xd; /* Temperature */
1815 arr[n++] = 0x2f; /* Informational exceptions */
1816 arr[3] = n - 4;
1817 break;
1818 case 0xd: /* Temperature log page */
1819 arr[3] = resp_temp_l_pg(arr + 4);
1820 break;
1821 case 0x2f: /* Informational exceptions log page */
1822 arr[3] = resp_ie_l_pg(arr + 4);
1823 break;
1824 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001825 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04001826 return check_condition_result;
1827 }
1828 } else if (0xff == subpcode) {
1829 arr[0] |= 0x40;
1830 arr[1] = subpcode;
1831 switch (pcode) {
1832 case 0x0: /* Supported log pages and subpages log page */
1833 n = 4;
1834 arr[n++] = 0x0;
1835 arr[n++] = 0x0; /* 0,0 page */
1836 arr[n++] = 0x0;
1837 arr[n++] = 0xff; /* this page */
1838 arr[n++] = 0xd;
1839 arr[n++] = 0x0; /* Temperature */
1840 arr[n++] = 0x2f;
1841 arr[n++] = 0x0; /* Informational exceptions */
1842 arr[3] = n - 4;
1843 break;
1844 case 0xd: /* Temperature subpages */
1845 n = 4;
1846 arr[n++] = 0xd;
1847 arr[n++] = 0x0; /* Temperature */
1848 arr[3] = n - 4;
1849 break;
1850 case 0x2f: /* Informational exceptions subpages */
1851 n = 4;
1852 arr[n++] = 0x2f;
1853 arr[n++] = 0x0; /* Informational exceptions */
1854 arr[3] = n - 4;
1855 break;
1856 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001857 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04001858 return check_condition_result;
1859 }
1860 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001861 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001862 return check_condition_result;
1863 }
1864 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1865 return fill_from_dev_buffer(scp, arr,
1866 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1867}
1868
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001869static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09001870 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001872 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001873 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 return check_condition_result;
1875 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001876 /* transfer length excessive (tie in to block limits VPD page) */
1877 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001878 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001879 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001880 return check_condition_result;
1881 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001882 return 0;
1883}
1884
Akinobu Mitaa4517512013-07-08 16:01:57 -07001885/* Returns number of bytes copied or -1 if error. */
FUJITA Tomonori19789102008-03-30 00:59:56 +09001886static int do_device_access(struct scsi_cmnd *scmd,
FUJITA Tomonori19789102008-03-30 00:59:56 +09001887 unsigned long long lba, unsigned int num, int write)
1888{
1889 int ret;
Darrick J. Wonga361cc02011-01-31 18:47:54 -08001890 unsigned long long block, rest = 0;
Akinobu Mitaa4517512013-07-08 16:01:57 -07001891 struct scsi_data_buffer *sdb;
1892 enum dma_data_direction dir;
1893 size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
1894 off_t);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001895
Akinobu Mitaa4517512013-07-08 16:01:57 -07001896 if (write) {
1897 sdb = scsi_out(scmd);
1898 dir = DMA_TO_DEVICE;
1899 func = sg_pcopy_to_buffer;
1900 } else {
1901 sdb = scsi_in(scmd);
1902 dir = DMA_FROM_DEVICE;
1903 func = sg_pcopy_from_buffer;
1904 }
1905
1906 if (!sdb->length)
1907 return 0;
1908 if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
1909 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001910
1911 block = do_div(lba, sdebug_store_sectors);
1912 if (block + num > sdebug_store_sectors)
1913 rest = block + num - sdebug_store_sectors;
1914
Akinobu Mitaa4517512013-07-08 16:01:57 -07001915 ret = func(sdb->table.sgl, sdb->table.nents,
1916 fake_storep + (block * scsi_debug_sector_size),
1917 (num - rest) * scsi_debug_sector_size, 0);
1918 if (ret != (num - rest) * scsi_debug_sector_size)
1919 return ret;
1920
1921 if (rest) {
1922 ret += func(sdb->table.sgl, sdb->table.nents,
1923 fake_storep, rest * scsi_debug_sector_size,
1924 (num - rest) * scsi_debug_sector_size);
1925 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001926
1927 return ret;
1928}
1929
Akinobu Mita51d648a2013-09-18 21:27:28 +09001930static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001931{
Akinobu Mita51d648a2013-09-18 21:27:28 +09001932 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001933
Akinobu Mita51d648a2013-09-18 21:27:28 +09001934 if (scsi_debug_guard)
1935 csum = (__force __be16)ip_compute_csum(buf, len);
1936 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001937 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09001938
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001939 return csum;
1940}
1941
1942static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
1943 sector_t sector, u32 ei_lba)
1944{
Akinobu Mita51d648a2013-09-18 21:27:28 +09001945 __be16 csum = dif_compute_csum(data, scsi_debug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001946
1947 if (sdt->guard_tag != csum) {
1948 pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
1949 __func__,
1950 (unsigned long)sector,
1951 be16_to_cpu(sdt->guard_tag),
1952 be16_to_cpu(csum));
1953 return 0x01;
1954 }
1955 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1956 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
1957 pr_err("%s: REF check failed on sector %lu\n",
1958 __func__, (unsigned long)sector);
1959 return 0x03;
1960 }
1961 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1962 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1963 pr_err("%s: REF check failed on sector %lu\n",
1964 __func__, (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001965 return 0x03;
1966 }
1967 return 0;
1968}
1969
Akinobu Mitabb8c0632013-09-18 21:27:25 +09001970static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09001971 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001972{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001973 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001974 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09001975 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001976 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001977
Akinobu Mitae18d8be2013-06-29 17:59:18 +09001978 /* Bytes of protection data to copy into sgl */
1979 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001980
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001981 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
1982 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
1983 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
1984
1985 while (sg_miter_next(&miter) && resid > 0) {
1986 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09001987 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001988 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09001989
1990 if (dif_store_end < start + len)
1991 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001992
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09001993 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09001994
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09001995 if (read)
1996 memcpy(paddr, start, len - rest);
1997 else
1998 memcpy(start, paddr, len - rest);
1999
2000 if (rest) {
2001 if (read)
2002 memcpy(paddr + len - rest, dif_storep, rest);
2003 else
2004 memcpy(dif_storep, paddr + len - rest, rest);
2005 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002006
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002007 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002008 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002009 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002010 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002011}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002012
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002013static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2014 unsigned int sectors, u32 ei_lba)
2015{
2016 unsigned int i;
2017 struct sd_dif_tuple *sdt;
2018 sector_t sector;
2019
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002020 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002021 int ret;
2022
2023 sector = start_sec + i;
2024 sdt = dif_store(sector);
2025
Akinobu Mita51d648a2013-09-18 21:27:28 +09002026 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002027 continue;
2028
2029 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2030 if (ret) {
2031 dif_errors++;
2032 return ret;
2033 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002034 }
2035
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002036 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002037 dix_reads++;
2038
2039 return 0;
2040}
2041
FUJITA Tomonori19789102008-03-30 00:59:56 +09002042static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002043 unsigned int num, u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002044{
2045 unsigned long iflags;
2046 int ret;
2047
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002048 ret = check_device_access_params(SCpnt, lba, num);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002049 if (ret)
2050 return ret;
2051
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002053 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002054 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
2055 /* claim unrecoverable read error */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002056 mk_sense_buffer(SCpnt, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002057 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002058 if (0x70 == (SCpnt->sense_buffer[0] & 0x7f)) {
2059 SCpnt->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002060 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2061 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002062 SCpnt->sense_buffer[3] = (ret >> 24) & 0xff;
2063 SCpnt->sense_buffer[4] = (ret >> 16) & 0xff;
2064 SCpnt->sense_buffer[5] = (ret >> 8) & 0xff;
2065 SCpnt->sense_buffer[6] = ret & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002066 }
Douglas Gilberta87e3a62010-12-17 19:16:06 -05002067 scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 return check_condition_result;
2069 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002070
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002071 read_lock_irqsave(&atomic_rw, iflags);
2072
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002073 /* DIX + T10 DIF */
2074 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002075 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002076
2077 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002078 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002079 mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002080 return illegal_condition_result;
2081 }
2082 }
2083
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002084 ret = do_device_access(SCpnt, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 read_unlock_irqrestore(&atomic_rw, iflags);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002086 if (ret == -1)
2087 return DID_ERROR << 16;
2088
2089 scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret;
2090
2091 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092}
2093
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002094void dump_sector(unsigned char *buf, int len)
2095{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002096 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002097
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002098 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002099 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002100 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002101
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002102 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002103 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002104
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002105 if (c >= 0x20 && c < 0x7e)
2106 n += scnprintf(b + n, sizeof(b) - n,
2107 " %c ", buf[i+j]);
2108 else
2109 n += scnprintf(b + n, sizeof(b) - n,
2110 "%02x ", buf[i+j]);
2111 }
2112 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002113 }
2114}
2115
2116static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002117 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002118{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002119 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002120 struct sd_dif_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002121 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002122 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002123 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002124 int dpage_offset;
2125 struct sg_mapping_iter diter;
2126 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002127
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002128 BUG_ON(scsi_sg_count(SCpnt) == 0);
2129 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2130
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002131 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2132 scsi_prot_sg_count(SCpnt),
2133 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2134 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2135 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002136
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002137 /* For each protection page */
2138 while (sg_miter_next(&piter)) {
2139 dpage_offset = 0;
2140 if (WARN_ON(!sg_miter_next(&diter))) {
2141 ret = 0x01;
2142 goto out;
2143 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002144
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002145 for (ppage_offset = 0; ppage_offset < piter.length;
2146 ppage_offset += sizeof(struct sd_dif_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002147 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002148 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002149 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002150 if (dpage_offset >= diter.length) {
2151 if (WARN_ON(!sg_miter_next(&diter))) {
2152 ret = 0x01;
2153 goto out;
2154 }
2155 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002156 }
2157
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002158 sdt = piter.addr + ppage_offset;
2159 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002160
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002161 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002162 if (ret) {
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002163 dump_sector(daddr, scsi_debug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002164 goto out;
2165 }
2166
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002167 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002168 ei_lba++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002169 dpage_offset += scsi_debug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002170 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002171 diter.consumed = dpage_offset;
2172 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002173 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002174 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002175
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002176 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002177 dix_writes++;
2178
2179 return 0;
2180
2181out:
2182 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002183 sg_miter_stop(&diter);
2184 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002185 return ret;
2186}
2187
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002188static unsigned long lba_to_map_index(sector_t lba)
2189{
2190 if (scsi_debug_unmap_alignment) {
2191 lba += scsi_debug_unmap_granularity -
2192 scsi_debug_unmap_alignment;
2193 }
2194 do_div(lba, scsi_debug_unmap_granularity);
2195
2196 return lba;
2197}
2198
2199static sector_t map_index_to_lba(unsigned long index)
2200{
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002201 sector_t lba = index * scsi_debug_unmap_granularity;
2202
2203 if (scsi_debug_unmap_alignment) {
2204 lba -= scsi_debug_unmap_granularity -
2205 scsi_debug_unmap_alignment;
2206 }
2207
2208 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002209}
2210
Martin K. Petersen44d92692009-10-15 14:45:27 -04002211static unsigned int map_state(sector_t lba, unsigned int *num)
2212{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002213 sector_t end;
2214 unsigned int mapped;
2215 unsigned long index;
2216 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002217
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002218 index = lba_to_map_index(lba);
2219 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002220
2221 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002222 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002223 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002224 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002225
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002226 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002227 *num = end - lba;
2228
2229 return mapped;
2230}
2231
2232static void map_region(sector_t lba, unsigned int len)
2233{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002234 sector_t end = lba + len;
2235
Martin K. Petersen44d92692009-10-15 14:45:27 -04002236 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002237 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002238
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002239 if (index < map_size)
2240 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002241
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002242 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002243 }
2244}
2245
2246static void unmap_region(sector_t lba, unsigned int len)
2247{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002248 sector_t end = lba + len;
2249
Martin K. Petersen44d92692009-10-15 14:45:27 -04002250 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002251 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002252
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002253 if (lba == map_index_to_lba(index) &&
2254 lba + scsi_debug_unmap_granularity <= end &&
2255 index < map_size) {
2256 clear_bit(index, map_storep);
2257 if (scsi_debug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002258 memset(fake_storep +
Akinobu Mitacc34a8e2013-04-16 22:11:57 +09002259 lba * scsi_debug_sector_size, 0,
2260 scsi_debug_sector_size *
2261 scsi_debug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002262 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002263 if (dif_storep) {
2264 memset(dif_storep + lba, 0xff,
2265 sizeof(*dif_storep) *
2266 scsi_debug_unmap_granularity);
2267 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002268 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002269 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002270 }
2271}
2272
FUJITA Tomonori19789102008-03-30 00:59:56 +09002273static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002274 unsigned int num, u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275{
2276 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002277 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002279 ret = check_device_access_params(SCpnt, lba, num);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002280 if (ret)
2281 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002283 write_lock_irqsave(&atomic_rw, iflags);
2284
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002285 /* DIX + T10 DIF */
2286 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002287 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002288
2289 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002290 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002291 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10,
2292 prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002293 return illegal_condition_result;
2294 }
2295 }
2296
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002297 ret = do_device_access(SCpnt, lba, num, 1);
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002298 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002299 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002301 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002303 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002305 sdev_printk(KERN_INFO, SCpnt->device,
2306 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
2307 my_name, num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 return 0;
2310}
2311
Martin K. Petersen44d92692009-10-15 14:45:27 -04002312static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002313 unsigned int num, u32 ei_lba, unsigned int unmap)
Martin K. Petersen44d92692009-10-15 14:45:27 -04002314{
2315 unsigned long iflags;
2316 unsigned long long i;
2317 int ret;
2318
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002319 ret = check_device_access_params(scmd, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002320 if (ret)
2321 return ret;
2322
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002323 if (num > scsi_debug_write_same_length) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002324 mk_sense_buffer(scmd, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002325 0);
2326 return check_condition_result;
2327 }
2328
Martin K. Petersen44d92692009-10-15 14:45:27 -04002329 write_lock_irqsave(&atomic_rw, iflags);
2330
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002331 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002332 unmap_region(lba, num);
2333 goto out;
2334 }
2335
2336 /* Else fetch one logical block */
2337 ret = fetch_to_dev_buffer(scmd,
2338 fake_storep + (lba * scsi_debug_sector_size),
2339 scsi_debug_sector_size);
2340
2341 if (-1 == ret) {
2342 write_unlock_irqrestore(&atomic_rw, iflags);
2343 return (DID_ERROR << 16);
2344 } else if ((ret < (num * scsi_debug_sector_size)) &&
2345 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002346 sdev_printk(KERN_INFO, scmd->device,
2347 "%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
2348 my_name, "write same",
2349 num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002350
2351 /* Copy first sector to remaining blocks */
2352 for (i = 1 ; i < num ; i++)
2353 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2354 fake_storep + (lba * scsi_debug_sector_size),
2355 scsi_debug_sector_size);
2356
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002357 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002358 map_region(lba, num);
2359out:
2360 write_unlock_irqrestore(&atomic_rw, iflags);
2361
2362 return 0;
2363}
2364
2365struct unmap_block_desc {
2366 __be64 lba;
2367 __be32 blocks;
2368 __be32 __reserved;
2369};
2370
2371static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2372{
2373 unsigned char *buf;
2374 struct unmap_block_desc *desc;
2375 unsigned int i, payload_len, descriptors;
2376 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002377 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002378
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002379 ret = check_readiness(scmd, UAS_ONLY, devip);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002380 if (ret)
2381 return ret;
2382
2383 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2384 BUG_ON(scsi_bufflen(scmd) != payload_len);
2385
2386 descriptors = (payload_len - 8) / 16;
2387
2388 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2389 if (!buf)
2390 return check_condition_result;
2391
2392 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2393
2394 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2395 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2396
2397 desc = (void *)&buf[8];
2398
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002399 write_lock_irqsave(&atomic_rw, iflags);
2400
Martin K. Petersen44d92692009-10-15 14:45:27 -04002401 for (i = 0 ; i < descriptors ; i++) {
2402 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2403 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2404
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002405 ret = check_device_access_params(scmd, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002406 if (ret)
2407 goto out;
2408
2409 unmap_region(lba, num);
2410 }
2411
2412 ret = 0;
2413
2414out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002415 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002416 kfree(buf);
2417
2418 return ret;
2419}
2420
2421#define SDEBUG_GET_LBA_STATUS_LEN 32
2422
2423static int resp_get_lba_status(struct scsi_cmnd * scmd,
2424 struct sdebug_dev_info * devip)
2425{
2426 unsigned long long lba;
2427 unsigned int alloc_len, mapped, num;
2428 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2429 int ret;
2430
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002431 ret = check_readiness(scmd, UAS_ONLY, devip);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002432 if (ret)
2433 return ret;
2434
2435 lba = get_unaligned_be64(&scmd->cmnd[2]);
2436 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2437
2438 if (alloc_len < 24)
2439 return 0;
2440
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002441 ret = check_device_access_params(scmd, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002442 if (ret)
2443 return ret;
2444
2445 mapped = map_state(lba, &num);
2446
2447 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertde13e962012-01-19 19:30:00 -05002448 put_unaligned_be32(20, &arr[0]); /* Parameter Data Length */
Martin K. Petersen44d92692009-10-15 14:45:27 -04002449 put_unaligned_be64(lba, &arr[8]); /* LBA */
2450 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2451 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2452
2453 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2454}
2455
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002456#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
2458static int resp_report_luns(struct scsi_cmnd * scp,
2459 struct sdebug_dev_info * devip)
2460{
2461 unsigned int alloc_len;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002462 int lun_cnt, i, upper, num, n, want_wlun, shortish;
2463 u64 lun;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002464 unsigned char *cmd = scp->cmnd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 int select_report = (int)cmd[2];
2466 struct scsi_lun *one_lun;
2467 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002468 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
2470 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002471 shortish = (alloc_len < 4);
2472 if (shortish || (select_report > 2)) {
2473 mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 return check_condition_result;
2475 }
2476 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2477 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2478 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002479 if (1 == select_report)
2480 lun_cnt = 0;
2481 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2482 --lun_cnt;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002483 want_wlun = (select_report > 0) ? 1 : 0;
2484 num = lun_cnt + want_wlun;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002485 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2486 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2487 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2488 sizeof(struct scsi_lun)), num);
2489 if (n < num) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002490 want_wlun = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002491 lun_cnt = n;
2492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002494 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2495 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2496 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2497 i++, lun++) {
2498 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 if (upper)
2500 one_lun[i].scsi_lun[0] =
2501 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002502 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002504 if (want_wlun) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002505 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2506 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2507 i++;
2508 }
2509 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 return fill_from_dev_buffer(scp, arr,
2511 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2512}
2513
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002514static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2515 unsigned int num, struct sdebug_dev_info *devip)
2516{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002517 int j;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002518 unsigned char *kaddr, *buf;
2519 unsigned int offset;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002520 struct scsi_data_buffer *sdb = scsi_in(scp);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002521 struct sg_mapping_iter miter;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002522
2523 /* better not to use temporary buffer. */
2524 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09002525 if (!buf) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002526 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
2527 INSUFF_RES_ASCQ);
Akinobu Mitac5af0db2014-02-26 22:57:01 +09002528 return check_condition_result;
2529 }
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002530
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002531 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002532
2533 offset = 0;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002534 sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
2535 SG_MITER_ATOMIC | SG_MITER_TO_SG);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002536
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002537 while (sg_miter_next(&miter)) {
2538 kaddr = miter.addr;
2539 for (j = 0; j < miter.length; j++)
2540 *(kaddr + j) ^= *(buf + offset + j);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002541
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002542 offset += miter.length;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002543 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002544 sg_miter_stop(&miter);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002545 kfree(buf);
2546
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002547 return 0;
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002548}
2549
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002550/* When timer or tasklet goes off this function is called. */
2551static void sdebug_q_cmd_complete(unsigned long indx)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002553 int qa_indx;
2554 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002556 struct sdebug_queued_cmd *sqcp;
2557 struct scsi_cmnd *scp;
2558 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002560 atomic_inc(&sdebug_completions);
2561 qa_indx = indx;
2562 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
2563 pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 return;
2565 }
2566 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002567 sqcp = &queued_arr[qa_indx];
2568 scp = sqcp->a_cmnd;
2569 if (NULL == scp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002571 pr_err("%s: scp is NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 return;
2573 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002574 devip = (struct sdebug_dev_info *)scp->device->hostdata;
2575 if (devip)
2576 atomic_dec(&devip->num_in_q);
2577 else
2578 pr_err("%s: devip=NULL\n", __func__);
2579 if (atomic_read(&retired_max_queue) > 0)
2580 retiring = 1;
2581
2582 sqcp->a_cmnd = NULL;
2583 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
2584 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2585 pr_err("%s: Unexpected completion\n", __func__);
2586 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002588
2589 if (unlikely(retiring)) { /* user has reduced max_queue */
2590 int k, retval;
2591
2592 retval = atomic_read(&retired_max_queue);
2593 if (qa_indx >= retval) {
2594 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2595 pr_err("%s: index %d too large\n", __func__, retval);
2596 return;
2597 }
2598 k = find_last_bit(queued_in_use_bm, retval);
2599 if ((k < scsi_debug_max_queue) || (k == retval))
2600 atomic_set(&retired_max_queue, 0);
2601 else
2602 atomic_set(&retired_max_queue, k + 1);
2603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002605 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606}
2607
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002608/* When high resolution timer goes off this function is called. */
2609static enum hrtimer_restart
2610sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
2611{
2612 int qa_indx;
2613 int retiring = 0;
2614 unsigned long iflags;
2615 struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer;
2616 struct sdebug_queued_cmd *sqcp;
2617 struct scsi_cmnd *scp;
2618 struct sdebug_dev_info *devip;
2619
2620 atomic_inc(&sdebug_completions);
2621 qa_indx = sd_hrtp->qa_indx;
2622 if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) {
2623 pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx);
2624 goto the_end;
2625 }
2626 spin_lock_irqsave(&queued_arr_lock, iflags);
2627 sqcp = &queued_arr[qa_indx];
2628 scp = sqcp->a_cmnd;
2629 if (NULL == scp) {
2630 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2631 pr_err("%s: scp is NULL\n", __func__);
2632 goto the_end;
2633 }
2634 devip = (struct sdebug_dev_info *)scp->device->hostdata;
2635 if (devip)
2636 atomic_dec(&devip->num_in_q);
2637 else
2638 pr_err("%s: devip=NULL\n", __func__);
2639 if (atomic_read(&retired_max_queue) > 0)
2640 retiring = 1;
2641
2642 sqcp->a_cmnd = NULL;
2643 if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) {
2644 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2645 pr_err("%s: Unexpected completion\n", __func__);
2646 goto the_end;
2647 }
2648
2649 if (unlikely(retiring)) { /* user has reduced max_queue */
2650 int k, retval;
2651
2652 retval = atomic_read(&retired_max_queue);
2653 if (qa_indx >= retval) {
2654 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2655 pr_err("%s: index %d too large\n", __func__, retval);
2656 goto the_end;
2657 }
2658 k = find_last_bit(queued_in_use_bm, retval);
2659 if ((k < scsi_debug_max_queue) || (k == retval))
2660 atomic_set(&retired_max_queue, 0);
2661 else
2662 atomic_set(&retired_max_queue, k + 1);
2663 }
2664 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2665 scp->scsi_done(scp); /* callback to mid level */
2666the_end:
2667 return HRTIMER_NORESTART;
2668}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002670static struct sdebug_dev_info *
2671sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002672{
2673 struct sdebug_dev_info *devip;
2674
2675 devip = kzalloc(sizeof(*devip), flags);
2676 if (devip) {
2677 devip->sdbg_host = sdbg_host;
2678 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2679 }
2680 return devip;
2681}
2682
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2684{
2685 struct sdebug_host_info * sdbg_host;
2686 struct sdebug_dev_info * open_devip = NULL;
2687 struct sdebug_dev_info * devip =
2688 (struct sdebug_dev_info *)sdev->hostdata;
2689
2690 if (devip)
2691 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002692 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2693 if (!sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002694 pr_err("%s: Host info NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 return NULL;
2696 }
2697 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2698 if ((devip->used) && (devip->channel == sdev->channel) &&
2699 (devip->target == sdev->id) &&
2700 (devip->lun == sdev->lun))
2701 return devip;
2702 else {
2703 if ((!devip->used) && (!open_devip))
2704 open_devip = devip;
2705 }
2706 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002707 if (!open_devip) { /* try and make a new one */
2708 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2709 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002711 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 return NULL;
2713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002715
2716 open_devip->channel = sdev->channel;
2717 open_devip->target = sdev->id;
2718 open_devip->lun = sdev->lun;
2719 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002720 atomic_set(&open_devip->num_in_q, 0);
2721 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002722 open_devip->used = 1;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002723 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2724 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2725
2726 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727}
2728
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002729static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002731 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02002732 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002733 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002734 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002735 return 0;
2736}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002738static int scsi_debug_slave_configure(struct scsi_device *sdp)
2739{
2740 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002741
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02002743 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002744 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2745 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2746 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2747 devip = devInfoReg(sdp);
2748 if (NULL == devip)
2749 return 1; /* no resources, will be marked offline */
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01002750 sdp->hostdata = devip;
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09002751 blk_queue_max_segment_size(sdp->request_queue, -1U);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002752 if (scsi_debug_no_uld)
2753 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002754 return 0;
2755}
2756
2757static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2758{
2759 struct sdebug_dev_info *devip =
2760 (struct sdebug_dev_info *)sdp->hostdata;
2761
2762 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02002763 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002764 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2765 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002766 /* make this slot available for re-use */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002767 devip->used = 0;
2768 sdp->hostdata = NULL;
2769 }
2770}
2771
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002772/* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002773static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2774{
2775 unsigned long iflags;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002776 int k, qmax, r_qmax;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002777 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002778 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002779
2780 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002781 qmax = scsi_debug_max_queue;
2782 r_qmax = atomic_read(&retired_max_queue);
2783 if (r_qmax > qmax)
2784 qmax = r_qmax;
2785 for (k = 0; k < qmax; ++k) {
2786 if (test_bit(k, queued_in_use_bm)) {
2787 sqcp = &queued_arr[k];
2788 if (cmnd == sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002789 devip = (struct sdebug_dev_info *)
2790 cmnd->device->hostdata;
2791 if (devip)
2792 atomic_dec(&devip->num_in_q);
2793 sqcp->a_cmnd = NULL;
2794 spin_unlock_irqrestore(&queued_arr_lock,
2795 iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002796 if (scsi_debug_ndelay > 0) {
2797 if (sqcp->sd_hrtp)
2798 hrtimer_cancel(
2799 &sqcp->sd_hrtp->hrt);
2800 } else if (scsi_debug_delay > 0) {
2801 if (sqcp->cmnd_timerp)
2802 del_timer_sync(
2803 sqcp->cmnd_timerp);
2804 } else if (scsi_debug_delay < 0) {
2805 if (sqcp->tletp)
2806 tasklet_kill(sqcp->tletp);
2807 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002808 clear_bit(k, queued_in_use_bm);
2809 return 1;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002810 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002811 }
2812 }
2813 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002814 return 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002815}
2816
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002817/* Deletes (stops) timers or tasklets of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002818static void stop_all_queued(void)
2819{
2820 unsigned long iflags;
2821 int k;
2822 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002823 struct sdebug_dev_info *devip;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002824
2825 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002826 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2827 if (test_bit(k, queued_in_use_bm)) {
2828 sqcp = &queued_arr[k];
2829 if (sqcp->a_cmnd) {
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002830 devip = (struct sdebug_dev_info *)
2831 sqcp->a_cmnd->device->hostdata;
2832 if (devip)
2833 atomic_dec(&devip->num_in_q);
2834 sqcp->a_cmnd = NULL;
2835 spin_unlock_irqrestore(&queued_arr_lock,
2836 iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002837 if (scsi_debug_ndelay > 0) {
2838 if (sqcp->sd_hrtp)
2839 hrtimer_cancel(
2840 &sqcp->sd_hrtp->hrt);
2841 } else if (scsi_debug_delay > 0) {
2842 if (sqcp->cmnd_timerp)
2843 del_timer_sync(
2844 sqcp->cmnd_timerp);
2845 } else if (scsi_debug_delay < 0) {
2846 if (sqcp->tletp)
2847 tasklet_kill(sqcp->tletp);
2848 }
Douglas Gilbertdb525fc2014-08-31 19:09:59 -04002849 clear_bit(k, queued_in_use_bm);
2850 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002851 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002852 }
2853 }
2854 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855}
2856
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002857/* Free queued command memory on heap */
2858static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002860 unsigned long iflags;
2861 int k;
2862 struct sdebug_queued_cmd *sqcp;
2863
2864 spin_lock_irqsave(&queued_arr_lock, iflags);
2865 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2866 sqcp = &queued_arr[k];
2867 kfree(sqcp->cmnd_timerp);
2868 sqcp->cmnd_timerp = NULL;
2869 kfree(sqcp->tletp);
2870 sqcp->tletp = NULL;
2871 kfree(sqcp->sd_hrtp);
2872 sqcp->sd_hrtp = NULL;
2873 }
2874 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875}
2876
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002877static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002879 ++num_aborts;
2880 if (SCpnt) {
2881 if (SCpnt->device &&
2882 (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
2883 sdev_printk(KERN_INFO, SCpnt->device, "%s\n",
2884 __func__);
2885 stop_queued_cmnd(SCpnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002887 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888}
2889
2890static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2891{
2892 struct sdebug_dev_info * devip;
2893
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002895 if (SCpnt && SCpnt->device) {
2896 struct scsi_device *sdp = SCpnt->device;
2897
2898 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2899 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2900 devip = devInfoReg(sdp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002902 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 }
2904 return SUCCESS;
2905}
2906
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002907static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
2908{
2909 struct sdebug_host_info *sdbg_host;
2910 struct sdebug_dev_info *devip;
2911 struct scsi_device *sdp;
2912 struct Scsi_Host *hp;
2913 int k = 0;
2914
2915 ++num_target_resets;
2916 if (!SCpnt)
2917 goto lie;
2918 sdp = SCpnt->device;
2919 if (!sdp)
2920 goto lie;
2921 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2922 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2923 hp = sdp->host;
2924 if (!hp)
2925 goto lie;
2926 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
2927 if (sdbg_host) {
2928 list_for_each_entry(devip,
2929 &sdbg_host->dev_info_list,
2930 dev_list)
2931 if (devip->target == sdp->id) {
2932 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2933 ++k;
2934 }
2935 }
2936 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2937 sdev_printk(KERN_INFO, sdp,
2938 "%s: %d device(s) found in target\n", __func__, k);
2939lie:
2940 return SUCCESS;
2941}
2942
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2944{
2945 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002946 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 struct scsi_device * sdp;
2948 struct Scsi_Host * hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002949 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002952 if (!(SCpnt && SCpnt->device))
2953 goto lie;
2954 sdp = SCpnt->device;
2955 if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)
2956 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
2957 hp = sdp->host;
2958 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002959 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002961 list_for_each_entry(devip,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002963 dev_list) {
2964 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2965 ++k;
2966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 }
2968 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002969 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2970 sdev_printk(KERN_INFO, sdp,
2971 "%s: %d device(s) found in host\n", __func__, k);
2972lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 return SUCCESS;
2974}
2975
2976static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2977{
2978 struct sdebug_host_info * sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002979 struct sdebug_dev_info *devip;
2980 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 ++num_host_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002983 if ((SCpnt->device) && (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts))
2984 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 spin_lock(&sdebug_host_list_lock);
2986 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002987 list_for_each_entry(devip, &sdbg_host->dev_info_list,
2988 dev_list) {
2989 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
2990 ++k;
2991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 }
2993 spin_unlock(&sdebug_host_list_lock);
2994 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002995 if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts)
2996 sdev_printk(KERN_INFO, SCpnt->device,
2997 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 return SUCCESS;
2999}
3000
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003001static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003002 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003{
3004 struct partition * pp;
3005 int starts[SDEBUG_MAX_PARTS + 2];
3006 int sectors_per_part, num_sectors, k;
3007 int heads_by_sects, start_sec, end_sec;
3008
3009 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003010 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 return;
3012 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
3013 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003014 pr_warn("%s: reducing partitions to %d\n", __func__,
3015 SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003017 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 sectors_per_part = (num_sectors - sdebug_sectors_per)
3019 / scsi_debug_num_parts;
3020 heads_by_sects = sdebug_heads * sdebug_sectors_per;
3021 starts[0] = sdebug_sectors_per;
3022 for (k = 1; k < scsi_debug_num_parts; ++k)
3023 starts[k] = ((k * sectors_per_part) / heads_by_sects)
3024 * heads_by_sects;
3025 starts[scsi_debug_num_parts] = num_sectors;
3026 starts[scsi_debug_num_parts + 1] = 0;
3027
3028 ramp[510] = 0x55; /* magic partition markings */
3029 ramp[511] = 0xAA;
3030 pp = (struct partition *)(ramp + 0x1be);
3031 for (k = 0; starts[k + 1]; ++k, ++pp) {
3032 start_sec = starts[k];
3033 end_sec = starts[k + 1] - 1;
3034 pp->boot_ind = 0;
3035
3036 pp->cyl = start_sec / heads_by_sects;
3037 pp->head = (start_sec - (pp->cyl * heads_by_sects))
3038 / sdebug_sectors_per;
3039 pp->sector = (start_sec % sdebug_sectors_per) + 1;
3040
3041 pp->end_cyl = end_sec / heads_by_sects;
3042 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
3043 / sdebug_sectors_per;
3044 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
3045
Akinobu Mita150c3542013-08-26 22:08:40 +09003046 pp->start_sect = cpu_to_le32(start_sec);
3047 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 pp->sys_ind = 0x83; /* plain Linux partition */
3049 }
3050}
3051
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003052static int
3053schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
3054 int scsi_result, int delta_jiff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003056 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003057 int k, num_in_q, qdepth, inject;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003058 struct sdebug_queued_cmd *sqcp = NULL;
3059 struct scsi_device *sdp = cmnd->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003061 if (NULL == cmnd || NULL == devip) {
3062 pr_warn("%s: called with NULL cmnd or devip pointer\n",
3063 __func__);
3064 /* no particularly good error to report back */
3065 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003067 if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
3068 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
3069 __func__, scsi_result);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003070 if (delta_jiff == 0)
3071 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003073 /* schedule the response at a later time if resources permit */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003074 spin_lock_irqsave(&queued_arr_lock, iflags);
3075 num_in_q = atomic_read(&devip->num_in_q);
3076 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003077 inject = 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003078 if ((qdepth > 0) && (num_in_q >= qdepth)) {
3079 if (scsi_result) {
3080 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3081 goto respond_in_thread;
3082 } else
3083 scsi_result = device_qfull_result;
3084 } else if ((scsi_debug_every_nth != 0) &&
3085 (SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) &&
3086 (scsi_result == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003087 if ((num_in_q == (qdepth - 1)) &&
3088 (atomic_inc_return(&sdebug_a_tsf) >=
3089 abs(scsi_debug_every_nth))) {
3090 atomic_set(&sdebug_a_tsf, 0);
3091 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003092 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003094 }
3095
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003096 k = find_first_zero_bit(queued_in_use_bm, scsi_debug_max_queue);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003097 if (k >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003099 if (scsi_result)
3100 goto respond_in_thread;
3101 else if (SCSI_DEBUG_OPT_ALL_TSF & scsi_debug_opts)
3102 scsi_result = device_qfull_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003103 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts)
3104 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003105 "%s: max_queue=%d exceeded, %s\n",
3106 __func__, scsi_debug_max_queue,
3107 (scsi_result ? "status: TASK SET FULL" :
3108 "report: host busy"));
3109 if (scsi_result)
3110 goto respond_in_thread;
3111 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003112 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003114 __set_bit(k, queued_in_use_bm);
3115 atomic_inc(&devip->num_in_q);
3116 sqcp = &queued_arr[k];
3117 sqcp->a_cmnd = cmnd;
3118 cmnd->result = scsi_result;
3119 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3120 if (delta_jiff > 0) {
3121 if (NULL == sqcp->cmnd_timerp) {
3122 sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list),
3123 GFP_ATOMIC);
3124 if (NULL == sqcp->cmnd_timerp)
3125 return SCSI_MLQUEUE_HOST_BUSY;
3126 init_timer(sqcp->cmnd_timerp);
3127 }
3128 sqcp->cmnd_timerp->function = sdebug_q_cmd_complete;
3129 sqcp->cmnd_timerp->data = k;
3130 sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff;
3131 add_timer(sqcp->cmnd_timerp);
3132 } else if (scsi_debug_ndelay > 0) {
3133 ktime_t kt = ktime_set(0, scsi_debug_ndelay);
3134 struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp;
3135
3136 if (NULL == sd_hp) {
3137 sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC);
3138 if (NULL == sd_hp)
3139 return SCSI_MLQUEUE_HOST_BUSY;
3140 sqcp->sd_hrtp = sd_hp;
3141 hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC,
3142 HRTIMER_MODE_REL);
3143 sd_hp->hrt.function = sdebug_q_cmd_hrt_complete;
3144 sd_hp->qa_indx = k;
3145 }
3146 hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL);
3147 } else { /* delay < 0 */
3148 if (NULL == sqcp->tletp) {
3149 sqcp->tletp = kmalloc(sizeof(*sqcp->tletp),
3150 GFP_ATOMIC);
3151 if (NULL == sqcp->tletp)
3152 return SCSI_MLQUEUE_HOST_BUSY;
3153 tasklet_init(sqcp->tletp,
3154 sdebug_q_cmd_complete, k);
3155 }
3156 if (-1 == delta_jiff)
3157 tasklet_hi_schedule(sqcp->tletp);
3158 else
3159 tasklet_schedule(sqcp->tletp);
3160 }
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003161 if ((SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) &&
3162 (scsi_result == device_qfull_result))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003163 sdev_printk(KERN_INFO, sdp,
3164 "%s: num_in_q=%d +1, %s%s\n", __func__,
3165 num_in_q, (inject ? "<inject> " : ""),
3166 "status: TASK SET FULL");
3167 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02003168
3169respond_in_thread: /* call back to mid-layer using invocation thread */
3170 cmnd->result = scsi_result;
3171 cmnd->scsi_done(cmnd);
3172 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003174
Douglas Gilbert23183912006-09-16 20:30:47 -04003175/* Note: The following macros create attribute files in the
3176 /sys/module/scsi_debug/parameters directory. Unfortunately this
3177 driver is unaware of a change and cannot trigger auxiliary actions
3178 as it can when the corresponding attribute in the
3179 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
3180 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003181module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003182module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Akinobu Mita0759c662014-02-26 22:57:04 +09003183module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003184module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
3185module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003186module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
3187module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003188module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
3189module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04003190module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Akinobu Mita68aee7b2013-09-18 21:27:27 +09003191module_param_named(guard, scsi_debug_guard, uint, S_IRUGO);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003192module_param_named(host_lock, scsi_debug_host_lock, bool, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003193module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
3194module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
3195module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003196module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003197module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003198module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003199module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003200module_param_named(ndelay, scsi_debug_ndelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003201module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003202module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003203module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
3204module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003205module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003206module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003207module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003208module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
Martin Pittd9867882012-09-06 12:04:33 +02003209module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003210module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003211module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
3212module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
3213module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
3214module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
3215module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003216module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04003217module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
3218 S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003219module_param_named(write_same_length, scsi_debug_write_same_length, int,
3220 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
3222MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
3223MODULE_DESCRIPTION("SCSI debug adapter driver");
3224MODULE_LICENSE("GPL");
3225MODULE_VERSION(SCSI_DEBUG_VERSION);
3226
3227MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003228MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Akinobu Mita0759c662014-02-26 22:57:04 +09003229MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003230MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003231MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003232MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
3233MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003234MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07003235MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04003236MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003237MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003238MODULE_PARM_DESC(host_lock, "use host_lock around all commands (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003239MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
3240MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
3241MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06003242MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003243MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003244MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003245MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
3246MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003247MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003248MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003250MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003251MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05003252MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003253MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02003255MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilberte46b0342014-08-05 12:21:53 +02003256MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003257MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003258MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
3259MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04003260MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
3261MODULE_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 -05003262MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
3263MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
3264MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
3266static char sdebug_info[256];
3267
3268static const char * scsi_debug_info(struct Scsi_Host * shp)
3269{
3270 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
3271 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
3272 scsi_debug_version_date, scsi_debug_dev_size_mb,
3273 scsi_debug_opts);
3274 return sdebug_info;
3275}
3276
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003277/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Al Viroc8ed5552013-03-31 01:46:06 -04003278static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279{
Al Viroc8ed5552013-03-31 01:46:06 -04003280 char arr[16];
3281 int opts;
3282 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
Al Viroc8ed5552013-03-31 01:46:06 -04003284 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
3285 return -EACCES;
3286 memcpy(arr, buffer, minLen);
3287 arr[minLen] = '\0';
3288 if (1 != sscanf(arr, "%d", &opts))
3289 return -EINVAL;
3290 scsi_debug_opts = opts;
3291 if (scsi_debug_every_nth != 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003292 atomic_set(&sdebug_cmnd_count, 0);
Al Viroc8ed5552013-03-31 01:46:06 -04003293 return length;
3294}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003296/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
3297 * same for each scsi_debug host (if more than one). Some of the counters
3298 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04003299static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
3300{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003301 int f, l;
3302 char b[32];
3303
3304 if (scsi_debug_every_nth > 0)
3305 snprintf(b, sizeof(b), " (curr:%d)",
3306 ((SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) ?
3307 atomic_read(&sdebug_a_tsf) :
3308 atomic_read(&sdebug_cmnd_count)));
3309 else
3310 b[0] = '\0';
3311
3312 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n"
3313 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
3314 "every_nth=%d%s\n"
3315 "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n"
3316 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
3317 "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, "
3318 "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d "
3319 "usec_in_jiffy=%lu\n",
3320 SCSI_DEBUG_VERSION, scsi_debug_version_date,
3321 scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts,
3322 scsi_debug_every_nth, b, scsi_debug_delay, scsi_debug_ndelay,
3323 scsi_debug_max_luns, atomic_read(&sdebug_completions),
3324 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
3325 sdebug_sectors_per, num_aborts, num_dev_resets,
3326 num_target_resets, num_bus_resets, num_host_resets,
3327 dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000);
3328
3329 f = find_first_bit(queued_in_use_bm, scsi_debug_max_queue);
3330 if (f != scsi_debug_max_queue) {
3331 l = find_last_bit(queued_in_use_bm, scsi_debug_max_queue);
3332 seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n",
3333 "queued_in_use_bm", f, l);
3334 }
Al Viroc8ed5552013-03-31 01:46:06 -04003335 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336}
3337
Akinobu Mita82069372013-10-14 22:48:04 +09003338static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339{
3340 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
3341}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003342/* Returns -EBUSY if delay is being changed and commands are queued */
Akinobu Mita82069372013-10-14 22:48:04 +09003343static ssize_t delay_store(struct device_driver *ddp, const char *buf,
3344 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003346 int delay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003348 if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) {
3349 res = count;
3350 if (scsi_debug_delay != delay) {
3351 unsigned long iflags;
3352 int k;
3353
3354 spin_lock_irqsave(&queued_arr_lock, iflags);
3355 k = find_first_bit(queued_in_use_bm,
3356 scsi_debug_max_queue);
3357 if (k != scsi_debug_max_queue)
3358 res = -EBUSY; /* have queued commands */
3359 else {
3360 scsi_debug_delay = delay;
3361 scsi_debug_ndelay = 0;
3362 }
3363 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003365 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 }
3367 return -EINVAL;
3368}
Akinobu Mita82069372013-10-14 22:48:04 +09003369static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003371static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
3372{
3373 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ndelay);
3374}
3375/* Returns -EBUSY if ndelay is being changed and commands are queued */
3376/* If > 0 and accepted then scsi_debug_delay is set to DELAY_OVERRIDDEN */
3377static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
3378 size_t count)
3379{
3380 unsigned long iflags;
3381 int ndelay, res, k;
3382
3383 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
3384 (ndelay >= 0) && (ndelay < 1000000000)) {
3385 res = count;
3386 if (scsi_debug_ndelay != ndelay) {
3387 spin_lock_irqsave(&queued_arr_lock, iflags);
3388 k = find_first_bit(queued_in_use_bm,
3389 scsi_debug_max_queue);
3390 if (k != scsi_debug_max_queue)
3391 res = -EBUSY; /* have queued commands */
3392 else {
3393 scsi_debug_ndelay = ndelay;
3394 scsi_debug_delay = ndelay ? DELAY_OVERRIDDEN
3395 : DEF_DELAY;
3396 }
3397 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3398 }
3399 return res;
3400 }
3401 return -EINVAL;
3402}
3403static DRIVER_ATTR_RW(ndelay);
3404
Akinobu Mita82069372013-10-14 22:48:04 +09003405static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406{
3407 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
3408}
3409
Akinobu Mita82069372013-10-14 22:48:04 +09003410static ssize_t opts_store(struct device_driver *ddp, const char *buf,
3411 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412{
3413 int opts;
3414 char work[20];
3415
3416 if (1 == sscanf(buf, "%10s", work)) {
Rasmus Villemoes48a96872014-10-13 15:54:44 -07003417 if (0 == strncasecmp(work,"0x", 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 if (1 == sscanf(&work[2], "%x", &opts))
3419 goto opts_done;
3420 } else {
3421 if (1 == sscanf(work, "%d", &opts))
3422 goto opts_done;
3423 }
3424 }
3425 return -EINVAL;
3426opts_done:
3427 scsi_debug_opts = opts;
Douglas Gilbert817fd662014-11-24 20:18:02 -05003428 if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
3429 sdebug_any_injecting_opt = true;
3430 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
3431 sdebug_any_injecting_opt = true;
3432 else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
3433 sdebug_any_injecting_opt = true;
3434 else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
3435 sdebug_any_injecting_opt = true;
3436 else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
3437 sdebug_any_injecting_opt = true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003438 atomic_set(&sdebug_cmnd_count, 0);
3439 atomic_set(&sdebug_a_tsf, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 return count;
3441}
Akinobu Mita82069372013-10-14 22:48:04 +09003442static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
Akinobu Mita82069372013-10-14 22:48:04 +09003444static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445{
3446 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
3447}
Akinobu Mita82069372013-10-14 22:48:04 +09003448static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
3449 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450{
3451 int n;
3452
3453 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3454 scsi_debug_ptype = n;
3455 return count;
3456 }
3457 return -EINVAL;
3458}
Akinobu Mita82069372013-10-14 22:48:04 +09003459static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460
Akinobu Mita82069372013-10-14 22:48:04 +09003461static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462{
3463 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
3464}
Akinobu Mita82069372013-10-14 22:48:04 +09003465static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
3466 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467{
3468 int n;
3469
3470 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3471 scsi_debug_dsense = n;
3472 return count;
3473 }
3474 return -EINVAL;
3475}
Akinobu Mita82069372013-10-14 22:48:04 +09003476static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
Akinobu Mita82069372013-10-14 22:48:04 +09003478static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04003479{
3480 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
3481}
Akinobu Mita82069372013-10-14 22:48:04 +09003482static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
3483 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04003484{
3485 int n;
3486
3487 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003488 n = (n > 0);
3489 scsi_debug_fake_rw = (scsi_debug_fake_rw > 0);
3490 if (scsi_debug_fake_rw != n) {
3491 if ((0 == n) && (NULL == fake_storep)) {
3492 unsigned long sz =
3493 (unsigned long)scsi_debug_dev_size_mb *
3494 1048576;
3495
3496 fake_storep = vmalloc(sz);
3497 if (NULL == fake_storep) {
3498 pr_err("%s: out of memory, 9\n",
3499 __func__);
3500 return -ENOMEM;
3501 }
3502 memset(fake_storep, 0, sz);
3503 }
3504 scsi_debug_fake_rw = n;
3505 }
Douglas Gilbert23183912006-09-16 20:30:47 -04003506 return count;
3507 }
3508 return -EINVAL;
3509}
Akinobu Mita82069372013-10-14 22:48:04 +09003510static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04003511
Akinobu Mita82069372013-10-14 22:48:04 +09003512static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003513{
3514 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
3515}
Akinobu Mita82069372013-10-14 22:48:04 +09003516static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
3517 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003518{
3519 int n;
3520
3521 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3522 scsi_debug_no_lun_0 = n;
3523 return count;
3524 }
3525 return -EINVAL;
3526}
Akinobu Mita82069372013-10-14 22:48:04 +09003527static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003528
Akinobu Mita82069372013-10-14 22:48:04 +09003529static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530{
3531 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
3532}
Akinobu Mita82069372013-10-14 22:48:04 +09003533static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
3534 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535{
3536 int n;
3537
3538 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3539 scsi_debug_num_tgts = n;
3540 sdebug_max_tgts_luns();
3541 return count;
3542 }
3543 return -EINVAL;
3544}
Akinobu Mita82069372013-10-14 22:48:04 +09003545static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546
Akinobu Mita82069372013-10-14 22:48:04 +09003547static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548{
3549 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
3550}
Akinobu Mita82069372013-10-14 22:48:04 +09003551static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552
Akinobu Mita82069372013-10-14 22:48:04 +09003553static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554{
3555 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
3556}
Akinobu Mita82069372013-10-14 22:48:04 +09003557static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
Akinobu Mita82069372013-10-14 22:48:04 +09003559static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560{
3561 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
3562}
Akinobu Mita82069372013-10-14 22:48:04 +09003563static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
3564 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565{
3566 int nth;
3567
3568 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
3569 scsi_debug_every_nth = nth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003570 atomic_set(&sdebug_cmnd_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 return count;
3572 }
3573 return -EINVAL;
3574}
Akinobu Mita82069372013-10-14 22:48:04 +09003575static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576
Akinobu Mita82069372013-10-14 22:48:04 +09003577static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578{
3579 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
3580}
Akinobu Mita82069372013-10-14 22:48:04 +09003581static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
3582 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583{
3584 int n;
3585
3586 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3587 scsi_debug_max_luns = n;
3588 sdebug_max_tgts_luns();
3589 return count;
3590 }
3591 return -EINVAL;
3592}
Akinobu Mita82069372013-10-14 22:48:04 +09003593static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
Akinobu Mita82069372013-10-14 22:48:04 +09003595static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003596{
3597 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
3598}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003599/* N.B. max_queue can be changed while there are queued commands. In flight
3600 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09003601static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
3602 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003603{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003604 unsigned long iflags;
3605 int n, k;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003606
3607 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
3608 (n <= SCSI_DEBUG_CANQUEUE)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003609 spin_lock_irqsave(&queued_arr_lock, iflags);
3610 k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003611 scsi_debug_max_queue = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003612 if (SCSI_DEBUG_CANQUEUE == k)
3613 atomic_set(&retired_max_queue, 0);
3614 else if (k >= n)
3615 atomic_set(&retired_max_queue, k + 1);
3616 else
3617 atomic_set(&retired_max_queue, 0);
3618 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003619 return count;
3620 }
3621 return -EINVAL;
3622}
Akinobu Mita82069372013-10-14 22:48:04 +09003623static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003624
Akinobu Mita82069372013-10-14 22:48:04 +09003625static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003626{
3627 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
3628}
Akinobu Mita82069372013-10-14 22:48:04 +09003629static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003630
Akinobu Mita82069372013-10-14 22:48:04 +09003631static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632{
3633 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
3634}
Akinobu Mita82069372013-10-14 22:48:04 +09003635static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636
Akinobu Mita82069372013-10-14 22:48:04 +09003637static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003638{
3639 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3640}
Akinobu Mita82069372013-10-14 22:48:04 +09003641static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
3642 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003643{
3644 int n;
3645
3646 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3647 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003648
3649 sdebug_capacity = get_sdebug_capacity();
3650
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003651 return count;
3652 }
3653 return -EINVAL;
3654}
Akinobu Mita82069372013-10-14 22:48:04 +09003655static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003656
Akinobu Mita82069372013-10-14 22:48:04 +09003657static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658{
3659 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
3660}
3661
Akinobu Mita82069372013-10-14 22:48:04 +09003662static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
3663 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003665 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003667 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 if (delta_hosts > 0) {
3670 do {
3671 sdebug_add_adapter();
3672 } while (--delta_hosts);
3673 } else if (delta_hosts < 0) {
3674 do {
3675 sdebug_remove_adapter();
3676 } while (++delta_hosts);
3677 }
3678 return count;
3679}
Akinobu Mita82069372013-10-14 22:48:04 +09003680static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
Akinobu Mita82069372013-10-14 22:48:04 +09003682static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04003683{
3684 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3685}
Akinobu Mita82069372013-10-14 22:48:04 +09003686static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
3687 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04003688{
3689 int n;
3690
3691 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3692 scsi_debug_vpd_use_hostno = n;
3693 return count;
3694 }
3695 return -EINVAL;
3696}
Akinobu Mita82069372013-10-14 22:48:04 +09003697static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04003698
Akinobu Mita82069372013-10-14 22:48:04 +09003699static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136a2008-06-05 00:12:59 -04003700{
3701 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3702}
Akinobu Mita82069372013-10-14 22:48:04 +09003703static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003704
Akinobu Mita82069372013-10-14 22:48:04 +09003705static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003706{
3707 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3708}
Akinobu Mita82069372013-10-14 22:48:04 +09003709static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003710
Akinobu Mita82069372013-10-14 22:48:04 +09003711static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003712{
3713 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3714}
Akinobu Mita82069372013-10-14 22:48:04 +09003715static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003716
Akinobu Mita82069372013-10-14 22:48:04 +09003717static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003718{
Akinobu Mita68aee7b2013-09-18 21:27:27 +09003719 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003720}
Akinobu Mita82069372013-10-14 22:48:04 +09003721static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003722
Akinobu Mita82069372013-10-14 22:48:04 +09003723static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003724{
3725 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3726}
Akinobu Mita82069372013-10-14 22:48:04 +09003727static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003728
Akinobu Mita82069372013-10-14 22:48:04 +09003729static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003730{
3731 ssize_t count;
3732
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003733 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003734 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3735 sdebug_store_sectors);
3736
3737 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3738
3739 buf[count++] = '\n';
3740 buf[count++] = 0;
3741
3742 return count;
3743}
Akinobu Mita82069372013-10-14 22:48:04 +09003744static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003745
Akinobu Mita82069372013-10-14 22:48:04 +09003746static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02003747{
3748 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
3749}
Akinobu Mita82069372013-10-14 22:48:04 +09003750static ssize_t removable_store(struct device_driver *ddp, const char *buf,
3751 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02003752{
3753 int n;
3754
3755 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3756 scsi_debug_removable = (n > 0);
3757 return count;
3758 }
3759 return -EINVAL;
3760}
Akinobu Mita82069372013-10-14 22:48:04 +09003761static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02003762
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003763static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
3764{
3765 return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_host_lock);
3766}
3767/* Returns -EBUSY if host_lock is being changed and commands are queued */
3768static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
3769 size_t count)
3770{
3771 int n, res;
3772
3773 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3774 bool new_host_lock = (n > 0);
3775
3776 res = count;
3777 if (new_host_lock != scsi_debug_host_lock) {
3778 unsigned long iflags;
3779 int k;
3780
3781 spin_lock_irqsave(&queued_arr_lock, iflags);
3782 k = find_first_bit(queued_in_use_bm,
3783 scsi_debug_max_queue);
3784 if (k != scsi_debug_max_queue)
3785 res = -EBUSY; /* have queued commands */
3786 else
3787 scsi_debug_host_lock = new_host_lock;
3788 spin_unlock_irqrestore(&queued_arr_lock, iflags);
3789 }
3790 return res;
3791 }
3792 return -EINVAL;
3793}
3794static DRIVER_ATTR_RW(host_lock);
3795
3796
Akinobu Mita82069372013-10-14 22:48:04 +09003797/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04003798 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3799 files (over those found in the /sys/module/scsi_debug/parameters
3800 directory) is that auxiliary actions can be triggered when an attribute
3801 is changed. For example see: sdebug_add_host_store() above.
3802 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003803
Akinobu Mita82069372013-10-14 22:48:04 +09003804static struct attribute *sdebug_drv_attrs[] = {
3805 &driver_attr_delay.attr,
3806 &driver_attr_opts.attr,
3807 &driver_attr_ptype.attr,
3808 &driver_attr_dsense.attr,
3809 &driver_attr_fake_rw.attr,
3810 &driver_attr_no_lun_0.attr,
3811 &driver_attr_num_tgts.attr,
3812 &driver_attr_dev_size_mb.attr,
3813 &driver_attr_num_parts.attr,
3814 &driver_attr_every_nth.attr,
3815 &driver_attr_max_luns.attr,
3816 &driver_attr_max_queue.attr,
3817 &driver_attr_no_uld.attr,
3818 &driver_attr_scsi_level.attr,
3819 &driver_attr_virtual_gb.attr,
3820 &driver_attr_add_host.attr,
3821 &driver_attr_vpd_use_hostno.attr,
3822 &driver_attr_sector_size.attr,
3823 &driver_attr_dix.attr,
3824 &driver_attr_dif.attr,
3825 &driver_attr_guard.attr,
3826 &driver_attr_ato.attr,
3827 &driver_attr_map.attr,
3828 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003829 &driver_attr_host_lock.attr,
3830 &driver_attr_ndelay.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09003831 NULL,
3832};
3833ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834
Akinobu Mita11ddcec2014-02-26 22:56:59 +09003835static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003836
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837static int __init scsi_debug_init(void)
3838{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003839 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 int host_to_add;
3841 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003842 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003844 atomic_set(&sdebug_cmnd_count, 0);
3845 atomic_set(&sdebug_completions, 0);
3846 atomic_set(&retired_max_queue, 0);
3847
3848 if (scsi_debug_ndelay >= 1000000000) {
3849 pr_warn("%s: ndelay must be less than 1 second, ignored\n",
3850 __func__);
3851 scsi_debug_ndelay = 0;
3852 } else if (scsi_debug_ndelay > 0)
3853 scsi_debug_delay = DELAY_OVERRIDDEN;
3854
Martin K. Petersen597136a2008-06-05 00:12:59 -04003855 switch (scsi_debug_sector_size) {
3856 case 512:
3857 case 1024:
3858 case 2048:
3859 case 4096:
3860 break;
3861 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003862 pr_err("%s: invalid sector_size %d\n", __func__,
Martin K. Petersen597136a2008-06-05 00:12:59 -04003863 scsi_debug_sector_size);
3864 return -EINVAL;
3865 }
3866
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003867 switch (scsi_debug_dif) {
3868
3869 case SD_DIF_TYPE0_PROTECTION:
3870 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003871 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003872 case SD_DIF_TYPE3_PROTECTION:
3873 break;
3874
3875 default:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003876 pr_err("%s: dif must be 0, 1, 2 or 3\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003877 return -EINVAL;
3878 }
3879
3880 if (scsi_debug_guard > 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003881 pr_err("%s: guard must be 0 or 1\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003882 return -EINVAL;
3883 }
3884
3885 if (scsi_debug_ato > 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003886 pr_err("%s: ato must be 0 or 1\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003887 return -EINVAL;
3888 }
3889
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003890 if (scsi_debug_physblk_exp > 15) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003891 pr_err("%s: invalid physblk_exp %u\n", __func__,
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003892 scsi_debug_physblk_exp);
3893 return -EINVAL;
3894 }
3895
3896 if (scsi_debug_lowest_aligned > 0x3fff) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003897 pr_err("%s: lowest_aligned too big: %u\n", __func__,
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003898 scsi_debug_lowest_aligned);
3899 return -EINVAL;
3900 }
3901
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 if (scsi_debug_dev_size_mb < 1)
3903 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003904 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003905 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003906 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
3908 /* play around with geometry, don't waste too much on track 0 */
3909 sdebug_heads = 8;
3910 sdebug_sectors_per = 32;
3911 if (scsi_debug_dev_size_mb >= 16)
3912 sdebug_heads = 32;
3913 else if (scsi_debug_dev_size_mb >= 256)
3914 sdebug_heads = 64;
3915 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3916 (sdebug_sectors_per * sdebug_heads);
3917 if (sdebug_cylinders_per >= 1024) {
3918 /* other LLDs do this; implies >= 1GB ram disk ... */
3919 sdebug_heads = 255;
3920 sdebug_sectors_per = 63;
3921 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3922 (sdebug_sectors_per * sdebug_heads);
3923 }
3924
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003925 if (0 == scsi_debug_fake_rw) {
3926 fake_storep = vmalloc(sz);
3927 if (NULL == fake_storep) {
3928 pr_err("%s: out of memory, 1\n", __func__);
3929 return -ENOMEM;
3930 }
3931 memset(fake_storep, 0, sz);
3932 if (scsi_debug_num_parts > 0)
3933 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935
Akinobu Mita7cb69d02013-06-29 17:59:16 +09003936 if (scsi_debug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003937 int dif_size;
3938
3939 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3940 dif_storep = vmalloc(dif_size);
3941
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003942 pr_err("%s: dif_storep %u bytes @ %p\n", __func__, dif_size,
3943 dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003944
3945 if (dif_storep == NULL) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003946 pr_err("%s: out of mem. (DIX)\n", __func__);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003947 ret = -ENOMEM;
3948 goto free_vm;
3949 }
3950
3951 memset(dif_storep, 0xff, dif_size);
3952 }
3953
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003954 /* Logical Block Provisioning */
3955 if (scsi_debug_lbp()) {
Martin K. Petersen60147592010-08-19 11:49:00 -04003956 scsi_debug_unmap_max_blocks =
3957 clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
3958
3959 scsi_debug_unmap_max_desc =
3960 clamp(scsi_debug_unmap_max_desc, 0U, 256U);
3961
3962 scsi_debug_unmap_granularity =
3963 clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
3964
3965 if (scsi_debug_unmap_alignment &&
Akinobu Mitaac170782013-04-16 22:11:56 +09003966 scsi_debug_unmap_granularity <=
3967 scsi_debug_unmap_alignment) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003968 pr_err("%s: ERR: unmap_granularity <= unmap_alignment\n",
Martin K. Petersen44d92692009-10-15 14:45:27 -04003969 __func__);
3970 return -EINVAL;
3971 }
3972
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003973 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
3974 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003975
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003976 pr_info("%s: %lu provisioning blocks\n", __func__, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003977
3978 if (map_storep == NULL) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003979 pr_err("%s: out of mem. (MAP)\n", __func__);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003980 ret = -ENOMEM;
3981 goto free_vm;
3982 }
3983
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003984 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003985
3986 /* Map first 1KB for partition table */
3987 if (scsi_debug_num_parts)
3988 map_region(0, 2);
3989 }
3990
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003991 pseudo_primary = root_device_register("pseudo_0");
3992 if (IS_ERR(pseudo_primary)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003993 pr_warn("%s: root_device_register() error\n", __func__);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003994 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003995 goto free_vm;
3996 }
3997 ret = bus_register(&pseudo_lld_bus);
3998 if (ret < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003999 pr_warn("%s: bus_register error: %d\n", __func__, ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004000 goto dev_unreg;
4001 }
4002 ret = driver_register(&sdebug_driverfs_driver);
4003 if (ret < 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004004 pr_warn("%s: driver_register error: %d\n", __func__, ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004005 goto bus_unreg;
4006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 host_to_add = scsi_debug_add_host;
4009 scsi_debug_add_host = 0;
4010
4011 for (k = 0; k < host_to_add; k++) {
4012 if (sdebug_add_adapter()) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004013 pr_err("%s: sdebug_add_adapter failed k=%d\n",
4014 __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 break;
4016 }
4017 }
4018
4019 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004020 pr_info("%s: built %d host(s)\n", __func__,
4021 scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 }
4023 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004024
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004025bus_unreg:
4026 bus_unregister(&pseudo_lld_bus);
4027dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004028 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004029free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04004030 if (map_storep)
4031 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004032 if (dif_storep)
4033 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07004034 vfree(fake_storep);
4035
4036 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037}
4038
4039static void __exit scsi_debug_exit(void)
4040{
4041 int k = scsi_debug_add_host;
4042
4043 stop_all_queued();
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004044 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 for (; k; k--)
4046 sdebug_remove_adapter();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 driver_unregister(&sdebug_driverfs_driver);
4048 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004049 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004051 if (dif_storep)
4052 vfree(dif_storep);
4053
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 vfree(fake_storep);
4055}
4056
4057device_initcall(scsi_debug_init);
4058module_exit(scsi_debug_exit);
4059
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060static void sdebug_release_adapter(struct device * dev)
4061{
4062 struct sdebug_host_info *sdbg_host;
4063
4064 sdbg_host = to_sdebug_host(dev);
4065 kfree(sdbg_host);
4066}
4067
4068static int sdebug_add_adapter(void)
4069{
4070 int k, devs_per_host;
4071 int error = 0;
4072 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004073 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004075 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 if (NULL == sdbg_host) {
4077 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004078 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 return -ENOMEM;
4080 }
4081
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
4083
4084 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
4085 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09004086 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
4087 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004089 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 error = -ENOMEM;
4091 goto clean;
4092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093 }
4094
4095 spin_lock(&sdebug_host_list_lock);
4096 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
4097 spin_unlock(&sdebug_host_list_lock);
4098
4099 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07004100 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01004102 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103
4104 error = device_register(&sdbg_host->dev);
4105
4106 if (error)
4107 goto clean;
4108
4109 ++scsi_debug_add_host;
4110 return error;
4111
4112clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004113 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4114 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 list_del(&sdbg_devinfo->dev_list);
4116 kfree(sdbg_devinfo);
4117 }
4118
4119 kfree(sdbg_host);
4120 return error;
4121}
4122
4123static void sdebug_remove_adapter(void)
4124{
4125 struct sdebug_host_info * sdbg_host = NULL;
4126
4127 spin_lock(&sdebug_host_list_lock);
4128 if (!list_empty(&sdebug_host_list)) {
4129 sdbg_host = list_entry(sdebug_host_list.prev,
4130 struct sdebug_host_info, host_list);
4131 list_del(&sdbg_host->host_list);
4132 }
4133 spin_unlock(&sdebug_host_list_lock);
4134
4135 if (!sdbg_host)
4136 return;
4137
4138 device_unregister(&sdbg_host->dev);
4139 --scsi_debug_add_host;
4140}
4141
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004142static int
4143scsi_debug_queuecommand(struct scsi_cmnd *SCpnt)
FUJITA Tomonori639db472008-03-20 11:09:19 +09004144{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02004145 unsigned char *cmd = SCpnt->cmnd;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004146 int len, k;
4147 unsigned int num;
4148 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004149 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004150 int errsts = 0;
4151 int target = SCpnt->device->id;
4152 struct sdebug_dev_info *devip = NULL;
4153 int inj_recovered = 0;
4154 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004155 int inj_dif = 0;
4156 int inj_dix = 0;
Christoph Hellwigb57d7c02014-05-01 16:51:51 +02004157 int inj_short = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004158 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004159 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004160
4161 scsi_set_resid(SCpnt, 0);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004162 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) &&
Douglas Gilbert01123ef2014-08-05 12:20:02 +02004163 !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004164 char b[120];
4165 int n;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004166
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004167 len = SCpnt->cmd_len;
4168 if (len > 32)
4169 strcpy(b, "too long, over 32 bytes");
4170 else {
4171 for (k = 0, n = 0; k < len; ++k)
4172 n += scnprintf(b + n, sizeof(b) - n, "%02x ",
4173 (unsigned int)cmd[k]);
4174 }
4175 sdev_printk(KERN_INFO, SCpnt->device, "%s: cmd %s\n", my_name,
4176 b);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004177 }
4178
4179 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
4180 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004181 return schedule_resp(SCpnt, NULL, DID_NO_CONNECT << 16, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004182 devip = devInfoReg(SCpnt->device);
4183 if (NULL == devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004184 return schedule_resp(SCpnt, NULL, DID_NO_CONNECT << 16, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004185
4186 if ((scsi_debug_every_nth != 0) &&
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004187 (atomic_inc_return(&sdebug_cmnd_count) >=
4188 abs(scsi_debug_every_nth))) {
4189 atomic_set(&sdebug_cmnd_count, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004190 if (scsi_debug_every_nth < -1)
4191 scsi_debug_every_nth = -1;
4192 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
4193 return 0; /* ignore command causing timeout */
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -05004194 else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
4195 scsi_medium_access_command(SCpnt))
4196 return 0; /* time out reads and writes */
FUJITA Tomonori639db472008-03-20 11:09:19 +09004197 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
4198 inj_recovered = 1; /* to reads and writes below */
4199 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
4200 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004201 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
4202 inj_dif = 1; /* to reads and writes below */
4203 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
4204 inj_dix = 1; /* to reads and writes below */
Christoph Hellwigb57d7c02014-05-01 16:51:51 +02004205 else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & scsi_debug_opts)
4206 inj_short = 1;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004207 }
4208
4209 if (devip->wlun) {
4210 switch (*cmd) {
4211 case INQUIRY:
4212 case REQUEST_SENSE:
4213 case TEST_UNIT_READY:
4214 case REPORT_LUNS:
4215 break; /* only allowable wlun commands */
4216 default:
4217 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4218 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
4219 "not supported for wlun\n", *cmd);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004220 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004221 INVALID_OPCODE, 0);
4222 errsts = check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004223 return schedule_resp(SCpnt, devip, errsts, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004224 }
4225 }
4226
4227 switch (*cmd) {
4228 case INQUIRY: /* mandatory, ignore unit attention */
4229 delay_override = 1;
4230 errsts = resp_inquiry(SCpnt, target, devip);
4231 break;
4232 case REQUEST_SENSE: /* mandatory, ignore unit attention */
4233 delay_override = 1;
4234 errsts = resp_requests(SCpnt, devip);
4235 break;
4236 case REZERO_UNIT: /* actually this is REWIND for SSC */
4237 case START_STOP:
4238 errsts = resp_start_stop(SCpnt, devip);
4239 break;
4240 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004241 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004242 if (errsts)
4243 break;
4244 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4245 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
4246 cmd[4] ? "inhibited" : "enabled");
4247 break;
4248 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004249 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004250 break;
4251 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004252 /* delay_override = 1; */
4253 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004254 break;
4255 case RESERVE:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004256 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004257 break;
4258 case RESERVE_10:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004259 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004260 break;
4261 case RELEASE:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004262 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004263 break;
4264 case RELEASE_10:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004265 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004266 break;
4267 case READ_CAPACITY:
4268 errsts = resp_readcap(SCpnt, devip);
4269 break;
4270 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04004271 if (cmd[1] == SAI_READ_CAPACITY_16)
4272 errsts = resp_readcap16(SCpnt, devip);
4273 else if (cmd[1] == SAI_GET_LBA_STATUS) {
4274
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004275 if (scsi_debug_lbp() == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004276 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen44d92692009-10-15 14:45:27 -04004277 INVALID_COMMAND_OPCODE, 0);
4278 errsts = check_condition_result;
4279 } else
4280 errsts = resp_get_lba_status(SCpnt, devip);
4281 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004282 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004283 INVALID_OPCODE, 0);
4284 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004285 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09004286 break;
4287 case MAINTENANCE_IN:
4288 if (MI_REPORT_TARGET_PGS != cmd[1]) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004289 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004290 INVALID_OPCODE, 0);
4291 errsts = check_condition_result;
4292 break;
4293 }
4294 errsts = resp_report_tgtpgs(SCpnt, devip);
4295 break;
4296 case READ_16:
4297 case READ_12:
4298 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004299 /* READ{10,12,16} and DIF Type 2 are natural enemies */
4300 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
4301 cmd[1] & 0xe0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004302 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen395cef02009-09-18 17:33:03 -04004303 INVALID_COMMAND_OPCODE, 0);
4304 errsts = check_condition_result;
4305 break;
4306 }
4307
4308 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
4309 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
4310 (cmd[1] & 0xe0) == 0)
4311 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
4312
4313 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09004314 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004315read:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004316 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004317 if (errsts)
4318 break;
4319 if (scsi_debug_fake_rw)
4320 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004321 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
Christoph Hellwigb57d7c02014-05-01 16:51:51 +02004322
4323 if (inj_short)
4324 num /= 2;
4325
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004326 errsts = resp_read(SCpnt, lba, num, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004327 if (inj_recovered && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004328 mk_sense_buffer(SCpnt, RECOVERED_ERROR,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004329 THRESHOLD_EXCEEDED, 0);
4330 errsts = check_condition_result;
4331 } else if (inj_transport && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004332 mk_sense_buffer(SCpnt, ABORTED_COMMAND,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004333 TRANSPORT_PROBLEM, ACK_NAK_TO);
4334 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004335 } else if (inj_dif && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004336 /* Logical block guard check failed */
4337 mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, 1);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004338 errsts = illegal_condition_result;
4339 } else if (inj_dix && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004340 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10, 1);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004341 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004342 }
4343 break;
4344 case REPORT_LUNS: /* mandatory, ignore unit attention */
4345 delay_override = 1;
4346 errsts = resp_report_luns(SCpnt, devip);
4347 break;
4348 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004349 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004350 break;
4351 case WRITE_16:
4352 case WRITE_12:
4353 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004354 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
4355 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
4356 cmd[1] & 0xe0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004357 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen395cef02009-09-18 17:33:03 -04004358 INVALID_COMMAND_OPCODE, 0);
4359 errsts = check_condition_result;
4360 break;
4361 }
4362
4363 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
4364 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
4365 (cmd[1] & 0xe0) == 0)
4366 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
4367
4368 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09004369 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04004370write:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004371 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004372 if (errsts)
4373 break;
4374 if (scsi_debug_fake_rw)
4375 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004376 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004377 errsts = resp_write(SCpnt, lba, num, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004378 if (inj_recovered && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004379 mk_sense_buffer(SCpnt, RECOVERED_ERROR,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004380 THRESHOLD_EXCEEDED, 0);
4381 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004382 } else if (inj_dif && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004383 mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, 1);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004384 errsts = illegal_condition_result;
4385 } else if (inj_dix && (0 == errsts)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004386 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10, 1);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004387 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004388 }
4389 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004390 case WRITE_SAME_16:
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004391 case WRITE_SAME:
Martin K. Petersen60147592010-08-19 11:49:00 -04004392 if (cmd[1] & 0x8) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004393 if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
4394 (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004395 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen60147592010-08-19 11:49:00 -04004396 INVALID_FIELD_IN_CDB, 0);
4397 errsts = check_condition_result;
4398 } else
4399 unmap = 1;
4400 }
4401 if (errsts)
4402 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004403 errsts = check_readiness(SCpnt, UAS_TUR, devip);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004404 if (errsts)
4405 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004406 if (scsi_debug_fake_rw)
4407 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004408 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004409 errsts = resp_write_same(SCpnt, lba, num, ei_lba, unmap);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004410 break;
4411 case UNMAP:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004412 errsts = check_readiness(SCpnt, UAS_TUR, devip);
Martin K. Petersen44d92692009-10-15 14:45:27 -04004413 if (errsts)
4414 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004415 if (scsi_debug_fake_rw)
4416 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04004417
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004418 if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004419 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen44d92692009-10-15 14:45:27 -04004420 INVALID_COMMAND_OPCODE, 0);
4421 errsts = check_condition_result;
4422 } else
4423 errsts = resp_unmap(SCpnt, devip);
4424 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004425 case MODE_SENSE:
4426 case MODE_SENSE_10:
4427 errsts = resp_mode_sense(SCpnt, target, devip);
4428 break;
4429 case MODE_SELECT:
4430 errsts = resp_mode_select(SCpnt, 1, devip);
4431 break;
4432 case MODE_SELECT_10:
4433 errsts = resp_mode_select(SCpnt, 0, devip);
4434 break;
4435 case LOG_SENSE:
4436 errsts = resp_log_sense(SCpnt, devip);
4437 break;
4438 case SYNCHRONIZE_CACHE:
4439 delay_override = 1;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004440 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004441 break;
4442 case WRITE_BUFFER:
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004443 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004444 break;
4445 case XDWRITEREAD_10:
4446 if (!scsi_bidi_cmnd(SCpnt)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004447 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004448 INVALID_FIELD_IN_CDB, 0);
4449 errsts = check_condition_result;
4450 break;
4451 }
4452
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004453 errsts = check_readiness(SCpnt, UAS_TUR, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004454 if (errsts)
4455 break;
4456 if (scsi_debug_fake_rw)
4457 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004458 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004459 errsts = resp_read(SCpnt, lba, num, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004460 if (errsts)
4461 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004462 errsts = resp_write(SCpnt, lba, num, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004463 if (errsts)
4464 break;
4465 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
4466 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04004467 case VARIABLE_LENGTH_CMD:
4468 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
4469
4470 if ((cmd[10] & 0xe0) == 0)
4471 printk(KERN_ERR
4472 "Unprotected RD/WR to DIF device\n");
4473
4474 if (cmd[9] == READ_32) {
4475 BUG_ON(SCpnt->cmd_len < 32);
4476 goto read;
4477 }
4478
4479 if (cmd[9] == WRITE_32) {
4480 BUG_ON(SCpnt->cmd_len < 32);
4481 goto write;
4482 }
4483 }
4484
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004485 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
Martin K. Petersen395cef02009-09-18 17:33:03 -04004486 INVALID_FIELD_IN_CDB, 0);
4487 errsts = check_condition_result;
4488 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004489 case 0x85:
4490 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
4491 sdev_printk(KERN_INFO, SCpnt->device,
4492 "%s: ATA PASS-THROUGH(16) not supported\n", my_name);
4493 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
4494 INVALID_OPCODE, 0);
4495 errsts = check_condition_result;
4496 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09004497 default:
4498 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004499 sdev_printk(KERN_INFO, SCpnt->device,
4500 "%s: Opcode: 0x%x not supported\n",
4501 my_name, *cmd);
4502 errsts = check_readiness(SCpnt, UAS_ONLY, devip);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004503 if (errsts)
4504 break; /* Unit attention takes precedence */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004505 mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
FUJITA Tomonori639db472008-03-20 11:09:19 +09004506 errsts = check_condition_result;
4507 break;
4508 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004509 return schedule_resp(SCpnt, devip, errsts,
FUJITA Tomonori639db472008-03-20 11:09:19 +09004510 (delay_override ? 0 : scsi_debug_delay));
4511}
4512
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004513static int
4514sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
4515{
4516 if (scsi_debug_host_lock) {
4517 unsigned long iflags;
4518 int rc;
4519
4520 spin_lock_irqsave(shost->host_lock, iflags);
4521 rc = scsi_debug_queuecommand(cmd);
4522 spin_unlock_irqrestore(shost->host_lock, iflags);
4523 return rc;
4524 } else
4525 return scsi_debug_queuecommand(cmd);
4526}
4527
4528static int
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004529sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004530{
4531 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004532 unsigned long iflags;
4533 struct sdebug_dev_info *devip;
4534
4535 spin_lock_irqsave(&queued_arr_lock, iflags);
4536 devip = (struct sdebug_dev_info *)sdev->hostdata;
4537 if (NULL == devip) {
4538 spin_unlock_irqrestore(&queued_arr_lock, iflags);
4539 return -ENODEV;
4540 }
4541 num_in_q = atomic_read(&devip->num_in_q);
4542 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004543
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004544 if (qdepth < 1)
4545 qdepth = 1;
4546 /* allow to exceed max host queued_arr elements for testing */
4547 if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
4548 qdepth = SCSI_DEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01004549 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004550
4551 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4552 sdev_printk(KERN_INFO, sdev,
4553 "%s: qdepth=%d, num_in_q=%d\n",
4554 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004555 }
4556 return sdev->queue_depth;
4557}
4558
4559static int
4560sdebug_change_qtype(struct scsi_device *sdev, int qtype)
4561{
Christoph Hellwiga62182f2014-10-02 14:39:55 +02004562 qtype = scsi_change_queue_type(sdev, qtype);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004563 if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
4564 const char *cp;
4565
4566 switch (qtype) {
4567 case 0:
4568 cp = "untagged";
4569 break;
4570 case MSG_SIMPLE_TAG:
4571 cp = "simple tags";
4572 break;
4573 case MSG_ORDERED_TAG:
4574 cp = "ordered tags";
4575 break;
4576 default:
4577 cp = "unknown";
4578 break;
4579 }
4580 sdev_printk(KERN_INFO, sdev, "%s: to %s\n", __func__, cp);
4581 }
4582 return qtype;
4583}
Jeff Garzikf2812332010-11-16 02:10:29 -05004584
Douglas Gilbert817fd662014-11-24 20:18:02 -05004585static int
4586check_inject(struct scsi_cmnd *scp)
4587{
4588 struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
4589
4590 memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
4591
4592 if (atomic_inc_return(&sdebug_cmnd_count) >=
4593 abs(scsi_debug_every_nth)) {
4594 atomic_set(&sdebug_cmnd_count, 0);
4595 if (scsi_debug_every_nth < -1)
4596 scsi_debug_every_nth = -1;
4597 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
4598 return 1; /* ignore command causing timeout */
4599 else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
4600 scsi_medium_access_command(scp))
4601 return 1; /* time out reads and writes */
4602 if (sdebug_any_injecting_opt) {
4603 int opts = scsi_debug_opts;
4604
4605 if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
4606 ep->inj_recovered = true;
4607 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
4608 ep->inj_transport = true;
4609 else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
4610 ep->inj_dif = true;
4611 else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
4612 ep->inj_dix = true;
4613 else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
4614 ep->inj_short = true;
4615 }
4616 }
4617 return 0;
4618}
4619
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004620static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04004621 .show_info = scsi_debug_show_info,
4622 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004623 .proc_name = sdebug_proc_name,
4624 .name = "SCSI DEBUG",
4625 .info = scsi_debug_info,
4626 .slave_alloc = scsi_debug_slave_alloc,
4627 .slave_configure = scsi_debug_slave_configure,
4628 .slave_destroy = scsi_debug_slave_destroy,
4629 .ioctl = scsi_debug_ioctl,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004630 .queuecommand = sdebug_queuecommand_lock_or_not,
4631 .change_queue_depth = sdebug_change_qdepth,
4632 .change_queue_type = sdebug_change_qtype,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004633 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004634 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004635 .eh_target_reset_handler = scsi_debug_target_reset,
4636 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004637 .eh_host_reset_handler = scsi_debug_host_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004638 .can_queue = SCSI_DEBUG_CANQUEUE,
4639 .this_id = 7,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09004640 .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004641 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09004642 .max_sectors = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004643 .use_clustering = DISABLE_CLUSTERING,
4644 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01004645 .track_queue_depth = 1,
Douglas Gilbert817fd662014-11-24 20:18:02 -05004646 .cmd_size = sizeof(struct sdebug_scmd_extra_t),
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09004647};
4648
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649static int sdebug_driver_probe(struct device * dev)
4650{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05004651 int error = 0;
Douglas Gilbert817fd662014-11-24 20:18:02 -05004652 int opts;
Douglas Gilbert22017ed2014-11-24 23:04:47 -05004653 struct sdebug_host_info *sdbg_host;
4654 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004655 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656
4657 sdbg_host = to_sdebug_host(dev);
4658
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004659 sdebug_driver_template.can_queue = scsi_debug_max_queue;
Akinobu Mita0759c662014-02-26 22:57:04 +09004660 if (scsi_debug_clustering)
4661 sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004662 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
4663 if (NULL == hpnt) {
Finn Thain17c9ff52014-10-03 11:43:31 +10004664 pr_err("%s: scsi_host_alloc failed\n", __func__);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004665 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668
4669 sdbg_host->shost = hpnt;
4670 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
4671 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
4672 hpnt->max_id = scsi_debug_num_tgts + 1;
4673 else
4674 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004675 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676
Martin K. Petersenc6a44282009-01-04 03:08:19 -05004677 host_prot = 0;
4678
4679 switch (scsi_debug_dif) {
4680
4681 case SD_DIF_TYPE1_PROTECTION:
4682 host_prot = SHOST_DIF_TYPE1_PROTECTION;
4683 if (scsi_debug_dix)
4684 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
4685 break;
4686
4687 case SD_DIF_TYPE2_PROTECTION:
4688 host_prot = SHOST_DIF_TYPE2_PROTECTION;
4689 if (scsi_debug_dix)
4690 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
4691 break;
4692
4693 case SD_DIF_TYPE3_PROTECTION:
4694 host_prot = SHOST_DIF_TYPE3_PROTECTION;
4695 if (scsi_debug_dix)
4696 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
4697 break;
4698
4699 default:
4700 if (scsi_debug_dix)
4701 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
4702 break;
4703 }
4704
4705 scsi_host_set_prot(hpnt, host_prot);
4706
4707 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
4708 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
4709 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
4710 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4711 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4712 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4713 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4714 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4715
4716 if (scsi_debug_guard == 1)
4717 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4718 else
4719 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4720
Douglas Gilbert817fd662014-11-24 20:18:02 -05004721 opts = scsi_debug_opts;
4722 if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
4723 sdebug_any_injecting_opt = true;
4724 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
4725 sdebug_any_injecting_opt = true;
4726 else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
4727 sdebug_any_injecting_opt = true;
4728 else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
4729 sdebug_any_injecting_opt = true;
4730 else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
4731 sdebug_any_injecting_opt = true;
4732
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 error = scsi_add_host(hpnt, &sdbg_host->dev);
4734 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004735 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 error = -ENODEV;
4737 scsi_host_put(hpnt);
4738 } else
4739 scsi_scan_host(hpnt);
4740
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004741 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742}
4743
4744static int sdebug_driver_remove(struct device * dev)
4745{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004747 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
4749 sdbg_host = to_sdebug_host(dev);
4750
4751 if (!sdbg_host) {
4752 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004753 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 return -ENODEV;
4755 }
4756
4757 scsi_remove_host(sdbg_host->shost);
4758
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004759 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4760 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 list_del(&sdbg_devinfo->dev_list);
4762 kfree(sdbg_devinfo);
4763 }
4764
4765 scsi_host_put(sdbg_host->shost);
4766 return 0;
4767}
4768
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004769static int pseudo_lld_bus_match(struct device *dev,
4770 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004772 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004774
4775static struct bus_type pseudo_lld_bus = {
4776 .name = "pseudo",
4777 .match = pseudo_lld_bus_match,
4778 .probe = sdebug_driver_probe,
4779 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09004780 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004781};