blob: 3f096a6681aca1cd008b560135efeb1ee35b9ea7 [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>
45
46#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090047
Martin K. Petersen44d92692009-10-15 14:45:27 -040048#include <asm/unaligned.h>
49
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090050#include <scsi/scsi.h>
51#include <scsi/scsi_cmnd.h>
52#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <scsi/scsi_host.h>
54#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090055#include <scsi/scsi_eh.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040056#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Martin K. Petersenc6a44282009-01-04 03:08:19 -050058#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040061#define SCSI_DEBUG_VERSION "1.82"
62static const char * scsi_debug_version_date = "20100324";
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050064/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040065#define NO_ADDITIONAL_SENSE 0x0
66#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#define INVALID_OPCODE 0x20
70#define ADDR_OUT_OF_RANGE 0x21
Martin K. Petersen395cef02009-09-18 17:33:03 -040071#define INVALID_COMMAND_OPCODE 0x20
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040073#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define POWERON_RESET 0x29
75#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050076#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040077#define THRESHOLD_EXCEEDED 0x5d
78#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050080/* Additional Sense Code Qualifier (ASCQ) */
81#define ACK_NAK_TO 0x3
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
84
85/* Default values for driver parameters */
86#define DEF_NUM_HOST 1
87#define DEF_NUM_TGTS 1
88#define DEF_MAX_LUNS 1
89/* With these defaults, this driver will make 1 host with 1 target
90 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
91 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -050092#define DEF_ATO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070093#define DEF_DELAY 1
94#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -050095#define DEF_DIF 0
96#define DEF_DIX 0
97#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070098#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -050099#define DEF_FAKE_RW 0
100#define DEF_GUARD 0
101#define DEF_LBPU 0
102#define DEF_LBPWS 0
103#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600104#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500105#define DEF_LOWEST_ALIGNED 0
106#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107#define DEF_NUM_PARTS 0
108#define DEF_OPTS 0
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400109#define DEF_OPT_BLKS 64
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500110#define DEF_PHYSBLK_EXP 0
111#define DEF_PTYPE 0
Martin Pittd9867882012-09-06 12:04:33 +0200112#define DEF_REMOVABLE false
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500113#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
114#define DEF_SECTOR_SIZE 512
115#define DEF_UNMAP_ALIGNMENT 0
116#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400117#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
118#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_VIRTUAL_GB 0
120#define DEF_VPD_USE_HOSTNO 1
121#define DEF_WRITESAME_LENGTH 0xFFFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123/* bit mask values for scsi_debug_opts */
124#define SCSI_DEBUG_OPT_NOISE 1
125#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
126#define SCSI_DEBUG_OPT_TIMEOUT 4
127#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500128#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500129#define SCSI_DEBUG_OPT_DIF_ERR 32
130#define SCSI_DEBUG_OPT_DIX_ERR 64
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -0500131#define SCSI_DEBUG_OPT_MAC_TIMEOUT 128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132/* When "every_nth" > 0 then modulo "every_nth" commands:
133 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
134 * - a RECOVERED_ERROR is simulated on successful read and write
135 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500136 * - a TRANSPORT_ERROR is simulated on successful read and write
137 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 *
139 * When "every_nth" < 0 then after "- every_nth" commands:
140 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
141 * - a RECOVERED_ERROR is simulated on successful read and write
142 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500143 * - a TRANSPORT_ERROR is simulated on successful read and write
144 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 * This will continue until some other action occurs (e.g. the user
146 * writing a new value (other than -1 or 1) to every_nth via sysfs).
147 */
148
149/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
150 * sector on read commands: */
151#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500152#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
154/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
155 * or "peripheral device" addressing (value 0) */
156#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400157#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400159/* Can queue up to this number of commands. Typically commands that
160 * that have a non-zero delay are queued. */
161#define SCSI_DEBUG_CANQUEUE 255
162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int scsi_debug_add_host = DEF_NUM_HOST;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500164static int scsi_debug_ato = DEF_ATO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165static int scsi_debug_delay = DEF_DELAY;
166static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500167static int scsi_debug_dif = DEF_DIF;
168static int scsi_debug_dix = DEF_DIX;
169static int scsi_debug_dsense = DEF_D_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170static int scsi_debug_every_nth = DEF_EVERY_NTH;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500171static int scsi_debug_fake_rw = DEF_FAKE_RW;
172static int scsi_debug_guard = DEF_GUARD;
173static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174static int scsi_debug_max_luns = DEF_MAX_LUNS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400175static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400176static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500177static int scsi_debug_no_uld = 0;
178static int scsi_debug_num_parts = DEF_NUM_PARTS;
179static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400180static int scsi_debug_opt_blks = DEF_OPT_BLKS;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500181static int scsi_debug_opts = DEF_OPTS;
182static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
183static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
184static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
185static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
186static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
187static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
188static unsigned int scsi_debug_lbpu = DEF_LBPU;
189static unsigned int scsi_debug_lbpws = DEF_LBPWS;
190static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600191static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
Martin K. Petersen60147592010-08-19 11:49:00 -0400192static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500193static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
194static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
195static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
196static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
Martin Pittd9867882012-09-06 12:04:33 +0200197static bool scsi_debug_removable = DEF_REMOVABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
199static int scsi_debug_cmnd_count = 0;
200
201#define DEV_READONLY(TGT) (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400203static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static sector_t sdebug_capacity; /* in sectors */
205
206/* old BIOS stuff, kernel may get rid of them but some mode sense pages
207 may still need them */
208static int sdebug_heads; /* heads per disk */
209static int sdebug_cylinders_per; /* cylinders per surface */
210static int sdebug_sectors_per; /* sectors per cylinder */
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212#define SDEBUG_MAX_PARTS 4
213
214#define SDEBUG_SENSE_LEN 32
215
Martin K. Petersen395cef02009-09-18 17:33:03 -0400216#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900217
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500218static unsigned int scsi_debug_lbp(void)
219{
220 return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10;
221}
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223struct sdebug_dev_info {
224 struct list_head dev_list;
225 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
226 unsigned int channel;
227 unsigned int target;
228 unsigned int lun;
229 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400230 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400232 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 char used;
234};
235
236struct sdebug_host_info {
237 struct list_head host_list;
238 struct Scsi_Host *shost;
239 struct device dev;
240 struct list_head dev_info_list;
241};
242
243#define to_sdebug_host(d) \
244 container_of(d, struct sdebug_host_info, dev)
245
246static LIST_HEAD(sdebug_host_list);
247static DEFINE_SPINLOCK(sdebug_host_list_lock);
248
249typedef void (* done_funct_t) (struct scsi_cmnd *);
250
251struct sdebug_queued_cmd {
252 int in_use;
253 struct timer_list cmnd_timer;
254 done_funct_t done_funct;
255 struct scsi_cmnd * a_cmnd;
256 int scsi_result;
257};
258static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260static unsigned char * fake_storep; /* ramdisk storage */
Akinobu Mitae18d8be2013-06-29 17:59:18 +0900261static struct sd_dif_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400262static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Martin K. Petersen44d92692009-10-15 14:45:27 -0400264static unsigned long map_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265static int num_aborts = 0;
266static int num_dev_resets = 0;
267static int num_bus_resets = 0;
268static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500269static int dix_writes;
270static int dix_reads;
271static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273static DEFINE_SPINLOCK(queued_arr_lock);
274static DEFINE_RWLOCK(atomic_rw);
275
276static char sdebug_proc_name[] = "scsi_debug";
277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278static struct bus_type pseudo_lld_bus;
279
280static struct device_driver sdebug_driverfs_driver = {
281 .name = sdebug_proc_name,
282 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283};
284
285static const int check_condition_result =
286 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
287
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500288static const int illegal_condition_result =
289 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
290
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400291static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
292 0, 0, 0x2, 0x4b};
293static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
294 0, 0, 0x0, 0x0};
295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296static int sdebug_add_adapter(void);
297static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900299static void sdebug_max_tgts_luns(void)
300{
301 struct sdebug_host_info *sdbg_host;
302 struct Scsi_Host *hpnt;
303
304 spin_lock(&sdebug_host_list_lock);
305 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
306 hpnt = sdbg_host->shost;
307 if ((hpnt->this_id >= 0) &&
308 (scsi_debug_num_tgts > hpnt->this_id))
309 hpnt->max_id = scsi_debug_num_tgts + 1;
310 else
311 hpnt->max_id = scsi_debug_num_tgts;
312 /* scsi_debug_max_luns; */
313 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
314 }
315 spin_unlock(&sdebug_host_list_lock);
316}
317
318static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
319 int asc, int asq)
320{
321 unsigned char *sbuff;
322
323 sbuff = devip->sense_buff;
324 memset(sbuff, 0, SDEBUG_SENSE_LEN);
325
326 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
327
328 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
329 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
330 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
331}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900333static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400334 unsigned long long *lba, unsigned int *num,
335 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900336{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400337 *ei_lba = 0;
338
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900339 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400340 case VARIABLE_LENGTH_CMD:
341 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
342 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
343 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
344 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
345
346 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
347 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
348
349 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
350 (u32)cmd[28] << 24;
351 break;
352
Martin K. Petersen44d92692009-10-15 14:45:27 -0400353 case WRITE_SAME_16:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900354 case WRITE_16:
355 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900356 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
357 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
358 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
359 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
360
361 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
362 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900363 break;
364 case WRITE_12:
365 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900366 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
367 (u32)cmd[2] << 24;
368
369 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
370 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900371 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400372 case WRITE_SAME:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900373 case WRITE_10:
374 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900375 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900376 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
377 (u32)cmd[2] << 24;
378
379 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900380 break;
381 case WRITE_6:
382 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900383 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
384 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900385 *num = (0 == cmd[4]) ? 256 : cmd[4];
386 break;
387 default:
388 break;
389 }
390}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
393{
394 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
395 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
396 }
397 return -EINVAL;
398 /* return -ENOTTY; // correct return but upsets fdisk */
399}
400
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400401static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
402 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
404 if (devip->reset) {
405 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
406 printk(KERN_INFO "scsi_debug: Reporting Unit "
407 "attention: power on reset\n");
408 devip->reset = 0;
409 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
410 return check_condition_result;
411 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400412 if ((0 == reset_only) && devip->stopped) {
413 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
414 printk(KERN_INFO "scsi_debug: Reporting Not "
415 "ready: initializing command required\n");
416 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
417 0x2);
418 return check_condition_result;
419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return 0;
421}
422
423/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900424static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 int arr_len)
426{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900427 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900428 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900430 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900432 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900434
435 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
436 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900437 if (sdb->resid)
438 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400439 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900440 sdb->resid = scsi_bufflen(scp) - act_len;
441
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 return 0;
443}
444
445/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900446static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
447 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900449 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900451 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900453
454 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455}
456
457
458static const char * inq_vendor_id = "Linux ";
459static const char * inq_product_id = "scsi_debug ";
460static const char * inq_product_rev = "0004";
461
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200462static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
463 int target_dev_id, int dev_id_num,
464 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400465 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400467 int num, port_a;
468 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400470 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 /* T10 vendor identifier field format (faked) */
472 arr[0] = 0x2; /* ASCII */
473 arr[1] = 0x1;
474 arr[2] = 0x0;
475 memcpy(&arr[4], inq_vendor_id, 8);
476 memcpy(&arr[12], inq_product_id, 16);
477 memcpy(&arr[28], dev_id_str, dev_id_str_len);
478 num = 8 + 16 + dev_id_str_len;
479 arr[3] = num;
480 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400481 if (dev_id_num >= 0) {
482 /* NAA-5, Logical unit identifier (binary) */
483 arr[num++] = 0x1; /* binary (not necessarily sas) */
484 arr[num++] = 0x3; /* PIV=0, lu, naa */
485 arr[num++] = 0x0;
486 arr[num++] = 0x8;
487 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
488 arr[num++] = 0x33;
489 arr[num++] = 0x33;
490 arr[num++] = 0x30;
491 arr[num++] = (dev_id_num >> 24);
492 arr[num++] = (dev_id_num >> 16) & 0xff;
493 arr[num++] = (dev_id_num >> 8) & 0xff;
494 arr[num++] = dev_id_num & 0xff;
495 /* Target relative port number */
496 arr[num++] = 0x61; /* proto=sas, binary */
497 arr[num++] = 0x94; /* PIV=1, target port, rel port */
498 arr[num++] = 0x0; /* reserved */
499 arr[num++] = 0x4; /* length */
500 arr[num++] = 0x0; /* reserved */
501 arr[num++] = 0x0; /* reserved */
502 arr[num++] = 0x0;
503 arr[num++] = 0x1; /* relative port A */
504 }
505 /* NAA-5, Target port identifier */
506 arr[num++] = 0x61; /* proto=sas, binary */
507 arr[num++] = 0x93; /* piv=1, target port, naa */
508 arr[num++] = 0x0;
509 arr[num++] = 0x8;
510 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
511 arr[num++] = 0x22;
512 arr[num++] = 0x22;
513 arr[num++] = 0x20;
514 arr[num++] = (port_a >> 24);
515 arr[num++] = (port_a >> 16) & 0xff;
516 arr[num++] = (port_a >> 8) & 0xff;
517 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200518 /* NAA-5, Target port group identifier */
519 arr[num++] = 0x61; /* proto=sas, binary */
520 arr[num++] = 0x95; /* piv=1, target port group id */
521 arr[num++] = 0x0;
522 arr[num++] = 0x4;
523 arr[num++] = 0;
524 arr[num++] = 0;
525 arr[num++] = (port_group_id >> 8) & 0xff;
526 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400527 /* NAA-5, Target device identifier */
528 arr[num++] = 0x61; /* proto=sas, binary */
529 arr[num++] = 0xa3; /* piv=1, target device, naa */
530 arr[num++] = 0x0;
531 arr[num++] = 0x8;
532 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
533 arr[num++] = 0x22;
534 arr[num++] = 0x22;
535 arr[num++] = 0x20;
536 arr[num++] = (target_dev_id >> 24);
537 arr[num++] = (target_dev_id >> 16) & 0xff;
538 arr[num++] = (target_dev_id >> 8) & 0xff;
539 arr[num++] = target_dev_id & 0xff;
540 /* SCSI name string: Target device identifier */
541 arr[num++] = 0x63; /* proto=sas, UTF-8 */
542 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
543 arr[num++] = 0x0;
544 arr[num++] = 24;
545 memcpy(arr + num, "naa.52222220", 12);
546 num += 12;
547 snprintf(b, sizeof(b), "%08X", target_dev_id);
548 memcpy(arr + num, b, 8);
549 num += 8;
550 memset(arr + num, 0, 4);
551 num += 4;
552 return num;
553}
554
555
556static unsigned char vpd84_data[] = {
557/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
558 0x22,0x22,0x22,0x0,0xbb,0x1,
559 0x22,0x22,0x22,0x0,0xbb,0x2,
560};
561
562static int inquiry_evpd_84(unsigned char * arr)
563{
564 memcpy(arr, vpd84_data, sizeof(vpd84_data));
565 return sizeof(vpd84_data);
566}
567
568static int inquiry_evpd_85(unsigned char * arr)
569{
570 int num = 0;
571 const char * na1 = "https://www.kernel.org/config";
572 const char * na2 = "http://www.kernel.org/log";
573 int plen, olen;
574
575 arr[num++] = 0x1; /* lu, storage config */
576 arr[num++] = 0x0; /* reserved */
577 arr[num++] = 0x0;
578 olen = strlen(na1);
579 plen = olen + 1;
580 if (plen % 4)
581 plen = ((plen / 4) + 1) * 4;
582 arr[num++] = plen; /* length, null termianted, padded */
583 memcpy(arr + num, na1, olen);
584 memset(arr + num + olen, 0, plen - olen);
585 num += plen;
586
587 arr[num++] = 0x4; /* lu, logging */
588 arr[num++] = 0x0; /* reserved */
589 arr[num++] = 0x0;
590 olen = strlen(na2);
591 plen = olen + 1;
592 if (plen % 4)
593 plen = ((plen / 4) + 1) * 4;
594 arr[num++] = plen; /* length, null terminated, padded */
595 memcpy(arr + num, na2, olen);
596 memset(arr + num + olen, 0, plen - olen);
597 num += plen;
598
599 return num;
600}
601
602/* SCSI ports VPD page */
603static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
604{
605 int num = 0;
606 int port_a, port_b;
607
608 port_a = target_dev_id + 1;
609 port_b = port_a + 1;
610 arr[num++] = 0x0; /* reserved */
611 arr[num++] = 0x0; /* reserved */
612 arr[num++] = 0x0;
613 arr[num++] = 0x1; /* relative port 1 (primary) */
614 memset(arr + num, 0, 6);
615 num += 6;
616 arr[num++] = 0x0;
617 arr[num++] = 12; /* length tp descriptor */
618 /* naa-5 target port identifier (A) */
619 arr[num++] = 0x61; /* proto=sas, binary */
620 arr[num++] = 0x93; /* PIV=1, target port, NAA */
621 arr[num++] = 0x0; /* reserved */
622 arr[num++] = 0x8; /* length */
623 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
624 arr[num++] = 0x22;
625 arr[num++] = 0x22;
626 arr[num++] = 0x20;
627 arr[num++] = (port_a >> 24);
628 arr[num++] = (port_a >> 16) & 0xff;
629 arr[num++] = (port_a >> 8) & 0xff;
630 arr[num++] = port_a & 0xff;
631
632 arr[num++] = 0x0; /* reserved */
633 arr[num++] = 0x0; /* reserved */
634 arr[num++] = 0x0;
635 arr[num++] = 0x2; /* relative port 2 (secondary) */
636 memset(arr + num, 0, 6);
637 num += 6;
638 arr[num++] = 0x0;
639 arr[num++] = 12; /* length tp descriptor */
640 /* naa-5 target port identifier (B) */
641 arr[num++] = 0x61; /* proto=sas, binary */
642 arr[num++] = 0x93; /* PIV=1, target port, NAA */
643 arr[num++] = 0x0; /* reserved */
644 arr[num++] = 0x8; /* length */
645 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
646 arr[num++] = 0x22;
647 arr[num++] = 0x22;
648 arr[num++] = 0x20;
649 arr[num++] = (port_b >> 24);
650 arr[num++] = (port_b >> 16) & 0xff;
651 arr[num++] = (port_b >> 8) & 0xff;
652 arr[num++] = port_b & 0xff;
653
654 return num;
655}
656
657
658static unsigned char vpd89_data[] = {
659/* from 4th byte */ 0,0,0,0,
660'l','i','n','u','x',' ',' ',' ',
661'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
662'1','2','3','4',
6630x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6640xec,0,0,0,
6650x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6660,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6670x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6680x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6690x53,0x41,
6700x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6710x20,0x20,
6720x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6730x10,0x80,
6740,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6750x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6760x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6770,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6780x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6790x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6800,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6840x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6850,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6860xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6870,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6880,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6890,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6900,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6940,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6960,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6970,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6990,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
700};
701
702static int inquiry_evpd_89(unsigned char * arr)
703{
704 memcpy(arr, vpd89_data, sizeof(vpd89_data));
705 return sizeof(vpd89_data);
706}
707
708
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400709/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400710static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400711 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
712 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
713 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
714 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400715};
716
717static int inquiry_evpd_b0(unsigned char * arr)
718{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400719 unsigned int gran;
720
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400721 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400722
723 /* Optimal transfer length granularity */
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400724 gran = 1 << scsi_debug_physblk_exp;
725 arr[2] = (gran >> 8) & 0xff;
726 arr[3] = gran & 0xff;
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400727
728 /* Maximum Transfer Length */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400729 if (sdebug_store_sectors > 0x400) {
730 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
731 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
732 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
733 arr[7] = sdebug_store_sectors & 0xff;
734 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400735
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400736 /* Optimal Transfer Length */
737 put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
738
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500739 if (scsi_debug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400740 /* Maximum Unmap LBA Count */
Martin K. Petersen60147592010-08-19 11:49:00 -0400741 put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400742
743 /* Maximum Unmap Block Descriptor Count */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400744 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
745 }
746
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400747 /* Unmap Granularity Alignment */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400748 if (scsi_debug_unmap_alignment) {
749 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
750 arr[28] |= 0x80; /* UGAVALID */
751 }
752
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400753 /* Optimal Unmap Granularity */
Martin K. Petersen60147592010-08-19 11:49:00 -0400754 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
755
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500756 /* Maximum WRITE SAME Length */
757 put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
758
759 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400760
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400761 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762}
763
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400764/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600765static int inquiry_evpd_b1(unsigned char *arr)
766{
767 memset(arr, 0, 0x3c);
768 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400769 arr[1] = 1; /* non rotating medium (e.g. solid state) */
770 arr[2] = 0;
771 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600772
773 return 0x3c;
774}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600776/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -0400777static int inquiry_evpd_b2(unsigned char *arr)
778{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -0500779 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -0400780 arr[0] = 0; /* threshold exponent */
781
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500782 if (scsi_debug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -0400783 arr[1] = 1 << 7;
784
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500785 if (scsi_debug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -0400786 arr[1] |= 1 << 6;
787
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500788 if (scsi_debug_lbpws10)
789 arr[1] |= 1 << 5;
790
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600791 if (scsi_debug_lbprz)
792 arr[1] |= 1 << 2;
793
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -0500794 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -0400795}
796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400798#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800static int resp_inquiry(struct scsi_cmnd * scp, int target,
801 struct sdebug_dev_info * devip)
802{
803 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200804 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200806 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500809 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
810 if (! arr)
811 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400812 if (devip->wlun)
813 pq_pdt = 0x1e; /* present, wlun */
814 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
815 pq_pdt = 0x7f; /* not present, no device type */
816 else
817 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 arr[0] = pq_pdt;
819 if (0x2 & cmd[1]) { /* CMDDT bit set */
820 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
821 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200822 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return check_condition_result;
824 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200825 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400826 char lu_id_str[6];
827 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200829 port_group_id = (((host_no + 1) & 0x7f) << 8) +
830 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400831 if (0 == scsi_debug_vpd_use_hostno)
832 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400833 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
834 (devip->target * 1000) + devip->lun);
835 target_dev_id = ((host_no + 1) * 2000) +
836 (devip->target * 1000) - 3;
837 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400839 arr[1] = cmd[2]; /*sanity */
840 n = 4;
841 arr[n++] = 0x0; /* this page */
842 arr[n++] = 0x80; /* unit serial number */
843 arr[n++] = 0x83; /* device identification */
844 arr[n++] = 0x84; /* software interface ident. */
845 arr[n++] = 0x85; /* management network addresses */
846 arr[n++] = 0x86; /* extended inquiry */
847 arr[n++] = 0x87; /* mode page policy */
848 arr[n++] = 0x88; /* SCSI ports */
849 arr[n++] = 0x89; /* ATA information */
850 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600851 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500852 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
853 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400854 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400856 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400858 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400860 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200861 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
862 target_dev_id, lu_id_num,
863 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400864 } else if (0x84 == cmd[2]) { /* Software interface ident. */
865 arr[1] = cmd[2]; /*sanity */
866 arr[3] = inquiry_evpd_84(&arr[4]);
867 } else if (0x85 == cmd[2]) { /* Management network addresses */
868 arr[1] = cmd[2]; /*sanity */
869 arr[3] = inquiry_evpd_85(&arr[4]);
870 } else if (0x86 == cmd[2]) { /* extended inquiry */
871 arr[1] = cmd[2]; /*sanity */
872 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500873 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
874 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
875 else if (scsi_debug_dif)
876 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
877 else
878 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400879 arr[5] = 0x7; /* head of q, ordered + simple q's */
880 } else if (0x87 == cmd[2]) { /* mode page policy */
881 arr[1] = cmd[2]; /*sanity */
882 arr[3] = 0x8; /* number of following entries */
883 arr[4] = 0x2; /* disconnect-reconnect mp */
884 arr[6] = 0x80; /* mlus, shared */
885 arr[8] = 0x18; /* protocol specific lu */
886 arr[10] = 0x82; /* mlus, per initiator port */
887 } else if (0x88 == cmd[2]) { /* SCSI Ports */
888 arr[1] = cmd[2]; /*sanity */
889 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
890 } else if (0x89 == cmd[2]) { /* ATA information */
891 arr[1] = cmd[2]; /*sanity */
892 n = inquiry_evpd_89(&arr[4]);
893 arr[2] = (n >> 8);
894 arr[3] = (n & 0xff);
895 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
896 arr[1] = cmd[2]; /*sanity */
897 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600898 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
899 arr[1] = cmd[2]; /*sanity */
900 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500901 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -0400902 arr[1] = cmd[2]; /*sanity */
903 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 } else {
905 /* Illegal request, invalid field in cdb */
906 mk_sense_buffer(devip, ILLEGAL_REQUEST,
907 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200908 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 return check_condition_result;
910 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400911 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200912 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400913 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200914 kfree(arr);
915 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 }
917 /* drops through here for a standard inquiry */
Martin Pittd9867882012-09-06 12:04:33 +0200918 arr[1] = scsi_debug_removable ? 0x80 : 0; /* Removable disk */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 arr[2] = scsi_debug_scsi_level;
920 arr[3] = 2; /* response_data_format==2 */
921 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500922 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200923 if (0 == scsi_debug_vpd_use_hostno)
924 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400925 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400927 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 memcpy(&arr[8], inq_vendor_id, 8);
929 memcpy(&arr[16], inq_product_id, 16);
930 memcpy(&arr[32], inq_product_rev, 4);
931 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400932 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
933 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
934 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400936 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400938 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400940 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200941 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200943 kfree(arr);
944 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
947static int resp_requests(struct scsi_cmnd * scp,
948 struct sdebug_dev_info * devip)
949{
950 unsigned char * sbuff;
951 unsigned char *cmd = (unsigned char *)scp->cmnd;
952 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400953 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 int len = 18;
955
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400956 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400958 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
959 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400961 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
962 if (want_dsense) {
963 arr[0] = 0x72;
964 arr[1] = 0x0; /* NO_SENSE in sense_key */
965 arr[2] = THRESHOLD_EXCEEDED;
966 arr[3] = 0xff; /* TEST set and MRIE==6 */
967 } else {
968 arr[0] = 0x70;
969 arr[2] = 0x0; /* NO_SENSE in sense_key */
970 arr[7] = 0xa; /* 18 byte sense buffer */
971 arr[12] = THRESHOLD_EXCEEDED;
972 arr[13] = 0xff; /* TEST set and MRIE==6 */
973 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400974 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400976 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
977 /* DESC bit set and sense_buff in fixed format */
978 memset(arr, 0, sizeof(arr));
979 arr[0] = 0x72;
980 arr[1] = sbuff[2]; /* sense key */
981 arr[2] = sbuff[12]; /* asc */
982 arr[3] = sbuff[13]; /* ascq */
983 len = 8;
984 }
985 }
986 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 return fill_from_dev_buffer(scp, arr, len);
988}
989
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400990static int resp_start_stop(struct scsi_cmnd * scp,
991 struct sdebug_dev_info * devip)
992{
993 unsigned char *cmd = (unsigned char *)scp->cmnd;
994 int power_cond, errsts, start;
995
996 if ((errsts = check_readiness(scp, 1, devip)))
997 return errsts;
998 power_cond = (cmd[4] & 0xf0) >> 4;
999 if (power_cond) {
1000 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1001 0);
1002 return check_condition_result;
1003 }
1004 start = cmd[4] & 1;
1005 if (start == devip->stopped)
1006 devip->stopped = !start;
1007 return 0;
1008}
1009
FUJITA Tomonori28898872008-03-30 00:59:55 +09001010static sector_t get_sdebug_capacity(void)
1011{
1012 if (scsi_debug_virtual_gb > 0)
Douglas Gilbert5447ed62010-04-25 12:30:23 +02001013 return (sector_t)scsi_debug_virtual_gb *
1014 (1073741824 / scsi_debug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001015 else
1016 return sdebug_store_sectors;
1017}
1018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019#define SDEBUG_READCAP_ARR_SZ 8
1020static int resp_readcap(struct scsi_cmnd * scp,
1021 struct sdebug_dev_info * devip)
1022{
1023 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001024 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 int errsts;
1026
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001027 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001029 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001030 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001032 if (sdebug_capacity < 0xffffffff) {
1033 capac = (unsigned int)sdebug_capacity - 1;
1034 arr[0] = (capac >> 24);
1035 arr[1] = (capac >> 16) & 0xff;
1036 arr[2] = (capac >> 8) & 0xff;
1037 arr[3] = capac & 0xff;
1038 } else {
1039 arr[0] = 0xff;
1040 arr[1] = 0xff;
1041 arr[2] = 0xff;
1042 arr[3] = 0xff;
1043 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001044 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1045 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1047}
1048
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001049#define SDEBUG_READCAP16_ARR_SZ 32
1050static int resp_readcap16(struct scsi_cmnd * scp,
1051 struct sdebug_dev_info * devip)
1052{
1053 unsigned char *cmd = (unsigned char *)scp->cmnd;
1054 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1055 unsigned long long capac;
1056 int errsts, k, alloc_len;
1057
1058 if ((errsts = check_readiness(scp, 1, devip)))
1059 return errsts;
1060 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1061 + cmd[13]);
1062 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001063 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001064 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1065 capac = sdebug_capacity - 1;
1066 for (k = 0; k < 8; ++k, capac >>= 8)
1067 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001068 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1069 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1070 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1071 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001072 arr[13] = scsi_debug_physblk_exp & 0xf;
1073 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001074
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001075 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001076 arr[14] |= 0x80; /* LBPME */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001077 if (scsi_debug_lbprz)
1078 arr[14] |= 0x40; /* LBPRZ */
1079 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001080
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001081 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001082
1083 if (scsi_debug_dif) {
1084 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1085 arr[12] |= 1; /* PROT_EN */
1086 }
1087
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001088 return fill_from_dev_buffer(scp, arr,
1089 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1090}
1091
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001092#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1093
1094static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1095 struct sdebug_dev_info * devip)
1096{
1097 unsigned char *cmd = (unsigned char *)scp->cmnd;
1098 unsigned char * arr;
1099 int host_no = devip->sdbg_host->shost->host_no;
1100 int n, ret, alen, rlen;
1101 int port_group_a, port_group_b, port_a, port_b;
1102
1103 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1104 + cmd[9]);
1105
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001106 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1107 if (! arr)
1108 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001109 /*
1110 * EVPD page 0x88 states we have two ports, one
1111 * real and a fake port with no device connected.
1112 * So we create two port groups with one port each
1113 * and set the group with port B to unavailable.
1114 */
1115 port_a = 0x1; /* relative port A */
1116 port_b = 0x2; /* relative port B */
1117 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1118 (devip->channel & 0x7f);
1119 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1120 (devip->channel & 0x7f) + 0x80;
1121
1122 /*
1123 * The asymmetric access state is cycled according to the host_id.
1124 */
1125 n = 4;
1126 if (0 == scsi_debug_vpd_use_hostno) {
1127 arr[n++] = host_no % 3; /* Asymm access state */
1128 arr[n++] = 0x0F; /* claim: all states are supported */
1129 } else {
1130 arr[n++] = 0x0; /* Active/Optimized path */
1131 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1132 }
1133 arr[n++] = (port_group_a >> 8) & 0xff;
1134 arr[n++] = port_group_a & 0xff;
1135 arr[n++] = 0; /* Reserved */
1136 arr[n++] = 0; /* Status code */
1137 arr[n++] = 0; /* Vendor unique */
1138 arr[n++] = 0x1; /* One port per group */
1139 arr[n++] = 0; /* Reserved */
1140 arr[n++] = 0; /* Reserved */
1141 arr[n++] = (port_a >> 8) & 0xff;
1142 arr[n++] = port_a & 0xff;
1143 arr[n++] = 3; /* Port unavailable */
1144 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1145 arr[n++] = (port_group_b >> 8) & 0xff;
1146 arr[n++] = port_group_b & 0xff;
1147 arr[n++] = 0; /* Reserved */
1148 arr[n++] = 0; /* Status code */
1149 arr[n++] = 0; /* Vendor unique */
1150 arr[n++] = 0x1; /* One port per group */
1151 arr[n++] = 0; /* Reserved */
1152 arr[n++] = 0; /* Reserved */
1153 arr[n++] = (port_b >> 8) & 0xff;
1154 arr[n++] = port_b & 0xff;
1155
1156 rlen = n - 4;
1157 arr[0] = (rlen >> 24) & 0xff;
1158 arr[1] = (rlen >> 16) & 0xff;
1159 arr[2] = (rlen >> 8) & 0xff;
1160 arr[3] = rlen & 0xff;
1161
1162 /*
1163 * Return the smallest value of either
1164 * - The allocated length
1165 * - The constructed command length
1166 * - The maximum array size
1167 */
1168 rlen = min(alen,n);
1169 ret = fill_from_dev_buffer(scp, arr,
1170 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1171 kfree(arr);
1172 return ret;
1173}
1174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175/* <<Following mode page info copied from ST318451LW>> */
1176
1177static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1178{ /* Read-Write Error Recovery page for mode_sense */
1179 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1180 5, 0, 0xff, 0xff};
1181
1182 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1183 if (1 == pcontrol)
1184 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1185 return sizeof(err_recov_pg);
1186}
1187
1188static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1189{ /* Disconnect-Reconnect page for mode_sense */
1190 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1191 0, 0, 0, 0, 0, 0, 0, 0};
1192
1193 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1194 if (1 == pcontrol)
1195 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1196 return sizeof(disconnect_pg);
1197}
1198
1199static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1200{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001201 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1202 0, 0, 0, 0, 0, 0, 0, 0,
1203 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
Martin K. Petersen597136a2008-06-05 00:12:59 -04001205 memcpy(p, format_pg, sizeof(format_pg));
1206 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1207 p[11] = sdebug_sectors_per & 0xff;
1208 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1209 p[13] = scsi_debug_sector_size & 0xff;
Martin Pittd9867882012-09-06 12:04:33 +02001210 if (scsi_debug_removable)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001211 p[20] |= 0x20; /* should agree with INQUIRY */
1212 if (1 == pcontrol)
1213 memset(p + 2, 0, sizeof(format_pg) - 2);
1214 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215}
1216
1217static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1218{ /* Caching page for mode_sense */
1219 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1220 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1221
1222 memcpy(p, caching_pg, sizeof(caching_pg));
1223 if (1 == pcontrol)
1224 memset(p + 2, 0, sizeof(caching_pg) - 2);
1225 return sizeof(caching_pg);
1226}
1227
1228static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1229{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001230 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1231 0, 0, 0, 0};
1232 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 0, 0, 0x2, 0x4b};
1234
1235 if (scsi_debug_dsense)
1236 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001237 else
1238 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001239
1240 if (scsi_debug_ato)
1241 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1242
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1244 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001245 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1246 else if (2 == pcontrol)
1247 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 return sizeof(ctrl_m_pg);
1249}
1250
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001251
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1253{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001254 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1255 0, 0, 0x0, 0x0};
1256 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1257 0, 0, 0x0, 0x0};
1258
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1260 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001261 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1262 else if (2 == pcontrol)
1263 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 return sizeof(iec_m_pg);
1265}
1266
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001267static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1268{ /* SAS SSP mode page - short format for mode_sense */
1269 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1270 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1271
1272 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1273 if (1 == pcontrol)
1274 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1275 return sizeof(sas_sf_m_pg);
1276}
1277
1278
1279static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1280 int target_dev_id)
1281{ /* SAS phy control and discover mode page for mode_sense */
1282 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1283 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1284 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1285 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1286 0x2, 0, 0, 0, 0, 0, 0, 0,
1287 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1288 0, 0, 0, 0, 0, 0, 0, 0,
1289 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1290 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1291 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1292 0x3, 0, 0, 0, 0, 0, 0, 0,
1293 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1294 0, 0, 0, 0, 0, 0, 0, 0,
1295 };
1296 int port_a, port_b;
1297
1298 port_a = target_dev_id + 1;
1299 port_b = port_a + 1;
1300 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1301 p[20] = (port_a >> 24);
1302 p[21] = (port_a >> 16) & 0xff;
1303 p[22] = (port_a >> 8) & 0xff;
1304 p[23] = port_a & 0xff;
1305 p[48 + 20] = (port_b >> 24);
1306 p[48 + 21] = (port_b >> 16) & 0xff;
1307 p[48 + 22] = (port_b >> 8) & 0xff;
1308 p[48 + 23] = port_b & 0xff;
1309 if (1 == pcontrol)
1310 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1311 return sizeof(sas_pcd_m_pg);
1312}
1313
1314static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1315{ /* SAS SSP shared protocol specific port mode subpage */
1316 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1317 0, 0, 0, 0, 0, 0, 0, 0,
1318 };
1319
1320 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1321 if (1 == pcontrol)
1322 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1323 return sizeof(sas_sha_m_pg);
1324}
1325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326#define SDEBUG_MAX_MSENSE_SZ 256
1327
1328static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1329 struct sdebug_dev_info * devip)
1330{
Douglas Gilbert23183912006-09-16 20:30:47 -04001331 unsigned char dbd, llbaa;
1332 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001334 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 unsigned char * ap;
1336 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1337 unsigned char *cmd = (unsigned char *)scp->cmnd;
1338
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001339 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001341 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 pcontrol = (cmd[2] & 0xc0) >> 6;
1343 pcode = cmd[2] & 0x3f;
1344 subpcode = cmd[3];
1345 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001346 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1347 if ((0 == scsi_debug_ptype) && (0 == dbd))
1348 bd_len = llbaa ? 16 : 8;
1349 else
1350 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1352 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1353 if (0x3 == pcontrol) { /* Saving values not supported */
1354 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1355 0);
1356 return check_condition_result;
1357 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001358 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1359 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001360 /* set DPOFUA bit for disks */
1361 if (0 == scsi_debug_ptype)
1362 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1363 else
1364 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (msense_6) {
1366 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001367 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 offset = 4;
1369 } else {
1370 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001371 if (16 == bd_len)
1372 arr[4] = 0x1; /* set LONGLBA bit */
1373 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 offset = 8;
1375 }
1376 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001377 if ((bd_len > 0) && (!sdebug_capacity))
1378 sdebug_capacity = get_sdebug_capacity();
1379
Douglas Gilbert23183912006-09-16 20:30:47 -04001380 if (8 == bd_len) {
1381 if (sdebug_capacity > 0xfffffffe) {
1382 ap[0] = 0xff;
1383 ap[1] = 0xff;
1384 ap[2] = 0xff;
1385 ap[3] = 0xff;
1386 } else {
1387 ap[0] = (sdebug_capacity >> 24) & 0xff;
1388 ap[1] = (sdebug_capacity >> 16) & 0xff;
1389 ap[2] = (sdebug_capacity >> 8) & 0xff;
1390 ap[3] = sdebug_capacity & 0xff;
1391 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001392 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1393 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001394 offset += bd_len;
1395 ap = arr + offset;
1396 } else if (16 == bd_len) {
1397 unsigned long long capac = sdebug_capacity;
1398
1399 for (k = 0; k < 8; ++k, capac >>= 8)
1400 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001401 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1402 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1403 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1404 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001405 offset += bd_len;
1406 ap = arr + offset;
1407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001409 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1410 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1412 0);
1413 return check_condition_result;
1414 }
1415 switch (pcode) {
1416 case 0x1: /* Read-Write error recovery page, direct access */
1417 len = resp_err_recov_pg(ap, pcontrol, target);
1418 offset += len;
1419 break;
1420 case 0x2: /* Disconnect-Reconnect page, all devices */
1421 len = resp_disconnect_pg(ap, pcontrol, target);
1422 offset += len;
1423 break;
1424 case 0x3: /* Format device page, direct access */
1425 len = resp_format_pg(ap, pcontrol, target);
1426 offset += len;
1427 break;
1428 case 0x8: /* Caching page, direct access */
1429 len = resp_caching_pg(ap, pcontrol, target);
1430 offset += len;
1431 break;
1432 case 0xa: /* Control Mode page, all devices */
1433 len = resp_ctrl_m_pg(ap, pcontrol, target);
1434 offset += len;
1435 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001436 case 0x19: /* if spc==1 then sas phy, control+discover */
1437 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1438 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1439 INVALID_FIELD_IN_CDB, 0);
1440 return check_condition_result;
1441 }
1442 len = 0;
1443 if ((0x0 == subpcode) || (0xff == subpcode))
1444 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1445 if ((0x1 == subpcode) || (0xff == subpcode))
1446 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1447 target_dev_id);
1448 if ((0x2 == subpcode) || (0xff == subpcode))
1449 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1450 offset += len;
1451 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 case 0x1c: /* Informational Exceptions Mode page, all devices */
1453 len = resp_iec_m_pg(ap, pcontrol, target);
1454 offset += len;
1455 break;
1456 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001457 if ((0 == subpcode) || (0xff == subpcode)) {
1458 len = resp_err_recov_pg(ap, pcontrol, target);
1459 len += resp_disconnect_pg(ap + len, pcontrol, target);
1460 len += resp_format_pg(ap + len, pcontrol, target);
1461 len += resp_caching_pg(ap + len, pcontrol, target);
1462 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1463 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1464 if (0xff == subpcode) {
1465 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1466 target, target_dev_id);
1467 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1468 }
1469 len += resp_iec_m_pg(ap + len, pcontrol, target);
1470 } else {
1471 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1472 INVALID_FIELD_IN_CDB, 0);
1473 return check_condition_result;
1474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 offset += len;
1476 break;
1477 default:
1478 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1479 0);
1480 return check_condition_result;
1481 }
1482 if (msense_6)
1483 arr[0] = offset - 1;
1484 else {
1485 arr[0] = ((offset - 2) >> 8) & 0xff;
1486 arr[1] = (offset - 2) & 0xff;
1487 }
1488 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1489}
1490
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001491#define SDEBUG_MAX_MSELECT_SZ 512
1492
1493static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1494 struct sdebug_dev_info * devip)
1495{
1496 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1497 int param_len, res, errsts, mpage;
1498 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1499 unsigned char *cmd = (unsigned char *)scp->cmnd;
1500
1501 if ((errsts = check_readiness(scp, 1, devip)))
1502 return errsts;
1503 memset(arr, 0, sizeof(arr));
1504 pf = cmd[1] & 0x10;
1505 sp = cmd[1] & 0x1;
1506 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1507 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1508 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1509 INVALID_FIELD_IN_CDB, 0);
1510 return check_condition_result;
1511 }
1512 res = fetch_to_dev_buffer(scp, arr, param_len);
1513 if (-1 == res)
1514 return (DID_ERROR << 16);
1515 else if ((res < param_len) &&
1516 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1517 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1518 " IO sent=%d bytes\n", param_len, res);
1519 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1520 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001521 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001522 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1523 INVALID_FIELD_IN_PARAM_LIST, 0);
1524 return check_condition_result;
1525 }
1526 off = bd_len + (mselect6 ? 4 : 8);
1527 mpage = arr[off] & 0x3f;
1528 ps = !!(arr[off] & 0x80);
1529 if (ps) {
1530 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1531 INVALID_FIELD_IN_PARAM_LIST, 0);
1532 return check_condition_result;
1533 }
1534 spf = !!(arr[off] & 0x40);
1535 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1536 (arr[off + 1] + 2);
1537 if ((pg_len + off) > param_len) {
1538 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1539 PARAMETER_LIST_LENGTH_ERR, 0);
1540 return check_condition_result;
1541 }
1542 switch (mpage) {
1543 case 0xa: /* Control Mode page */
1544 if (ctrl_m_pg[1] == arr[off + 1]) {
1545 memcpy(ctrl_m_pg + 2, arr + off + 2,
1546 sizeof(ctrl_m_pg) - 2);
1547 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1548 return 0;
1549 }
1550 break;
1551 case 0x1c: /* Informational Exceptions Mode page */
1552 if (iec_m_pg[1] == arr[off + 1]) {
1553 memcpy(iec_m_pg + 2, arr + off + 2,
1554 sizeof(iec_m_pg) - 2);
1555 return 0;
1556 }
1557 break;
1558 default:
1559 break;
1560 }
1561 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1562 INVALID_FIELD_IN_PARAM_LIST, 0);
1563 return check_condition_result;
1564}
1565
1566static int resp_temp_l_pg(unsigned char * arr)
1567{
1568 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1569 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1570 };
1571
1572 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1573 return sizeof(temp_l_pg);
1574}
1575
1576static int resp_ie_l_pg(unsigned char * arr)
1577{
1578 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1579 };
1580
1581 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1582 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1583 arr[4] = THRESHOLD_EXCEEDED;
1584 arr[5] = 0xff;
1585 }
1586 return sizeof(ie_l_pg);
1587}
1588
1589#define SDEBUG_MAX_LSENSE_SZ 512
1590
1591static int resp_log_sense(struct scsi_cmnd * scp,
1592 struct sdebug_dev_info * devip)
1593{
Douglas Gilbert23183912006-09-16 20:30:47 -04001594 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001595 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1596 unsigned char *cmd = (unsigned char *)scp->cmnd;
1597
1598 if ((errsts = check_readiness(scp, 1, devip)))
1599 return errsts;
1600 memset(arr, 0, sizeof(arr));
1601 ppc = cmd[1] & 0x2;
1602 sp = cmd[1] & 0x1;
1603 if (ppc || sp) {
1604 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1605 INVALID_FIELD_IN_CDB, 0);
1606 return check_condition_result;
1607 }
1608 pcontrol = (cmd[2] & 0xc0) >> 6;
1609 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001610 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001611 alloc_len = (cmd[7] << 8) + cmd[8];
1612 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001613 if (0 == subpcode) {
1614 switch (pcode) {
1615 case 0x0: /* Supported log pages log page */
1616 n = 4;
1617 arr[n++] = 0x0; /* this page */
1618 arr[n++] = 0xd; /* Temperature */
1619 arr[n++] = 0x2f; /* Informational exceptions */
1620 arr[3] = n - 4;
1621 break;
1622 case 0xd: /* Temperature log page */
1623 arr[3] = resp_temp_l_pg(arr + 4);
1624 break;
1625 case 0x2f: /* Informational exceptions log page */
1626 arr[3] = resp_ie_l_pg(arr + 4);
1627 break;
1628 default:
1629 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1630 INVALID_FIELD_IN_CDB, 0);
1631 return check_condition_result;
1632 }
1633 } else if (0xff == subpcode) {
1634 arr[0] |= 0x40;
1635 arr[1] = subpcode;
1636 switch (pcode) {
1637 case 0x0: /* Supported log pages and subpages log page */
1638 n = 4;
1639 arr[n++] = 0x0;
1640 arr[n++] = 0x0; /* 0,0 page */
1641 arr[n++] = 0x0;
1642 arr[n++] = 0xff; /* this page */
1643 arr[n++] = 0xd;
1644 arr[n++] = 0x0; /* Temperature */
1645 arr[n++] = 0x2f;
1646 arr[n++] = 0x0; /* Informational exceptions */
1647 arr[3] = n - 4;
1648 break;
1649 case 0xd: /* Temperature subpages */
1650 n = 4;
1651 arr[n++] = 0xd;
1652 arr[n++] = 0x0; /* Temperature */
1653 arr[3] = n - 4;
1654 break;
1655 case 0x2f: /* Informational exceptions subpages */
1656 n = 4;
1657 arr[n++] = 0x2f;
1658 arr[n++] = 0x0; /* Informational exceptions */
1659 arr[3] = n - 4;
1660 break;
1661 default:
1662 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1663 INVALID_FIELD_IN_CDB, 0);
1664 return check_condition_result;
1665 }
1666 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001667 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1668 INVALID_FIELD_IN_CDB, 0);
1669 return check_condition_result;
1670 }
1671 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1672 return fill_from_dev_buffer(scp, arr,
1673 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1674}
1675
FUJITA Tomonori19789102008-03-30 00:59:56 +09001676static int check_device_access_params(struct sdebug_dev_info *devi,
1677 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001679 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001680 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 return check_condition_result;
1682 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001683 /* transfer length excessive (tie in to block limits VPD page) */
1684 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001685 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001686 return check_condition_result;
1687 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001688 return 0;
1689}
1690
1691static int do_device_access(struct scsi_cmnd *scmd,
1692 struct sdebug_dev_info *devi,
1693 unsigned long long lba, unsigned int num, int write)
1694{
1695 int ret;
Darrick J. Wonga361cc02011-01-31 18:47:54 -08001696 unsigned long long block, rest = 0;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001697 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1698
1699 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1700
1701 block = do_div(lba, sdebug_store_sectors);
1702 if (block + num > sdebug_store_sectors)
1703 rest = block + num - sdebug_store_sectors;
1704
Martin K. Petersen597136a2008-06-05 00:12:59 -04001705 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1706 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001707 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001708 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001709
1710 return ret;
1711}
1712
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001713static u16 dif_compute_csum(const void *buf, int len)
1714{
1715 u16 csum;
1716
1717 switch (scsi_debug_guard) {
1718 case 1:
1719 csum = ip_compute_csum(buf, len);
1720 break;
1721 case 0:
1722 csum = cpu_to_be16(crc_t10dif(buf, len));
1723 break;
1724 }
1725 return csum;
1726}
1727
1728static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
1729 sector_t sector, u32 ei_lba)
1730{
1731 u16 csum = dif_compute_csum(data, scsi_debug_sector_size);
1732
1733 if (sdt->guard_tag != csum) {
1734 pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
1735 __func__,
1736 (unsigned long)sector,
1737 be16_to_cpu(sdt->guard_tag),
1738 be16_to_cpu(csum));
1739 return 0x01;
1740 }
1741 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
1742 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
1743 pr_err("%s: REF check failed on sector %lu\n",
1744 __func__, (unsigned long)sector);
1745 return 0x03;
1746 }
1747 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1748 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1749 pr_err("%s: REF check failed on sector %lu\n",
1750 __func__, (unsigned long)sector);
1751 dif_errors++;
1752 return 0x03;
1753 }
1754 return 0;
1755}
1756
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001757static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001758 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001759{
1760 unsigned int i, resid;
1761 struct scatterlist *psgl;
1762 struct sd_dif_tuple *sdt;
1763 sector_t sector;
1764 sector_t tmp_sec = start_sec;
1765 void *paddr;
1766
1767 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1768
Akinobu Mitae18d8be2013-06-29 17:59:18 +09001769 sdt = dif_storep + start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001770
1771 for (i = 0 ; i < sectors ; i++) {
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001772 int ret;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001773
1774 if (sdt[i].app_tag == 0xffff)
1775 continue;
1776
1777 sector = start_sec + i;
1778
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001779 ret = dif_verify(&sdt[i],
1780 fake_storep + sector * scsi_debug_sector_size,
1781 sector, ei_lba);
1782 if (ret) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001783 dif_errors++;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001784 return ret;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001785 }
1786
1787 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001788 }
1789
Akinobu Mitae18d8be2013-06-29 17:59:18 +09001790 /* Bytes of protection data to copy into sgl */
1791 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001792 sector = start_sec;
1793
1794 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1795 int len = min(psgl->length, resid);
1796
Cong Wang77dfce02011-11-25 23:14:23 +08001797 paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
Akinobu Mitae18d8be2013-06-29 17:59:18 +09001798 memcpy(paddr, dif_storep + sector, len);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001799
Akinobu Mitae18d8be2013-06-29 17:59:18 +09001800 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001801 if (sector >= sdebug_store_sectors) {
1802 /* Force wrap */
1803 tmp_sec = sector;
1804 sector = do_div(tmp_sec, sdebug_store_sectors);
1805 }
1806 resid -= len;
Cong Wang77dfce02011-11-25 23:14:23 +08001807 kunmap_atomic(paddr);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001808 }
1809
1810 dix_reads++;
1811
1812 return 0;
1813}
1814
FUJITA Tomonori19789102008-03-30 00:59:56 +09001815static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001816 unsigned int num, struct sdebug_dev_info *devip,
1817 u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001818{
1819 unsigned long iflags;
1820 int ret;
1821
1822 ret = check_device_access_params(devip, lba, num);
1823 if (ret)
1824 return ret;
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05001827 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001828 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1829 /* claim unrecoverable read error */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05001830 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001831 /* set info field and valid bit for fixed descriptor */
1832 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1833 devip->sense_buff[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05001834 ret = (lba < OPT_MEDIUM_ERR_ADDR)
1835 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001836 devip->sense_buff[3] = (ret >> 24) & 0xff;
1837 devip->sense_buff[4] = (ret >> 16) & 0xff;
1838 devip->sense_buff[5] = (ret >> 8) & 0xff;
1839 devip->sense_buff[6] = ret & 0xff;
1840 }
Douglas Gilberta87e3a62010-12-17 19:16:06 -05001841 scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 return check_condition_result;
1843 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001844
1845 /* DIX + T10 DIF */
1846 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001847 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001848
1849 if (prot_ret) {
1850 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1851 return illegal_condition_result;
1852 }
1853 }
1854
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001856 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 read_unlock_irqrestore(&atomic_rw, iflags);
1858 return ret;
1859}
1860
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001861void dump_sector(unsigned char *buf, int len)
1862{
1863 int i, j;
1864
1865 printk(KERN_ERR ">>> Sector Dump <<<\n");
1866
1867 for (i = 0 ; i < len ; i += 16) {
1868 printk(KERN_ERR "%04d: ", i);
1869
1870 for (j = 0 ; j < 16 ; j++) {
1871 unsigned char c = buf[i+j];
1872 if (c >= 0x20 && c < 0x7e)
1873 printk(" %c ", buf[i+j]);
1874 else
1875 printk("%02x ", buf[i+j]);
1876 }
1877
1878 printk("\n");
1879 }
1880}
1881
1882static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001883 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001884{
1885 int i, j, ret;
1886 struct sd_dif_tuple *sdt;
1887 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1888 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1889 void *daddr, *paddr;
1890 sector_t tmp_sec = start_sec;
1891 sector_t sector;
1892 int ppage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001893
1894 sector = do_div(tmp_sec, sdebug_store_sectors);
1895
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001896 BUG_ON(scsi_sg_count(SCpnt) == 0);
1897 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1898
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001899 ppage_offset = 0;
1900
1901 /* For each data page */
1902 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
Cong Wang77dfce02011-11-25 23:14:23 +08001903 daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
Akinobu Mitafc3fc352013-06-29 17:59:15 +09001904 paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001905
1906 /* For each sector-sized chunk in data page */
Akinobu Mita518d9df2013-06-29 17:59:14 +09001907 for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001908
1909 /* If we're at the end of the current
1910 * protection page advance to the next one
1911 */
1912 if (ppage_offset >= psgl->length) {
Cong Wang77dfce02011-11-25 23:14:23 +08001913 kunmap_atomic(paddr);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001914 psgl = sg_next(psgl);
1915 BUG_ON(psgl == NULL);
Cong Wang77dfce02011-11-25 23:14:23 +08001916 paddr = kmap_atomic(sg_page(psgl))
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001917 + psgl->offset;
1918 ppage_offset = 0;
1919 }
1920
1921 sdt = paddr + ppage_offset;
1922
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09001923 ret = dif_verify(sdt, daddr + j, start_sec, ei_lba);
1924 if (ret) {
Akinobu Mita518d9df2013-06-29 17:59:14 +09001925 dump_sector(daddr + j, scsi_debug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04001926 goto out;
1927 }
1928
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001929 /* Would be great to copy this in bigger
1930 * chunks. However, for the sake of
1931 * correctness we need to verify each sector
1932 * before writing it to "stable" storage
1933 */
Akinobu Mitae18d8be2013-06-29 17:59:18 +09001934 memcpy(dif_storep + sector, sdt, sizeof(*sdt));
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001935
1936 sector++;
1937
1938 if (sector == sdebug_store_sectors)
1939 sector = 0; /* Force wrap */
1940
1941 start_sec++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001942 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001943 ppage_offset += sizeof(struct sd_dif_tuple);
1944 }
1945
Akinobu Mitafc3fc352013-06-29 17:59:15 +09001946 kunmap_atomic(paddr);
Cong Wang77dfce02011-11-25 23:14:23 +08001947 kunmap_atomic(daddr);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001948 }
1949
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001950 dix_writes++;
1951
1952 return 0;
1953
1954out:
1955 dif_errors++;
Cong Wang77dfce02011-11-25 23:14:23 +08001956 kunmap_atomic(paddr);
Akinobu Mitafc3fc352013-06-29 17:59:15 +09001957 kunmap_atomic(daddr);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001958 return ret;
1959}
1960
Akinobu Mitab90ebc32013-04-16 22:11:58 +09001961static unsigned long lba_to_map_index(sector_t lba)
1962{
1963 if (scsi_debug_unmap_alignment) {
1964 lba += scsi_debug_unmap_granularity -
1965 scsi_debug_unmap_alignment;
1966 }
1967 do_div(lba, scsi_debug_unmap_granularity);
1968
1969 return lba;
1970}
1971
1972static sector_t map_index_to_lba(unsigned long index)
1973{
1974 return index * scsi_debug_unmap_granularity -
1975 scsi_debug_unmap_alignment;
1976}
1977
Martin K. Petersen44d92692009-10-15 14:45:27 -04001978static unsigned int map_state(sector_t lba, unsigned int *num)
1979{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09001980 sector_t end;
1981 unsigned int mapped;
1982 unsigned long index;
1983 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001984
Akinobu Mitab90ebc32013-04-16 22:11:58 +09001985 index = lba_to_map_index(lba);
1986 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001987
1988 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09001989 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001990 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09001991 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001992
Akinobu Mitab90ebc32013-04-16 22:11:58 +09001993 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04001994 *num = end - lba;
1995
1996 return mapped;
1997}
1998
1999static void map_region(sector_t lba, unsigned int len)
2000{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002001 sector_t end = lba + len;
2002
Martin K. Petersen44d92692009-10-15 14:45:27 -04002003 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002004 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002005
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002006 if (index < map_size)
2007 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002008
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002009 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002010 }
2011}
2012
2013static void unmap_region(sector_t lba, unsigned int len)
2014{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002015 sector_t end = lba + len;
2016
Martin K. Petersen44d92692009-10-15 14:45:27 -04002017 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002018 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002019
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002020 if (lba == map_index_to_lba(index) &&
2021 lba + scsi_debug_unmap_granularity <= end &&
2022 index < map_size) {
2023 clear_bit(index, map_storep);
2024 if (scsi_debug_lbprz) {
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002025 memset(fake_storep +
Akinobu Mitacc34a8e2013-04-16 22:11:57 +09002026 lba * scsi_debug_sector_size, 0,
2027 scsi_debug_sector_size *
2028 scsi_debug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002029 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002030 if (dif_storep) {
2031 memset(dif_storep + lba, 0xff,
2032 sizeof(*dif_storep) *
2033 scsi_debug_unmap_granularity);
2034 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002035 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002036 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002037 }
2038}
2039
FUJITA Tomonori19789102008-03-30 00:59:56 +09002040static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002041 unsigned int num, struct sdebug_dev_info *devip,
2042 u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043{
2044 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002045 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046
FUJITA Tomonori19789102008-03-30 00:59:56 +09002047 ret = check_device_access_params(devip, lba, num);
2048 if (ret)
2049 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002051 /* DIX + T10 DIF */
2052 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002053 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002054
2055 if (prot_ret) {
2056 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2057 return illegal_condition_result;
2058 }
2059 }
2060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002062 ret = do_device_access(SCpnt, devip, lba, num, 1);
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002063 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002064 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002066 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002068 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002070 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04002071 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002072
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 return 0;
2074}
2075
Martin K. Petersen44d92692009-10-15 14:45:27 -04002076static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
2077 unsigned int num, struct sdebug_dev_info *devip,
2078 u32 ei_lba, unsigned int unmap)
2079{
2080 unsigned long iflags;
2081 unsigned long long i;
2082 int ret;
2083
2084 ret = check_device_access_params(devip, lba, num);
2085 if (ret)
2086 return ret;
2087
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002088 if (num > scsi_debug_write_same_length) {
2089 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2090 0);
2091 return check_condition_result;
2092 }
2093
Martin K. Petersen44d92692009-10-15 14:45:27 -04002094 write_lock_irqsave(&atomic_rw, iflags);
2095
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002096 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002097 unmap_region(lba, num);
2098 goto out;
2099 }
2100
2101 /* Else fetch one logical block */
2102 ret = fetch_to_dev_buffer(scmd,
2103 fake_storep + (lba * scsi_debug_sector_size),
2104 scsi_debug_sector_size);
2105
2106 if (-1 == ret) {
2107 write_unlock_irqrestore(&atomic_rw, iflags);
2108 return (DID_ERROR << 16);
2109 } else if ((ret < (num * scsi_debug_sector_size)) &&
2110 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2111 printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
2112 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
2113
2114 /* Copy first sector to remaining blocks */
2115 for (i = 1 ; i < num ; i++)
2116 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2117 fake_storep + (lba * scsi_debug_sector_size),
2118 scsi_debug_sector_size);
2119
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09002120 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04002121 map_region(lba, num);
2122out:
2123 write_unlock_irqrestore(&atomic_rw, iflags);
2124
2125 return 0;
2126}
2127
2128struct unmap_block_desc {
2129 __be64 lba;
2130 __be32 blocks;
2131 __be32 __reserved;
2132};
2133
2134static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2135{
2136 unsigned char *buf;
2137 struct unmap_block_desc *desc;
2138 unsigned int i, payload_len, descriptors;
2139 int ret;
2140
2141 ret = check_readiness(scmd, 1, devip);
2142 if (ret)
2143 return ret;
2144
2145 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2146 BUG_ON(scsi_bufflen(scmd) != payload_len);
2147
2148 descriptors = (payload_len - 8) / 16;
2149
2150 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2151 if (!buf)
2152 return check_condition_result;
2153
2154 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2155
2156 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2157 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2158
2159 desc = (void *)&buf[8];
2160
2161 for (i = 0 ; i < descriptors ; i++) {
2162 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2163 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2164
2165 ret = check_device_access_params(devip, lba, num);
2166 if (ret)
2167 goto out;
2168
2169 unmap_region(lba, num);
2170 }
2171
2172 ret = 0;
2173
2174out:
2175 kfree(buf);
2176
2177 return ret;
2178}
2179
2180#define SDEBUG_GET_LBA_STATUS_LEN 32
2181
2182static int resp_get_lba_status(struct scsi_cmnd * scmd,
2183 struct sdebug_dev_info * devip)
2184{
2185 unsigned long long lba;
2186 unsigned int alloc_len, mapped, num;
2187 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2188 int ret;
2189
2190 ret = check_readiness(scmd, 1, devip);
2191 if (ret)
2192 return ret;
2193
2194 lba = get_unaligned_be64(&scmd->cmnd[2]);
2195 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2196
2197 if (alloc_len < 24)
2198 return 0;
2199
2200 ret = check_device_access_params(devip, lba, 1);
2201 if (ret)
2202 return ret;
2203
2204 mapped = map_state(lba, &num);
2205
2206 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertde13e962012-01-19 19:30:00 -05002207 put_unaligned_be32(20, &arr[0]); /* Parameter Data Length */
Martin K. Petersen44d92692009-10-15 14:45:27 -04002208 put_unaligned_be64(lba, &arr[8]); /* LBA */
2209 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2210 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2211
2212 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2213}
2214
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002215#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
2217static int resp_report_luns(struct scsi_cmnd * scp,
2218 struct sdebug_dev_info * devip)
2219{
2220 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002221 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 unsigned char *cmd = (unsigned char *)scp->cmnd;
2223 int select_report = (int)cmd[2];
2224 struct scsi_lun *one_lun;
2225 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002226 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
2228 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002229 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2231 0);
2232 return check_condition_result;
2233 }
2234 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2235 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2236 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002237 if (1 == select_report)
2238 lun_cnt = 0;
2239 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2240 --lun_cnt;
2241 wlun = (select_report > 0) ? 1 : 0;
2242 num = lun_cnt + wlun;
2243 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2244 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2245 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2246 sizeof(struct scsi_lun)), num);
2247 if (n < num) {
2248 wlun = 0;
2249 lun_cnt = n;
2250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002252 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2253 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2254 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2255 i++, lun++) {
2256 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 if (upper)
2258 one_lun[i].scsi_lun[0] =
2259 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002260 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 if (wlun) {
2263 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2264 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2265 i++;
2266 }
2267 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 return fill_from_dev_buffer(scp, arr,
2269 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2270}
2271
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002272static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2273 unsigned int num, struct sdebug_dev_info *devip)
2274{
2275 int i, j, ret = -1;
2276 unsigned char *kaddr, *buf;
2277 unsigned int offset;
2278 struct scatterlist *sg;
2279 struct scsi_data_buffer *sdb = scsi_in(scp);
2280
2281 /* better not to use temporary buffer. */
2282 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2283 if (!buf)
2284 return ret;
2285
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002286 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002287
2288 offset = 0;
2289 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
Cong Wang77dfce02011-11-25 23:14:23 +08002290 kaddr = (unsigned char *)kmap_atomic(sg_page(sg));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002291 if (!kaddr)
2292 goto out;
2293
2294 for (j = 0; j < sg->length; j++)
2295 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2296
2297 offset += sg->length;
Cong Wang77dfce02011-11-25 23:14:23 +08002298 kunmap_atomic(kaddr);
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002299 }
2300 ret = 0;
2301out:
2302 kfree(buf);
2303
2304 return ret;
2305}
2306
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307/* When timer goes off this function is called. */
2308static void timer_intr_handler(unsigned long indx)
2309{
2310 struct sdebug_queued_cmd * sqcp;
2311 unsigned long iflags;
2312
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002313 if (indx >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2315 "large\n");
2316 return;
2317 }
2318 spin_lock_irqsave(&queued_arr_lock, iflags);
2319 sqcp = &queued_arr[(int)indx];
2320 if (! sqcp->in_use) {
2321 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2322 "interrupt\n");
2323 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2324 return;
2325 }
2326 sqcp->in_use = 0;
2327 if (sqcp->done_funct) {
2328 sqcp->a_cmnd->result = sqcp->scsi_result;
2329 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2330 }
2331 sqcp->done_funct = NULL;
2332 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2333}
2334
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002336static struct sdebug_dev_info *
2337sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002338{
2339 struct sdebug_dev_info *devip;
2340
2341 devip = kzalloc(sizeof(*devip), flags);
2342 if (devip) {
2343 devip->sdbg_host = sdbg_host;
2344 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2345 }
2346 return devip;
2347}
2348
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2350{
2351 struct sdebug_host_info * sdbg_host;
2352 struct sdebug_dev_info * open_devip = NULL;
2353 struct sdebug_dev_info * devip =
2354 (struct sdebug_dev_info *)sdev->hostdata;
2355
2356 if (devip)
2357 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002358 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2359 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 printk(KERN_ERR "Host info NULL\n");
2361 return NULL;
2362 }
2363 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2364 if ((devip->used) && (devip->channel == sdev->channel) &&
2365 (devip->target == sdev->id) &&
2366 (devip->lun == sdev->lun))
2367 return devip;
2368 else {
2369 if ((!devip->used) && (!open_devip))
2370 open_devip = devip;
2371 }
2372 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002373 if (!open_devip) { /* try and make a new one */
2374 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2375 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002377 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 return NULL;
2379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002381
2382 open_devip->channel = sdev->channel;
2383 open_devip->target = sdev->id;
2384 open_devip->lun = sdev->lun;
2385 open_devip->sdbg_host = sdbg_host;
2386 open_devip->reset = 1;
2387 open_devip->used = 1;
2388 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2389 if (scsi_debug_dsense)
2390 open_devip->sense_buff[0] = 0x72;
2391 else {
2392 open_devip->sense_buff[0] = 0x70;
2393 open_devip->sense_buff[7] = 0xa;
2394 }
2395 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2396 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2397
2398 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399}
2400
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002401static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002403 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2404 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2405 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002406 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002407 return 0;
2408}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002410static int scsi_debug_slave_configure(struct scsi_device *sdp)
2411{
2412 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002413
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002415 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2416 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2417 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2418 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2419 devip = devInfoReg(sdp);
2420 if (NULL == devip)
2421 return 1; /* no resources, will be marked offline */
2422 sdp->hostdata = devip;
2423 if (sdp->host->cmd_per_lun)
2424 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2425 sdp->host->cmd_per_lun);
2426 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002427 if (scsi_debug_no_uld)
2428 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002429 return 0;
2430}
2431
2432static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2433{
2434 struct sdebug_dev_info *devip =
2435 (struct sdebug_dev_info *)sdp->hostdata;
2436
2437 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2438 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2439 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2440 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002441 /* make this slot available for re-use */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002442 devip->used = 0;
2443 sdp->hostdata = NULL;
2444 }
2445}
2446
2447/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2448static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2449{
2450 unsigned long iflags;
2451 int k;
2452 struct sdebug_queued_cmd *sqcp;
2453
2454 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002455 for (k = 0; k < scsi_debug_max_queue; ++k) {
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002456 sqcp = &queued_arr[k];
2457 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2458 del_timer_sync(&sqcp->cmnd_timer);
2459 sqcp->in_use = 0;
2460 sqcp->a_cmnd = NULL;
2461 break;
2462 }
2463 }
2464 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002465 return (k < scsi_debug_max_queue) ? 1 : 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002466}
2467
2468/* Deletes (stops) timers of all queued commands */
2469static void stop_all_queued(void)
2470{
2471 unsigned long iflags;
2472 int k;
2473 struct sdebug_queued_cmd *sqcp;
2474
2475 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002476 for (k = 0; k < scsi_debug_max_queue; ++k) {
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002477 sqcp = &queued_arr[k];
2478 if (sqcp->in_use && sqcp->a_cmnd) {
2479 del_timer_sync(&sqcp->cmnd_timer);
2480 sqcp->in_use = 0;
2481 sqcp->a_cmnd = NULL;
2482 }
2483 }
2484 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485}
2486
2487static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2488{
2489 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2490 printk(KERN_INFO "scsi_debug: abort\n");
2491 ++num_aborts;
2492 stop_queued_cmnd(SCpnt);
2493 return SUCCESS;
2494}
2495
2496static int scsi_debug_biosparam(struct scsi_device *sdev,
2497 struct block_device * bdev, sector_t capacity, int *info)
2498{
2499 int res;
2500 unsigned char *buf;
2501
2502 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2503 printk(KERN_INFO "scsi_debug: biosparam\n");
2504 buf = scsi_bios_ptable(bdev);
2505 if (buf) {
2506 res = scsi_partsize(buf, capacity,
2507 &info[2], &info[0], &info[1]);
2508 kfree(buf);
2509 if (! res)
2510 return res;
2511 }
2512 info[0] = sdebug_heads;
2513 info[1] = sdebug_sectors_per;
2514 info[2] = sdebug_cylinders_per;
2515 return 0;
2516}
2517
2518static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2519{
2520 struct sdebug_dev_info * devip;
2521
2522 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2523 printk(KERN_INFO "scsi_debug: device_reset\n");
2524 ++num_dev_resets;
2525 if (SCpnt) {
2526 devip = devInfoReg(SCpnt->device);
2527 if (devip)
2528 devip->reset = 1;
2529 }
2530 return SUCCESS;
2531}
2532
2533static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2534{
2535 struct sdebug_host_info *sdbg_host;
2536 struct sdebug_dev_info * dev_info;
2537 struct scsi_device * sdp;
2538 struct Scsi_Host * hp;
2539
2540 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2541 printk(KERN_INFO "scsi_debug: bus_reset\n");
2542 ++num_bus_resets;
2543 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002544 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 if (sdbg_host) {
2546 list_for_each_entry(dev_info,
2547 &sdbg_host->dev_info_list,
2548 dev_list)
2549 dev_info->reset = 1;
2550 }
2551 }
2552 return SUCCESS;
2553}
2554
2555static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2556{
2557 struct sdebug_host_info * sdbg_host;
2558 struct sdebug_dev_info * dev_info;
2559
2560 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2561 printk(KERN_INFO "scsi_debug: host_reset\n");
2562 ++num_host_resets;
2563 spin_lock(&sdebug_host_list_lock);
2564 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2565 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2566 dev_list)
2567 dev_info->reset = 1;
2568 }
2569 spin_unlock(&sdebug_host_list_lock);
2570 stop_all_queued();
2571 return SUCCESS;
2572}
2573
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574/* Initializes timers in queued array */
2575static void __init init_all_queued(void)
2576{
2577 unsigned long iflags;
2578 int k;
2579 struct sdebug_queued_cmd * sqcp;
2580
2581 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002582 for (k = 0; k < scsi_debug_max_queue; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 sqcp = &queued_arr[k];
2584 init_timer(&sqcp->cmnd_timer);
2585 sqcp->in_use = 0;
2586 sqcp->a_cmnd = NULL;
2587 }
2588 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2589}
2590
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002591static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002592 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593{
2594 struct partition * pp;
2595 int starts[SDEBUG_MAX_PARTS + 2];
2596 int sectors_per_part, num_sectors, k;
2597 int heads_by_sects, start_sec, end_sec;
2598
2599 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002600 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 return;
2602 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2603 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2604 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2605 "partitions to %d\n", SDEBUG_MAX_PARTS);
2606 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002607 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 sectors_per_part = (num_sectors - sdebug_sectors_per)
2609 / scsi_debug_num_parts;
2610 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2611 starts[0] = sdebug_sectors_per;
2612 for (k = 1; k < scsi_debug_num_parts; ++k)
2613 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2614 * heads_by_sects;
2615 starts[scsi_debug_num_parts] = num_sectors;
2616 starts[scsi_debug_num_parts + 1] = 0;
2617
2618 ramp[510] = 0x55; /* magic partition markings */
2619 ramp[511] = 0xAA;
2620 pp = (struct partition *)(ramp + 0x1be);
2621 for (k = 0; starts[k + 1]; ++k, ++pp) {
2622 start_sec = starts[k];
2623 end_sec = starts[k + 1] - 1;
2624 pp->boot_ind = 0;
2625
2626 pp->cyl = start_sec / heads_by_sects;
2627 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2628 / sdebug_sectors_per;
2629 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2630
2631 pp->end_cyl = end_sec / heads_by_sects;
2632 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2633 / sdebug_sectors_per;
2634 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2635
2636 pp->start_sect = start_sec;
2637 pp->nr_sects = end_sec - start_sec + 1;
2638 pp->sys_ind = 0x83; /* plain Linux partition */
2639 }
2640}
2641
2642static int schedule_resp(struct scsi_cmnd * cmnd,
2643 struct sdebug_dev_info * devip,
2644 done_funct_t done, int scsi_result, int delta_jiff)
2645{
2646 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2647 if (scsi_result) {
2648 struct scsi_device * sdp = cmnd->device;
2649
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002650 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2651 "non-zero result=0x%x\n", sdp->host->host_no,
2652 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 }
2654 }
2655 if (cmnd && devip) {
2656 /* simulate autosense by this driver */
2657 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2658 memcpy(cmnd->sense_buffer, devip->sense_buff,
2659 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2660 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2661 }
2662 if (delta_jiff <= 0) {
2663 if (cmnd)
2664 cmnd->result = scsi_result;
2665 if (done)
2666 done(cmnd);
2667 return 0;
2668 } else {
2669 unsigned long iflags;
2670 int k;
2671 struct sdebug_queued_cmd * sqcp = NULL;
2672
2673 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002674 for (k = 0; k < scsi_debug_max_queue; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 sqcp = &queued_arr[k];
2676 if (! sqcp->in_use)
2677 break;
2678 }
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002679 if (k >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2681 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2682 return 1; /* report busy to mid level */
2683 }
2684 sqcp->in_use = 1;
2685 sqcp->a_cmnd = cmnd;
2686 sqcp->scsi_result = scsi_result;
2687 sqcp->done_funct = done;
2688 sqcp->cmnd_timer.function = timer_intr_handler;
2689 sqcp->cmnd_timer.data = k;
2690 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2691 add_timer(&sqcp->cmnd_timer);
2692 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2693 if (cmnd)
2694 cmnd->result = 0;
2695 return 0;
2696 }
2697}
Douglas Gilbert23183912006-09-16 20:30:47 -04002698/* Note: The following macros create attribute files in the
2699 /sys/module/scsi_debug/parameters directory. Unfortunately this
2700 driver is unaware of a change and cannot trigger auxiliary actions
2701 as it can when the corresponding attribute in the
2702 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2703 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002704module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002705module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002706module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2707module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002708module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2709module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002710module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2711module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002712module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002713module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2714module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
2715module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
2716module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002717module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002718module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002719module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002720module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002721module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002722module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002723module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2724module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002725module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002726module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002727module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002728module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
Martin Pittd9867882012-09-06 12:04:33 +02002729module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002730module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002731module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
2732module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
2733module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
2734module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
2735module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002736module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002737module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2738 S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002739module_param_named(write_same_length, scsi_debug_write_same_length, int,
2740 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741
2742MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2743MODULE_DESCRIPTION("SCSI debug adapter driver");
2744MODULE_LICENSE("GPL");
2745MODULE_VERSION(SCSI_DEBUG_VERSION);
2746
2747MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002748MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002750MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002751MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2752MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002753MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002754MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002755MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002756MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2757MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
2758MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
2759MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002760MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002761MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002762MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002763MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002764MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002765MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002767MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002768MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002769MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002770MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02002772MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002774MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002775MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
2776MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04002777MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
2778MODULE_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 -05002779MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
2780MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
2781MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
2783static char sdebug_info[256];
2784
2785static const char * scsi_debug_info(struct Scsi_Host * shp)
2786{
2787 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2788 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2789 scsi_debug_version_date, scsi_debug_dev_size_mb,
2790 scsi_debug_opts);
2791 return sdebug_info;
2792}
2793
2794/* scsi_debug_proc_info
2795 * Used if the driver currently has no own support for /proc/scsi
2796 */
Al Viroc8ed5552013-03-31 01:46:06 -04002797static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798{
Al Viroc8ed5552013-03-31 01:46:06 -04002799 char arr[16];
2800 int opts;
2801 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
Al Viroc8ed5552013-03-31 01:46:06 -04002803 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2804 return -EACCES;
2805 memcpy(arr, buffer, minLen);
2806 arr[minLen] = '\0';
2807 if (1 != sscanf(arr, "%d", &opts))
2808 return -EINVAL;
2809 scsi_debug_opts = opts;
2810 if (scsi_debug_every_nth != 0)
2811 scsi_debug_cmnd_count = 0;
2812 return length;
2813}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Al Viroc8ed5552013-03-31 01:46:06 -04002815static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
2816{
2817 seq_printf(m, "scsi_debug adapter driver, version "
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 "%s [%s]\n"
2819 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2820 "every_nth=%d(curr:%d)\n"
2821 "delay=%d, max_luns=%d, scsi_level=%d\n"
2822 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2823 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002824 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2826 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2827 scsi_debug_cmnd_count, scsi_debug_delay,
2828 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002829 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2830 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002831 num_host_resets, dix_reads, dix_writes, dif_errors);
Al Viroc8ed5552013-03-31 01:46:06 -04002832 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833}
2834
2835static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2836{
2837 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2838}
2839
2840static ssize_t sdebug_delay_store(struct device_driver * ddp,
2841 const char * buf, size_t count)
2842{
2843 int delay;
2844 char work[20];
2845
2846 if (1 == sscanf(buf, "%10s", work)) {
2847 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2848 scsi_debug_delay = delay;
2849 return count;
2850 }
2851 }
2852 return -EINVAL;
2853}
2854DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2855 sdebug_delay_store);
2856
2857static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2858{
2859 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2860}
2861
2862static ssize_t sdebug_opts_store(struct device_driver * ddp,
2863 const char * buf, size_t count)
2864{
2865 int opts;
2866 char work[20];
2867
2868 if (1 == sscanf(buf, "%10s", work)) {
2869 if (0 == strnicmp(work,"0x", 2)) {
2870 if (1 == sscanf(&work[2], "%x", &opts))
2871 goto opts_done;
2872 } else {
2873 if (1 == sscanf(work, "%d", &opts))
2874 goto opts_done;
2875 }
2876 }
2877 return -EINVAL;
2878opts_done:
2879 scsi_debug_opts = opts;
2880 scsi_debug_cmnd_count = 0;
2881 return count;
2882}
2883DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2884 sdebug_opts_store);
2885
2886static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2887{
2888 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2889}
2890static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2891 const char * buf, size_t count)
2892{
2893 int n;
2894
2895 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2896 scsi_debug_ptype = n;
2897 return count;
2898 }
2899 return -EINVAL;
2900}
2901DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2902
2903static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2904{
2905 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2906}
2907static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2908 const char * buf, size_t count)
2909{
2910 int n;
2911
2912 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2913 scsi_debug_dsense = n;
2914 return count;
2915 }
2916 return -EINVAL;
2917}
2918DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2919 sdebug_dsense_store);
2920
Douglas Gilbert23183912006-09-16 20:30:47 -04002921static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2922{
2923 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2924}
2925static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2926 const char * buf, size_t count)
2927{
2928 int n;
2929
2930 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2931 scsi_debug_fake_rw = n;
2932 return count;
2933 }
2934 return -EINVAL;
2935}
2936DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2937 sdebug_fake_rw_store);
2938
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002939static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2940{
2941 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2942}
2943static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2944 const char * buf, size_t count)
2945{
2946 int n;
2947
2948 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2949 scsi_debug_no_lun_0 = n;
2950 return count;
2951 }
2952 return -EINVAL;
2953}
2954DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2955 sdebug_no_lun_0_store);
2956
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2958{
2959 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2960}
2961static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2962 const char * buf, size_t count)
2963{
2964 int n;
2965
2966 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2967 scsi_debug_num_tgts = n;
2968 sdebug_max_tgts_luns();
2969 return count;
2970 }
2971 return -EINVAL;
2972}
2973DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2974 sdebug_num_tgts_store);
2975
2976static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2977{
2978 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2979}
2980DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2981
2982static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2983{
2984 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2985}
2986DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2987
2988static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2989{
2990 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2991}
2992static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2993 const char * buf, size_t count)
2994{
2995 int nth;
2996
2997 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2998 scsi_debug_every_nth = nth;
2999 scsi_debug_cmnd_count = 0;
3000 return count;
3001 }
3002 return -EINVAL;
3003}
3004DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
3005 sdebug_every_nth_store);
3006
3007static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
3008{
3009 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
3010}
3011static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
3012 const char * buf, size_t count)
3013{
3014 int n;
3015
3016 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3017 scsi_debug_max_luns = n;
3018 sdebug_max_tgts_luns();
3019 return count;
3020 }
3021 return -EINVAL;
3022}
3023DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
3024 sdebug_max_luns_store);
3025
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003026static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
3027{
3028 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
3029}
3030static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
3031 const char * buf, size_t count)
3032{
3033 int n;
3034
3035 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
3036 (n <= SCSI_DEBUG_CANQUEUE)) {
3037 scsi_debug_max_queue = n;
3038 return count;
3039 }
3040 return -EINVAL;
3041}
3042DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
3043 sdebug_max_queue_store);
3044
3045static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
3046{
3047 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
3048}
3049DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
3050
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
3052{
3053 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
3054}
3055DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
3056
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003057static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
3058{
3059 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3060}
3061static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
3062 const char * buf, size_t count)
3063{
3064 int n;
3065
3066 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3067 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003068
3069 sdebug_capacity = get_sdebug_capacity();
3070
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003071 return count;
3072 }
3073 return -EINVAL;
3074}
3075DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
3076 sdebug_virtual_gb_store);
3077
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
3079{
3080 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
3081}
3082
3083static ssize_t sdebug_add_host_store(struct device_driver * ddp,
3084 const char * buf, size_t count)
3085{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003086 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003088 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 if (delta_hosts > 0) {
3091 do {
3092 sdebug_add_adapter();
3093 } while (--delta_hosts);
3094 } else if (delta_hosts < 0) {
3095 do {
3096 sdebug_remove_adapter();
3097 } while (++delta_hosts);
3098 }
3099 return count;
3100}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003101DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 sdebug_add_host_store);
3103
Douglas Gilbert23183912006-09-16 20:30:47 -04003104static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
3105 char * buf)
3106{
3107 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3108}
3109static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
3110 const char * buf, size_t count)
3111{
3112 int n;
3113
3114 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3115 scsi_debug_vpd_use_hostno = n;
3116 return count;
3117 }
3118 return -EINVAL;
3119}
3120DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
3121 sdebug_vpd_use_hostno_store);
3122
Martin K. Petersen597136a2008-06-05 00:12:59 -04003123static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3124{
3125 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3126}
3127DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3128
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003129static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3130{
3131 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3132}
3133DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3134
3135static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3136{
3137 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3138}
3139DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3140
3141static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3142{
3143 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3144}
3145DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3146
3147static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3148{
3149 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3150}
3151DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3152
Martin K. Petersen44d92692009-10-15 14:45:27 -04003153static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
3154{
3155 ssize_t count;
3156
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003157 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003158 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3159 sdebug_store_sectors);
3160
3161 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3162
3163 buf[count++] = '\n';
3164 buf[count++] = 0;
3165
3166 return count;
3167}
3168DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
3169
Martin Pittd9867882012-09-06 12:04:33 +02003170static ssize_t sdebug_removable_show(struct device_driver *ddp,
3171 char *buf)
3172{
3173 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0);
3174}
3175static ssize_t sdebug_removable_store(struct device_driver *ddp,
3176 const char *buf, size_t count)
3177{
3178 int n;
3179
3180 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3181 scsi_debug_removable = (n > 0);
3182 return count;
3183 }
3184 return -EINVAL;
3185}
3186DRIVER_ATTR(removable, S_IRUGO | S_IWUSR, sdebug_removable_show,
3187 sdebug_removable_store);
3188
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003189
Douglas Gilbert23183912006-09-16 20:30:47 -04003190/* Note: The following function creates attribute files in the
3191 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3192 files (over those found in the /sys/module/scsi_debug/parameters
3193 directory) is that auxiliary actions can be triggered when an attribute
3194 is changed. For example see: sdebug_add_host_store() above.
3195 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003196static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003198 int ret;
3199
3200 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3201 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
3202 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3203 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3204 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04003205 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003206 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003207 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
Douglas Gilbert23183912006-09-16 20:30:47 -04003208 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003209 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003210 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003211 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003212 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3213 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
Martin Pittd9867882012-09-06 12:04:33 +02003214 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_removable);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003215 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04003216 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
3217 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003218 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003219 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3220 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3221 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3222 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003223 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003224 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225}
3226
3227static void do_remove_driverfs_files(void)
3228{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003229 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003230 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3231 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3232 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3233 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003234 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04003235 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3236 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
3238 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
3239 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Martin Pittd9867882012-09-06 12:04:33 +02003240 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_removable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003242 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003243 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
Douglas Gilbert23183912006-09-16 20:30:47 -04003244 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003245 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003247 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
3249 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3250 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3251 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
3252 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3253}
3254
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003255struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003256
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257static int __init scsi_debug_init(void)
3258{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003259 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 int host_to_add;
3261 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003262 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263
Martin K. Petersen597136a2008-06-05 00:12:59 -04003264 switch (scsi_debug_sector_size) {
3265 case 512:
3266 case 1024:
3267 case 2048:
3268 case 4096:
3269 break;
3270 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003271 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04003272 scsi_debug_sector_size);
3273 return -EINVAL;
3274 }
3275
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003276 switch (scsi_debug_dif) {
3277
3278 case SD_DIF_TYPE0_PROTECTION:
3279 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003280 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003281 case SD_DIF_TYPE3_PROTECTION:
3282 break;
3283
3284 default:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003285 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003286 return -EINVAL;
3287 }
3288
3289 if (scsi_debug_guard > 1) {
3290 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3291 return -EINVAL;
3292 }
3293
3294 if (scsi_debug_ato > 1) {
3295 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3296 return -EINVAL;
3297 }
3298
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003299 if (scsi_debug_physblk_exp > 15) {
3300 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3301 scsi_debug_physblk_exp);
3302 return -EINVAL;
3303 }
3304
3305 if (scsi_debug_lowest_aligned > 0x3fff) {
3306 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3307 scsi_debug_lowest_aligned);
3308 return -EINVAL;
3309 }
3310
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 if (scsi_debug_dev_size_mb < 1)
3312 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003313 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003314 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003315 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
3317 /* play around with geometry, don't waste too much on track 0 */
3318 sdebug_heads = 8;
3319 sdebug_sectors_per = 32;
3320 if (scsi_debug_dev_size_mb >= 16)
3321 sdebug_heads = 32;
3322 else if (scsi_debug_dev_size_mb >= 256)
3323 sdebug_heads = 64;
3324 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3325 (sdebug_sectors_per * sdebug_heads);
3326 if (sdebug_cylinders_per >= 1024) {
3327 /* other LLDs do this; implies >= 1GB ram disk ... */
3328 sdebug_heads = 255;
3329 sdebug_sectors_per = 63;
3330 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3331 (sdebug_sectors_per * sdebug_heads);
3332 }
3333
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 fake_storep = vmalloc(sz);
3335 if (NULL == fake_storep) {
3336 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
3337 return -ENOMEM;
3338 }
3339 memset(fake_storep, 0, sz);
3340 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003341 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342
Akinobu Mita7cb69d02013-06-29 17:59:16 +09003343 if (scsi_debug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003344 int dif_size;
3345
3346 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3347 dif_storep = vmalloc(dif_size);
3348
3349 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3350 dif_size, dif_storep);
3351
3352 if (dif_storep == NULL) {
3353 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3354 ret = -ENOMEM;
3355 goto free_vm;
3356 }
3357
3358 memset(dif_storep, 0xff, dif_size);
3359 }
3360
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003361 /* Logical Block Provisioning */
3362 if (scsi_debug_lbp()) {
Martin K. Petersen60147592010-08-19 11:49:00 -04003363 scsi_debug_unmap_max_blocks =
3364 clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
3365
3366 scsi_debug_unmap_max_desc =
3367 clamp(scsi_debug_unmap_max_desc, 0U, 256U);
3368
3369 scsi_debug_unmap_granularity =
3370 clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
3371
3372 if (scsi_debug_unmap_alignment &&
Akinobu Mitaac170782013-04-16 22:11:56 +09003373 scsi_debug_unmap_granularity <=
3374 scsi_debug_unmap_alignment) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003375 printk(KERN_ERR
Akinobu Mitaac170782013-04-16 22:11:56 +09003376 "%s: ERR: unmap_granularity <= unmap_alignment\n",
Martin K. Petersen44d92692009-10-15 14:45:27 -04003377 __func__);
3378 return -EINVAL;
3379 }
3380
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003381 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
3382 map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003383
3384 printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
3385 map_size);
3386
3387 if (map_storep == NULL) {
3388 printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
3389 ret = -ENOMEM;
3390 goto free_vm;
3391 }
3392
Akinobu Mitab90ebc32013-04-16 22:11:58 +09003393 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003394
3395 /* Map first 1KB for partition table */
3396 if (scsi_debug_num_parts)
3397 map_region(0, 2);
3398 }
3399
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003400 pseudo_primary = root_device_register("pseudo_0");
3401 if (IS_ERR(pseudo_primary)) {
3402 printk(KERN_WARNING "scsi_debug: root_device_register() error\n");
3403 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003404 goto free_vm;
3405 }
3406 ret = bus_register(&pseudo_lld_bus);
3407 if (ret < 0) {
3408 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
3409 ret);
3410 goto dev_unreg;
3411 }
3412 ret = driver_register(&sdebug_driverfs_driver);
3413 if (ret < 0) {
3414 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
3415 ret);
3416 goto bus_unreg;
3417 }
3418 ret = do_create_driverfs_files();
3419 if (ret < 0) {
3420 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
3421 ret);
3422 goto del_files;
3423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003425 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 host_to_add = scsi_debug_add_host;
3428 scsi_debug_add_host = 0;
3429
3430 for (k = 0; k < host_to_add; k++) {
3431 if (sdebug_add_adapter()) {
3432 printk(KERN_ERR "scsi_debug_init: "
3433 "sdebug_add_adapter failed k=%d\n", k);
3434 break;
3435 }
3436 }
3437
3438 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3439 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
3440 scsi_debug_add_host);
3441 }
3442 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003443
3444del_files:
3445 do_remove_driverfs_files();
3446 driver_unregister(&sdebug_driverfs_driver);
3447bus_unreg:
3448 bus_unregister(&pseudo_lld_bus);
3449dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003450 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003451free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003452 if (map_storep)
3453 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003454 if (dif_storep)
3455 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003456 vfree(fake_storep);
3457
3458 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459}
3460
3461static void __exit scsi_debug_exit(void)
3462{
3463 int k = scsi_debug_add_host;
3464
3465 stop_all_queued();
3466 for (; k; k--)
3467 sdebug_remove_adapter();
3468 do_remove_driverfs_files();
3469 driver_unregister(&sdebug_driverfs_driver);
3470 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003471 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003473 if (dif_storep)
3474 vfree(dif_storep);
3475
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 vfree(fake_storep);
3477}
3478
3479device_initcall(scsi_debug_init);
3480module_exit(scsi_debug_exit);
3481
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482static void sdebug_release_adapter(struct device * dev)
3483{
3484 struct sdebug_host_info *sdbg_host;
3485
3486 sdbg_host = to_sdebug_host(dev);
3487 kfree(sdbg_host);
3488}
3489
3490static int sdebug_add_adapter(void)
3491{
3492 int k, devs_per_host;
3493 int error = 0;
3494 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003495 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003497 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 if (NULL == sdbg_host) {
3499 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003500 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 return -ENOMEM;
3502 }
3503
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3505
3506 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3507 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003508 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3509 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003511 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 error = -ENOMEM;
3513 goto clean;
3514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 }
3516
3517 spin_lock(&sdebug_host_list_lock);
3518 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3519 spin_unlock(&sdebug_host_list_lock);
3520
3521 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003522 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003524 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
3526 error = device_register(&sdbg_host->dev);
3527
3528 if (error)
3529 goto clean;
3530
3531 ++scsi_debug_add_host;
3532 return error;
3533
3534clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003535 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3536 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 list_del(&sdbg_devinfo->dev_list);
3538 kfree(sdbg_devinfo);
3539 }
3540
3541 kfree(sdbg_host);
3542 return error;
3543}
3544
3545static void sdebug_remove_adapter(void)
3546{
3547 struct sdebug_host_info * sdbg_host = NULL;
3548
3549 spin_lock(&sdebug_host_list_lock);
3550 if (!list_empty(&sdebug_host_list)) {
3551 sdbg_host = list_entry(sdebug_host_list.prev,
3552 struct sdebug_host_info, host_list);
3553 list_del(&sdbg_host->host_list);
3554 }
3555 spin_unlock(&sdebug_host_list_lock);
3556
3557 if (!sdbg_host)
3558 return;
3559
3560 device_unregister(&sdbg_host->dev);
3561 --scsi_debug_add_host;
3562}
3563
FUJITA Tomonori639db472008-03-20 11:09:19 +09003564static
Jeff Garzikf2812332010-11-16 02:10:29 -05003565int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
FUJITA Tomonori639db472008-03-20 11:09:19 +09003566{
3567 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3568 int len, k;
3569 unsigned int num;
3570 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003571 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003572 int errsts = 0;
3573 int target = SCpnt->device->id;
3574 struct sdebug_dev_info *devip = NULL;
3575 int inj_recovered = 0;
3576 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003577 int inj_dif = 0;
3578 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003579 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003580 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003581
3582 scsi_set_resid(SCpnt, 0);
3583 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3584 printk(KERN_INFO "scsi_debug: cmd ");
3585 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3586 printk("%02x ", (int)cmd[k]);
3587 printk("\n");
3588 }
3589
3590 if (target == SCpnt->device->host->hostt->this_id) {
3591 printk(KERN_INFO "scsi_debug: initiator's id used as "
3592 "target!\n");
3593 return schedule_resp(SCpnt, NULL, done,
3594 DID_NO_CONNECT << 16, 0);
3595 }
3596
3597 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3598 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3599 return schedule_resp(SCpnt, NULL, done,
3600 DID_NO_CONNECT << 16, 0);
3601 devip = devInfoReg(SCpnt->device);
3602 if (NULL == devip)
3603 return schedule_resp(SCpnt, NULL, done,
3604 DID_NO_CONNECT << 16, 0);
3605
3606 if ((scsi_debug_every_nth != 0) &&
3607 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3608 scsi_debug_cmnd_count = 0;
3609 if (scsi_debug_every_nth < -1)
3610 scsi_debug_every_nth = -1;
3611 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3612 return 0; /* ignore command causing timeout */
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -05003613 else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
3614 scsi_medium_access_command(SCpnt))
3615 return 0; /* time out reads and writes */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003616 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3617 inj_recovered = 1; /* to reads and writes below */
3618 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3619 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003620 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3621 inj_dif = 1; /* to reads and writes below */
3622 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3623 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003624 }
3625
3626 if (devip->wlun) {
3627 switch (*cmd) {
3628 case INQUIRY:
3629 case REQUEST_SENSE:
3630 case TEST_UNIT_READY:
3631 case REPORT_LUNS:
3632 break; /* only allowable wlun commands */
3633 default:
3634 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3635 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3636 "not supported for wlun\n", *cmd);
3637 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3638 INVALID_OPCODE, 0);
3639 errsts = check_condition_result;
3640 return schedule_resp(SCpnt, devip, done, errsts,
3641 0);
3642 }
3643 }
3644
3645 switch (*cmd) {
3646 case INQUIRY: /* mandatory, ignore unit attention */
3647 delay_override = 1;
3648 errsts = resp_inquiry(SCpnt, target, devip);
3649 break;
3650 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3651 delay_override = 1;
3652 errsts = resp_requests(SCpnt, devip);
3653 break;
3654 case REZERO_UNIT: /* actually this is REWIND for SSC */
3655 case START_STOP:
3656 errsts = resp_start_stop(SCpnt, devip);
3657 break;
3658 case ALLOW_MEDIUM_REMOVAL:
3659 errsts = check_readiness(SCpnt, 1, devip);
3660 if (errsts)
3661 break;
3662 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3663 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3664 cmd[4] ? "inhibited" : "enabled");
3665 break;
3666 case SEND_DIAGNOSTIC: /* mandatory */
3667 errsts = check_readiness(SCpnt, 1, devip);
3668 break;
3669 case TEST_UNIT_READY: /* mandatory */
3670 delay_override = 1;
3671 errsts = check_readiness(SCpnt, 0, devip);
3672 break;
3673 case RESERVE:
3674 errsts = check_readiness(SCpnt, 1, devip);
3675 break;
3676 case RESERVE_10:
3677 errsts = check_readiness(SCpnt, 1, devip);
3678 break;
3679 case RELEASE:
3680 errsts = check_readiness(SCpnt, 1, devip);
3681 break;
3682 case RELEASE_10:
3683 errsts = check_readiness(SCpnt, 1, devip);
3684 break;
3685 case READ_CAPACITY:
3686 errsts = resp_readcap(SCpnt, devip);
3687 break;
3688 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003689 if (cmd[1] == SAI_READ_CAPACITY_16)
3690 errsts = resp_readcap16(SCpnt, devip);
3691 else if (cmd[1] == SAI_GET_LBA_STATUS) {
3692
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003693 if (scsi_debug_lbp() == 0) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003694 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3695 INVALID_COMMAND_OPCODE, 0);
3696 errsts = check_condition_result;
3697 } else
3698 errsts = resp_get_lba_status(SCpnt, devip);
3699 } else {
FUJITA Tomonori639db472008-03-20 11:09:19 +09003700 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3701 INVALID_OPCODE, 0);
3702 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003703 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09003704 break;
3705 case MAINTENANCE_IN:
3706 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3707 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3708 INVALID_OPCODE, 0);
3709 errsts = check_condition_result;
3710 break;
3711 }
3712 errsts = resp_report_tgtpgs(SCpnt, devip);
3713 break;
3714 case READ_16:
3715 case READ_12:
3716 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003717 /* READ{10,12,16} and DIF Type 2 are natural enemies */
3718 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3719 cmd[1] & 0xe0) {
3720 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3721 INVALID_COMMAND_OPCODE, 0);
3722 errsts = check_condition_result;
3723 break;
3724 }
3725
3726 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3727 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3728 (cmd[1] & 0xe0) == 0)
3729 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3730
3731 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003732 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003733read:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003734 errsts = check_readiness(SCpnt, 0, devip);
3735 if (errsts)
3736 break;
3737 if (scsi_debug_fake_rw)
3738 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003739 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3740 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003741 if (inj_recovered && (0 == errsts)) {
3742 mk_sense_buffer(devip, RECOVERED_ERROR,
3743 THRESHOLD_EXCEEDED, 0);
3744 errsts = check_condition_result;
3745 } else if (inj_transport && (0 == errsts)) {
3746 mk_sense_buffer(devip, ABORTED_COMMAND,
3747 TRANSPORT_PROBLEM, ACK_NAK_TO);
3748 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003749 } else if (inj_dif && (0 == errsts)) {
3750 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3751 errsts = illegal_condition_result;
3752 } else if (inj_dix && (0 == errsts)) {
3753 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3754 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003755 }
3756 break;
3757 case REPORT_LUNS: /* mandatory, ignore unit attention */
3758 delay_override = 1;
3759 errsts = resp_report_luns(SCpnt, devip);
3760 break;
3761 case VERIFY: /* 10 byte SBC-2 command */
3762 errsts = check_readiness(SCpnt, 0, devip);
3763 break;
3764 case WRITE_16:
3765 case WRITE_12:
3766 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003767 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3768 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3769 cmd[1] & 0xe0) {
3770 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3771 INVALID_COMMAND_OPCODE, 0);
3772 errsts = check_condition_result;
3773 break;
3774 }
3775
3776 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3777 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3778 (cmd[1] & 0xe0) == 0)
3779 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3780
3781 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003782 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003783write:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003784 errsts = check_readiness(SCpnt, 0, devip);
3785 if (errsts)
3786 break;
3787 if (scsi_debug_fake_rw)
3788 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003789 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3790 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003791 if (inj_recovered && (0 == errsts)) {
3792 mk_sense_buffer(devip, RECOVERED_ERROR,
3793 THRESHOLD_EXCEEDED, 0);
3794 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003795 } else if (inj_dif && (0 == errsts)) {
3796 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3797 errsts = illegal_condition_result;
3798 } else if (inj_dix && (0 == errsts)) {
3799 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3800 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003801 }
3802 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003803 case WRITE_SAME_16:
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003804 case WRITE_SAME:
Martin K. Petersen60147592010-08-19 11:49:00 -04003805 if (cmd[1] & 0x8) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003806 if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
3807 (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
Martin K. Petersen60147592010-08-19 11:49:00 -04003808 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3809 INVALID_FIELD_IN_CDB, 0);
3810 errsts = check_condition_result;
3811 } else
3812 unmap = 1;
3813 }
3814 if (errsts)
3815 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003816 errsts = check_readiness(SCpnt, 0, devip);
3817 if (errsts)
3818 break;
3819 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3820 errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
3821 break;
3822 case UNMAP:
3823 errsts = check_readiness(SCpnt, 0, devip);
3824 if (errsts)
3825 break;
3826
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003827 if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003828 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3829 INVALID_COMMAND_OPCODE, 0);
3830 errsts = check_condition_result;
3831 } else
3832 errsts = resp_unmap(SCpnt, devip);
3833 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003834 case MODE_SENSE:
3835 case MODE_SENSE_10:
3836 errsts = resp_mode_sense(SCpnt, target, devip);
3837 break;
3838 case MODE_SELECT:
3839 errsts = resp_mode_select(SCpnt, 1, devip);
3840 break;
3841 case MODE_SELECT_10:
3842 errsts = resp_mode_select(SCpnt, 0, devip);
3843 break;
3844 case LOG_SENSE:
3845 errsts = resp_log_sense(SCpnt, devip);
3846 break;
3847 case SYNCHRONIZE_CACHE:
3848 delay_override = 1;
3849 errsts = check_readiness(SCpnt, 0, devip);
3850 break;
3851 case WRITE_BUFFER:
3852 errsts = check_readiness(SCpnt, 1, devip);
3853 break;
3854 case XDWRITEREAD_10:
3855 if (!scsi_bidi_cmnd(SCpnt)) {
3856 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3857 INVALID_FIELD_IN_CDB, 0);
3858 errsts = check_condition_result;
3859 break;
3860 }
3861
3862 errsts = check_readiness(SCpnt, 0, devip);
3863 if (errsts)
3864 break;
3865 if (scsi_debug_fake_rw)
3866 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003867 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3868 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003869 if (errsts)
3870 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003871 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003872 if (errsts)
3873 break;
3874 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3875 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003876 case VARIABLE_LENGTH_CMD:
3877 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3878
3879 if ((cmd[10] & 0xe0) == 0)
3880 printk(KERN_ERR
3881 "Unprotected RD/WR to DIF device\n");
3882
3883 if (cmd[9] == READ_32) {
3884 BUG_ON(SCpnt->cmd_len < 32);
3885 goto read;
3886 }
3887
3888 if (cmd[9] == WRITE_32) {
3889 BUG_ON(SCpnt->cmd_len < 32);
3890 goto write;
3891 }
3892 }
3893
3894 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3895 INVALID_FIELD_IN_CDB, 0);
3896 errsts = check_condition_result;
3897 break;
3898
FUJITA Tomonori639db472008-03-20 11:09:19 +09003899 default:
3900 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3901 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3902 "supported\n", *cmd);
3903 errsts = check_readiness(SCpnt, 1, devip);
3904 if (errsts)
3905 break; /* Unit attention takes precedence */
3906 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3907 errsts = check_condition_result;
3908 break;
3909 }
3910 return schedule_resp(SCpnt, devip, done, errsts,
3911 (delay_override ? 0 : scsi_debug_delay));
3912}
3913
Jeff Garzikf2812332010-11-16 02:10:29 -05003914static DEF_SCSI_QCMD(scsi_debug_queuecommand)
3915
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003916static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04003917 .show_info = scsi_debug_show_info,
3918 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003919 .proc_name = sdebug_proc_name,
3920 .name = "SCSI DEBUG",
3921 .info = scsi_debug_info,
3922 .slave_alloc = scsi_debug_slave_alloc,
3923 .slave_configure = scsi_debug_slave_configure,
3924 .slave_destroy = scsi_debug_slave_destroy,
3925 .ioctl = scsi_debug_ioctl,
3926 .queuecommand = scsi_debug_queuecommand,
3927 .eh_abort_handler = scsi_debug_abort,
3928 .eh_bus_reset_handler = scsi_debug_bus_reset,
3929 .eh_device_reset_handler = scsi_debug_device_reset,
3930 .eh_host_reset_handler = scsi_debug_host_reset,
3931 .bios_param = scsi_debug_biosparam,
3932 .can_queue = SCSI_DEBUG_CANQUEUE,
3933 .this_id = 7,
3934 .sg_tablesize = 256,
3935 .cmd_per_lun = 16,
3936 .max_sectors = 0xffff,
3937 .use_clustering = DISABLE_CLUSTERING,
3938 .module = THIS_MODULE,
3939};
3940
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941static int sdebug_driver_probe(struct device * dev)
3942{
3943 int error = 0;
3944 struct sdebug_host_info *sdbg_host;
3945 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003946 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947
3948 sdbg_host = to_sdebug_host(dev);
3949
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003950 sdebug_driver_template.can_queue = scsi_debug_max_queue;
3951 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3952 if (NULL == hpnt) {
3953 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
3954 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957
3958 sdbg_host->shost = hpnt;
3959 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3960 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3961 hpnt->max_id = scsi_debug_num_tgts + 1;
3962 else
3963 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003964 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003966 host_prot = 0;
3967
3968 switch (scsi_debug_dif) {
3969
3970 case SD_DIF_TYPE1_PROTECTION:
3971 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3972 if (scsi_debug_dix)
3973 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3974 break;
3975
3976 case SD_DIF_TYPE2_PROTECTION:
3977 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3978 if (scsi_debug_dix)
3979 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3980 break;
3981
3982 case SD_DIF_TYPE3_PROTECTION:
3983 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3984 if (scsi_debug_dix)
3985 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3986 break;
3987
3988 default:
3989 if (scsi_debug_dix)
3990 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3991 break;
3992 }
3993
3994 scsi_host_set_prot(hpnt, host_prot);
3995
3996 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3997 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3998 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3999 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4000 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4001 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4002 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4003 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4004
4005 if (scsi_debug_guard == 1)
4006 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4007 else
4008 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4009
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 error = scsi_add_host(hpnt, &sdbg_host->dev);
4011 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004012 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 error = -ENODEV;
4014 scsi_host_put(hpnt);
4015 } else
4016 scsi_scan_host(hpnt);
4017
4018
4019 return error;
4020}
4021
4022static int sdebug_driver_remove(struct device * dev)
4023{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004025 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
4027 sdbg_host = to_sdebug_host(dev);
4028
4029 if (!sdbg_host) {
4030 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004031 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 return -ENODEV;
4033 }
4034
4035 scsi_remove_host(sdbg_host->shost);
4036
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004037 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4038 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 list_del(&sdbg_devinfo->dev_list);
4040 kfree(sdbg_devinfo);
4041 }
4042
4043 scsi_host_put(sdbg_host->shost);
4044 return 0;
4045}
4046
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004047static int pseudo_lld_bus_match(struct device *dev,
4048 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004050 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004052
4053static struct bus_type pseudo_lld_bus = {
4054 .name = "pseudo",
4055 .match = pseudo_lld_bus_match,
4056 .probe = sdebug_driver_probe,
4057 .remove = sdebug_driver_remove,
4058};