blob: e4ba924c303dabb4384868c54b9b3b3d61f2cf51 [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
112#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
113#define DEF_SECTOR_SIZE 512
114#define DEF_UNMAP_ALIGNMENT 0
115#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400116#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
117#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500118#define DEF_VIRTUAL_GB 0
119#define DEF_VPD_USE_HOSTNO 1
120#define DEF_WRITESAME_LENGTH 0xFFFF
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122/* bit mask values for scsi_debug_opts */
123#define SCSI_DEBUG_OPT_NOISE 1
124#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
125#define SCSI_DEBUG_OPT_TIMEOUT 4
126#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500127#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500128#define SCSI_DEBUG_OPT_DIF_ERR 32
129#define SCSI_DEBUG_OPT_DIX_ERR 64
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -0500130#define SCSI_DEBUG_OPT_MAC_TIMEOUT 128
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131/* When "every_nth" > 0 then modulo "every_nth" commands:
132 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
133 * - a RECOVERED_ERROR is simulated on successful read and write
134 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500135 * - a TRANSPORT_ERROR is simulated on successful read and write
136 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 *
138 * When "every_nth" < 0 then after "- every_nth" commands:
139 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
140 * - a RECOVERED_ERROR is simulated on successful read and write
141 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500142 * - a TRANSPORT_ERROR is simulated on successful read and write
143 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 * This will continue until some other action occurs (e.g. the user
145 * writing a new value (other than -1 or 1) to every_nth via sysfs).
146 */
147
148/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
149 * sector on read commands: */
150#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500151#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
153/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
154 * or "peripheral device" addressing (value 0) */
155#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400156#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400158/* Can queue up to this number of commands. Typically commands that
159 * that have a non-zero delay are queued. */
160#define SCSI_DEBUG_CANQUEUE 255
161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static int scsi_debug_add_host = DEF_NUM_HOST;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500163static int scsi_debug_ato = DEF_ATO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164static int scsi_debug_delay = DEF_DELAY;
165static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500166static int scsi_debug_dif = DEF_DIF;
167static int scsi_debug_dix = DEF_DIX;
168static int scsi_debug_dsense = DEF_D_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169static int scsi_debug_every_nth = DEF_EVERY_NTH;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500170static int scsi_debug_fake_rw = DEF_FAKE_RW;
171static int scsi_debug_guard = DEF_GUARD;
172static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static int scsi_debug_max_luns = DEF_MAX_LUNS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400174static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400175static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500176static int scsi_debug_no_uld = 0;
177static int scsi_debug_num_parts = DEF_NUM_PARTS;
178static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400179static int scsi_debug_opt_blks = DEF_OPT_BLKS;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500180static int scsi_debug_opts = DEF_OPTS;
181static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
182static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
183static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
184static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
185static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
186static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
187static unsigned int scsi_debug_lbpu = DEF_LBPU;
188static unsigned int scsi_debug_lbpws = DEF_LBPWS;
189static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10;
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600190static unsigned int scsi_debug_lbprz = DEF_LBPRZ;
Martin K. Petersen60147592010-08-19 11:49:00 -0400191static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500192static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
193static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
194static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
195static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197static int scsi_debug_cmnd_count = 0;
198
199#define DEV_READONLY(TGT) (0)
200#define DEV_REMOVEABLE(TGT) (0)
201
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400202static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203static sector_t sdebug_capacity; /* in sectors */
204
205/* old BIOS stuff, kernel may get rid of them but some mode sense pages
206 may still need them */
207static int sdebug_heads; /* heads per disk */
208static int sdebug_cylinders_per; /* cylinders per surface */
209static int sdebug_sectors_per; /* sectors per cylinder */
210
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211#define SDEBUG_MAX_PARTS 4
212
213#define SDEBUG_SENSE_LEN 32
214
Martin K. Petersen395cef02009-09-18 17:33:03 -0400215#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900216
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500217static unsigned int scsi_debug_lbp(void)
218{
219 return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10;
220}
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222struct sdebug_dev_info {
223 struct list_head dev_list;
224 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
225 unsigned int channel;
226 unsigned int target;
227 unsigned int lun;
228 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400229 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400231 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 char used;
233};
234
235struct sdebug_host_info {
236 struct list_head host_list;
237 struct Scsi_Host *shost;
238 struct device dev;
239 struct list_head dev_info_list;
240};
241
242#define to_sdebug_host(d) \
243 container_of(d, struct sdebug_host_info, dev)
244
245static LIST_HEAD(sdebug_host_list);
246static DEFINE_SPINLOCK(sdebug_host_list_lock);
247
248typedef void (* done_funct_t) (struct scsi_cmnd *);
249
250struct sdebug_queued_cmd {
251 int in_use;
252 struct timer_list cmnd_timer;
253 done_funct_t done_funct;
254 struct scsi_cmnd * a_cmnd;
255 int scsi_result;
256};
257static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
258
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259static unsigned char * fake_storep; /* ramdisk storage */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500260static unsigned char *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400261static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Martin K. Petersen44d92692009-10-15 14:45:27 -0400263static unsigned long map_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264static int num_aborts = 0;
265static int num_dev_resets = 0;
266static int num_bus_resets = 0;
267static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500268static int dix_writes;
269static int dix_reads;
270static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
272static DEFINE_SPINLOCK(queued_arr_lock);
273static DEFINE_RWLOCK(atomic_rw);
274
275static char sdebug_proc_name[] = "scsi_debug";
276
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277static struct bus_type pseudo_lld_bus;
278
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500279static inline sector_t dif_offset(sector_t sector)
280{
281 return sector << 3;
282}
283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284static struct device_driver sdebug_driverfs_driver = {
285 .name = sdebug_proc_name,
286 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287};
288
289static const int check_condition_result =
290 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
291
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500292static const int illegal_condition_result =
293 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
294
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400295static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
296 0, 0, 0x2, 0x4b};
297static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
298 0, 0, 0x0, 0x0};
299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300static int sdebug_add_adapter(void);
301static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900303static void sdebug_max_tgts_luns(void)
304{
305 struct sdebug_host_info *sdbg_host;
306 struct Scsi_Host *hpnt;
307
308 spin_lock(&sdebug_host_list_lock);
309 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
310 hpnt = sdbg_host->shost;
311 if ((hpnt->this_id >= 0) &&
312 (scsi_debug_num_tgts > hpnt->this_id))
313 hpnt->max_id = scsi_debug_num_tgts + 1;
314 else
315 hpnt->max_id = scsi_debug_num_tgts;
316 /* scsi_debug_max_luns; */
317 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
318 }
319 spin_unlock(&sdebug_host_list_lock);
320}
321
322static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
323 int asc, int asq)
324{
325 unsigned char *sbuff;
326
327 sbuff = devip->sense_buff;
328 memset(sbuff, 0, SDEBUG_SENSE_LEN);
329
330 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
331
332 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
333 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
334 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
335}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900337static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400338 unsigned long long *lba, unsigned int *num,
339 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900340{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400341 *ei_lba = 0;
342
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900343 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400344 case VARIABLE_LENGTH_CMD:
345 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
346 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
347 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
348 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
349
350 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
351 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
352
353 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
354 (u32)cmd[28] << 24;
355 break;
356
Martin K. Petersen44d92692009-10-15 14:45:27 -0400357 case WRITE_SAME_16:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900358 case WRITE_16:
359 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900360 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
361 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
362 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
363 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
364
365 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
366 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900367 break;
368 case WRITE_12:
369 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900370 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
371 (u32)cmd[2] << 24;
372
373 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
374 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900375 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400376 case WRITE_SAME:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900377 case WRITE_10:
378 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900379 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900380 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
381 (u32)cmd[2] << 24;
382
383 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900384 break;
385 case WRITE_6:
386 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900387 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
388 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900389 *num = (0 == cmd[4]) ? 256 : cmd[4];
390 break;
391 default:
392 break;
393 }
394}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
397{
398 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
399 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
400 }
401 return -EINVAL;
402 /* return -ENOTTY; // correct return but upsets fdisk */
403}
404
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400405static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
406 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407{
408 if (devip->reset) {
409 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
410 printk(KERN_INFO "scsi_debug: Reporting Unit "
411 "attention: power on reset\n");
412 devip->reset = 0;
413 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
414 return check_condition_result;
415 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400416 if ((0 == reset_only) && devip->stopped) {
417 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
418 printk(KERN_INFO "scsi_debug: Reporting Not "
419 "ready: initializing command required\n");
420 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
421 0x2);
422 return check_condition_result;
423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 return 0;
425}
426
427/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900428static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 int arr_len)
430{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900431 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900432 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900434 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900436 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900438
439 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
440 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900441 if (sdb->resid)
442 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400443 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900444 sdb->resid = scsi_bufflen(scp) - act_len;
445
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 return 0;
447}
448
449/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900450static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
451 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900453 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900455 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900457
458 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
461
462static const char * inq_vendor_id = "Linux ";
463static const char * inq_product_id = "scsi_debug ";
464static const char * inq_product_rev = "0004";
465
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200466static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
467 int target_dev_id, int dev_id_num,
468 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400469 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400471 int num, port_a;
472 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400474 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 /* T10 vendor identifier field format (faked) */
476 arr[0] = 0x2; /* ASCII */
477 arr[1] = 0x1;
478 arr[2] = 0x0;
479 memcpy(&arr[4], inq_vendor_id, 8);
480 memcpy(&arr[12], inq_product_id, 16);
481 memcpy(&arr[28], dev_id_str, dev_id_str_len);
482 num = 8 + 16 + dev_id_str_len;
483 arr[3] = num;
484 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400485 if (dev_id_num >= 0) {
486 /* NAA-5, Logical unit identifier (binary) */
487 arr[num++] = 0x1; /* binary (not necessarily sas) */
488 arr[num++] = 0x3; /* PIV=0, lu, naa */
489 arr[num++] = 0x0;
490 arr[num++] = 0x8;
491 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
492 arr[num++] = 0x33;
493 arr[num++] = 0x33;
494 arr[num++] = 0x30;
495 arr[num++] = (dev_id_num >> 24);
496 arr[num++] = (dev_id_num >> 16) & 0xff;
497 arr[num++] = (dev_id_num >> 8) & 0xff;
498 arr[num++] = dev_id_num & 0xff;
499 /* Target relative port number */
500 arr[num++] = 0x61; /* proto=sas, binary */
501 arr[num++] = 0x94; /* PIV=1, target port, rel port */
502 arr[num++] = 0x0; /* reserved */
503 arr[num++] = 0x4; /* length */
504 arr[num++] = 0x0; /* reserved */
505 arr[num++] = 0x0; /* reserved */
506 arr[num++] = 0x0;
507 arr[num++] = 0x1; /* relative port A */
508 }
509 /* NAA-5, Target port identifier */
510 arr[num++] = 0x61; /* proto=sas, binary */
511 arr[num++] = 0x93; /* piv=1, target port, naa */
512 arr[num++] = 0x0;
513 arr[num++] = 0x8;
514 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
515 arr[num++] = 0x22;
516 arr[num++] = 0x22;
517 arr[num++] = 0x20;
518 arr[num++] = (port_a >> 24);
519 arr[num++] = (port_a >> 16) & 0xff;
520 arr[num++] = (port_a >> 8) & 0xff;
521 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200522 /* NAA-5, Target port group identifier */
523 arr[num++] = 0x61; /* proto=sas, binary */
524 arr[num++] = 0x95; /* piv=1, target port group id */
525 arr[num++] = 0x0;
526 arr[num++] = 0x4;
527 arr[num++] = 0;
528 arr[num++] = 0;
529 arr[num++] = (port_group_id >> 8) & 0xff;
530 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400531 /* NAA-5, Target device identifier */
532 arr[num++] = 0x61; /* proto=sas, binary */
533 arr[num++] = 0xa3; /* piv=1, target device, naa */
534 arr[num++] = 0x0;
535 arr[num++] = 0x8;
536 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
537 arr[num++] = 0x22;
538 arr[num++] = 0x22;
539 arr[num++] = 0x20;
540 arr[num++] = (target_dev_id >> 24);
541 arr[num++] = (target_dev_id >> 16) & 0xff;
542 arr[num++] = (target_dev_id >> 8) & 0xff;
543 arr[num++] = target_dev_id & 0xff;
544 /* SCSI name string: Target device identifier */
545 arr[num++] = 0x63; /* proto=sas, UTF-8 */
546 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
547 arr[num++] = 0x0;
548 arr[num++] = 24;
549 memcpy(arr + num, "naa.52222220", 12);
550 num += 12;
551 snprintf(b, sizeof(b), "%08X", target_dev_id);
552 memcpy(arr + num, b, 8);
553 num += 8;
554 memset(arr + num, 0, 4);
555 num += 4;
556 return num;
557}
558
559
560static unsigned char vpd84_data[] = {
561/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
562 0x22,0x22,0x22,0x0,0xbb,0x1,
563 0x22,0x22,0x22,0x0,0xbb,0x2,
564};
565
566static int inquiry_evpd_84(unsigned char * arr)
567{
568 memcpy(arr, vpd84_data, sizeof(vpd84_data));
569 return sizeof(vpd84_data);
570}
571
572static int inquiry_evpd_85(unsigned char * arr)
573{
574 int num = 0;
575 const char * na1 = "https://www.kernel.org/config";
576 const char * na2 = "http://www.kernel.org/log";
577 int plen, olen;
578
579 arr[num++] = 0x1; /* lu, storage config */
580 arr[num++] = 0x0; /* reserved */
581 arr[num++] = 0x0;
582 olen = strlen(na1);
583 plen = olen + 1;
584 if (plen % 4)
585 plen = ((plen / 4) + 1) * 4;
586 arr[num++] = plen; /* length, null termianted, padded */
587 memcpy(arr + num, na1, olen);
588 memset(arr + num + olen, 0, plen - olen);
589 num += plen;
590
591 arr[num++] = 0x4; /* lu, logging */
592 arr[num++] = 0x0; /* reserved */
593 arr[num++] = 0x0;
594 olen = strlen(na2);
595 plen = olen + 1;
596 if (plen % 4)
597 plen = ((plen / 4) + 1) * 4;
598 arr[num++] = plen; /* length, null terminated, padded */
599 memcpy(arr + num, na2, olen);
600 memset(arr + num + olen, 0, plen - olen);
601 num += plen;
602
603 return num;
604}
605
606/* SCSI ports VPD page */
607static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
608{
609 int num = 0;
610 int port_a, port_b;
611
612 port_a = target_dev_id + 1;
613 port_b = port_a + 1;
614 arr[num++] = 0x0; /* reserved */
615 arr[num++] = 0x0; /* reserved */
616 arr[num++] = 0x0;
617 arr[num++] = 0x1; /* relative port 1 (primary) */
618 memset(arr + num, 0, 6);
619 num += 6;
620 arr[num++] = 0x0;
621 arr[num++] = 12; /* length tp descriptor */
622 /* naa-5 target port identifier (A) */
623 arr[num++] = 0x61; /* proto=sas, binary */
624 arr[num++] = 0x93; /* PIV=1, target port, NAA */
625 arr[num++] = 0x0; /* reserved */
626 arr[num++] = 0x8; /* length */
627 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
628 arr[num++] = 0x22;
629 arr[num++] = 0x22;
630 arr[num++] = 0x20;
631 arr[num++] = (port_a >> 24);
632 arr[num++] = (port_a >> 16) & 0xff;
633 arr[num++] = (port_a >> 8) & 0xff;
634 arr[num++] = port_a & 0xff;
635
636 arr[num++] = 0x0; /* reserved */
637 arr[num++] = 0x0; /* reserved */
638 arr[num++] = 0x0;
639 arr[num++] = 0x2; /* relative port 2 (secondary) */
640 memset(arr + num, 0, 6);
641 num += 6;
642 arr[num++] = 0x0;
643 arr[num++] = 12; /* length tp descriptor */
644 /* naa-5 target port identifier (B) */
645 arr[num++] = 0x61; /* proto=sas, binary */
646 arr[num++] = 0x93; /* PIV=1, target port, NAA */
647 arr[num++] = 0x0; /* reserved */
648 arr[num++] = 0x8; /* length */
649 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
650 arr[num++] = 0x22;
651 arr[num++] = 0x22;
652 arr[num++] = 0x20;
653 arr[num++] = (port_b >> 24);
654 arr[num++] = (port_b >> 16) & 0xff;
655 arr[num++] = (port_b >> 8) & 0xff;
656 arr[num++] = port_b & 0xff;
657
658 return num;
659}
660
661
662static unsigned char vpd89_data[] = {
663/* from 4th byte */ 0,0,0,0,
664'l','i','n','u','x',' ',' ',' ',
665'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
666'1','2','3','4',
6670x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6680xec,0,0,0,
6690x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6700,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6710x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6720x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6730x53,0x41,
6740x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6750x20,0x20,
6760x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6770x10,0x80,
6780,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6790x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6800x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6810,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6820x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6830x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6840,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6880x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6890,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6900xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6910,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
7000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7020,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7030,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
704};
705
706static int inquiry_evpd_89(unsigned char * arr)
707{
708 memcpy(arr, vpd89_data, sizeof(vpd89_data));
709 return sizeof(vpd89_data);
710}
711
712
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400713/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400714static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400715 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
716 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
717 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
718 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400719};
720
721static int inquiry_evpd_b0(unsigned char * arr)
722{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400723 unsigned int gran;
724
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400725 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400726
727 /* Optimal transfer length granularity */
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400728 gran = 1 << scsi_debug_physblk_exp;
729 arr[2] = (gran >> 8) & 0xff;
730 arr[3] = gran & 0xff;
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400731
732 /* Maximum Transfer Length */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400733 if (sdebug_store_sectors > 0x400) {
734 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
735 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
736 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
737 arr[7] = sdebug_store_sectors & 0xff;
738 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400739
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400740 /* Optimal Transfer Length */
741 put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
742
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500743 if (scsi_debug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400744 /* Maximum Unmap LBA Count */
Martin K. Petersen60147592010-08-19 11:49:00 -0400745 put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400746
747 /* Maximum Unmap Block Descriptor Count */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400748 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
749 }
750
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400751 /* Unmap Granularity Alignment */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400752 if (scsi_debug_unmap_alignment) {
753 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
754 arr[28] |= 0x80; /* UGAVALID */
755 }
756
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400757 /* Optimal Unmap Granularity */
Martin K. Petersen60147592010-08-19 11:49:00 -0400758 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
759
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500760 /* Maximum WRITE SAME Length */
761 put_unaligned_be64(scsi_debug_write_same_length, &arr[32]);
762
763 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400764
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400765 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766}
767
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400768/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600769static int inquiry_evpd_b1(unsigned char *arr)
770{
771 memset(arr, 0, 0x3c);
772 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400773 arr[1] = 1; /* non rotating medium (e.g. solid state) */
774 arr[2] = 0;
775 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600776
777 return 0x3c;
778}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600780/* Logical block provisioning VPD page (SBC-3) */
Martin K. Petersen60147592010-08-19 11:49:00 -0400781static int inquiry_evpd_b2(unsigned char *arr)
782{
783 memset(arr, 0, 0x8);
784 arr[0] = 0; /* threshold exponent */
785
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500786 if (scsi_debug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -0400787 arr[1] = 1 << 7;
788
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500789 if (scsi_debug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -0400790 arr[1] |= 1 << 6;
791
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500792 if (scsi_debug_lbpws10)
793 arr[1] |= 1 << 5;
794
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600795 if (scsi_debug_lbprz)
796 arr[1] |= 1 << 2;
797
Martin K. Petersen60147592010-08-19 11:49:00 -0400798 return 0x8;
799}
800
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400802#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
804static int resp_inquiry(struct scsi_cmnd * scp, int target,
805 struct sdebug_dev_info * devip)
806{
807 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200808 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200810 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500813 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
814 if (! arr)
815 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400816 if (devip->wlun)
817 pq_pdt = 0x1e; /* present, wlun */
818 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
819 pq_pdt = 0x7f; /* not present, no device type */
820 else
821 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 arr[0] = pq_pdt;
823 if (0x2 & cmd[1]) { /* CMDDT bit set */
824 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
825 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200826 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 return check_condition_result;
828 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200829 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400830 char lu_id_str[6];
831 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200833 port_group_id = (((host_no + 1) & 0x7f) << 8) +
834 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400835 if (0 == scsi_debug_vpd_use_hostno)
836 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400837 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
838 (devip->target * 1000) + devip->lun);
839 target_dev_id = ((host_no + 1) * 2000) +
840 (devip->target * 1000) - 3;
841 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400843 arr[1] = cmd[2]; /*sanity */
844 n = 4;
845 arr[n++] = 0x0; /* this page */
846 arr[n++] = 0x80; /* unit serial number */
847 arr[n++] = 0x83; /* device identification */
848 arr[n++] = 0x84; /* software interface ident. */
849 arr[n++] = 0x85; /* management network addresses */
850 arr[n++] = 0x86; /* extended inquiry */
851 arr[n++] = 0x87; /* mode page policy */
852 arr[n++] = 0x88; /* SCSI ports */
853 arr[n++] = 0x89; /* ATA information */
854 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600855 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500856 if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */
857 arr[n++] = 0xb2;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400858 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400860 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400862 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400864 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200865 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
866 target_dev_id, lu_id_num,
867 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400868 } else if (0x84 == cmd[2]) { /* Software interface ident. */
869 arr[1] = cmd[2]; /*sanity */
870 arr[3] = inquiry_evpd_84(&arr[4]);
871 } else if (0x85 == cmd[2]) { /* Management network addresses */
872 arr[1] = cmd[2]; /*sanity */
873 arr[3] = inquiry_evpd_85(&arr[4]);
874 } else if (0x86 == cmd[2]) { /* extended inquiry */
875 arr[1] = cmd[2]; /*sanity */
876 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500877 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
878 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
879 else if (scsi_debug_dif)
880 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
881 else
882 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400883 arr[5] = 0x7; /* head of q, ordered + simple q's */
884 } else if (0x87 == cmd[2]) { /* mode page policy */
885 arr[1] = cmd[2]; /*sanity */
886 arr[3] = 0x8; /* number of following entries */
887 arr[4] = 0x2; /* disconnect-reconnect mp */
888 arr[6] = 0x80; /* mlus, shared */
889 arr[8] = 0x18; /* protocol specific lu */
890 arr[10] = 0x82; /* mlus, per initiator port */
891 } else if (0x88 == cmd[2]) { /* SCSI Ports */
892 arr[1] = cmd[2]; /*sanity */
893 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
894 } else if (0x89 == cmd[2]) { /* ATA information */
895 arr[1] = cmd[2]; /*sanity */
896 n = inquiry_evpd_89(&arr[4]);
897 arr[2] = (n >> 8);
898 arr[3] = (n & 0xff);
899 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
900 arr[1] = cmd[2]; /*sanity */
901 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600902 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
903 arr[1] = cmd[2]; /*sanity */
904 arr[3] = inquiry_evpd_b1(&arr[4]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500905 } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */
Martin K. Petersen60147592010-08-19 11:49:00 -0400906 arr[1] = cmd[2]; /*sanity */
907 arr[3] = inquiry_evpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 } else {
909 /* Illegal request, invalid field in cdb */
910 mk_sense_buffer(devip, ILLEGAL_REQUEST,
911 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200912 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 return check_condition_result;
914 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400915 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200916 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400917 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200918 kfree(arr);
919 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 }
921 /* drops through here for a standard inquiry */
922 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
923 arr[2] = scsi_debug_scsi_level;
924 arr[3] = 2; /* response_data_format==2 */
925 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500926 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200927 if (0 == scsi_debug_vpd_use_hostno)
928 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400929 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400931 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 memcpy(&arr[8], inq_vendor_id, 8);
933 memcpy(&arr[16], inq_product_id, 16);
934 memcpy(&arr[32], inq_product_rev, 4);
935 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400936 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
937 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
938 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400940 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400942 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400944 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200945 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200947 kfree(arr);
948 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949}
950
951static int resp_requests(struct scsi_cmnd * scp,
952 struct sdebug_dev_info * devip)
953{
954 unsigned char * sbuff;
955 unsigned char *cmd = (unsigned char *)scp->cmnd;
956 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400957 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 int len = 18;
959
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400960 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400962 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
963 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400965 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
966 if (want_dsense) {
967 arr[0] = 0x72;
968 arr[1] = 0x0; /* NO_SENSE in sense_key */
969 arr[2] = THRESHOLD_EXCEEDED;
970 arr[3] = 0xff; /* TEST set and MRIE==6 */
971 } else {
972 arr[0] = 0x70;
973 arr[2] = 0x0; /* NO_SENSE in sense_key */
974 arr[7] = 0xa; /* 18 byte sense buffer */
975 arr[12] = THRESHOLD_EXCEEDED;
976 arr[13] = 0xff; /* TEST set and MRIE==6 */
977 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400978 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400980 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
981 /* DESC bit set and sense_buff in fixed format */
982 memset(arr, 0, sizeof(arr));
983 arr[0] = 0x72;
984 arr[1] = sbuff[2]; /* sense key */
985 arr[2] = sbuff[12]; /* asc */
986 arr[3] = sbuff[13]; /* ascq */
987 len = 8;
988 }
989 }
990 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return fill_from_dev_buffer(scp, arr, len);
992}
993
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400994static int resp_start_stop(struct scsi_cmnd * scp,
995 struct sdebug_dev_info * devip)
996{
997 unsigned char *cmd = (unsigned char *)scp->cmnd;
998 int power_cond, errsts, start;
999
1000 if ((errsts = check_readiness(scp, 1, devip)))
1001 return errsts;
1002 power_cond = (cmd[4] & 0xf0) >> 4;
1003 if (power_cond) {
1004 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1005 0);
1006 return check_condition_result;
1007 }
1008 start = cmd[4] & 1;
1009 if (start == devip->stopped)
1010 devip->stopped = !start;
1011 return 0;
1012}
1013
FUJITA Tomonori28898872008-03-30 00:59:55 +09001014static sector_t get_sdebug_capacity(void)
1015{
1016 if (scsi_debug_virtual_gb > 0)
Douglas Gilbert5447ed62010-04-25 12:30:23 +02001017 return (sector_t)scsi_debug_virtual_gb *
1018 (1073741824 / scsi_debug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001019 else
1020 return sdebug_store_sectors;
1021}
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023#define SDEBUG_READCAP_ARR_SZ 8
1024static int resp_readcap(struct scsi_cmnd * scp,
1025 struct sdebug_dev_info * devip)
1026{
1027 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001028 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 int errsts;
1030
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001031 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001033 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001034 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001036 if (sdebug_capacity < 0xffffffff) {
1037 capac = (unsigned int)sdebug_capacity - 1;
1038 arr[0] = (capac >> 24);
1039 arr[1] = (capac >> 16) & 0xff;
1040 arr[2] = (capac >> 8) & 0xff;
1041 arr[3] = capac & 0xff;
1042 } else {
1043 arr[0] = 0xff;
1044 arr[1] = 0xff;
1045 arr[2] = 0xff;
1046 arr[3] = 0xff;
1047 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001048 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1049 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1051}
1052
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001053#define SDEBUG_READCAP16_ARR_SZ 32
1054static int resp_readcap16(struct scsi_cmnd * scp,
1055 struct sdebug_dev_info * devip)
1056{
1057 unsigned char *cmd = (unsigned char *)scp->cmnd;
1058 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1059 unsigned long long capac;
1060 int errsts, k, alloc_len;
1061
1062 if ((errsts = check_readiness(scp, 1, devip)))
1063 return errsts;
1064 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1065 + cmd[13]);
1066 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001067 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001068 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1069 capac = sdebug_capacity - 1;
1070 for (k = 0; k < 8; ++k, capac >>= 8)
1071 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001072 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1073 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1074 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1075 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001076 arr[13] = scsi_debug_physblk_exp & 0xf;
1077 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001078
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001079 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001080 arr[14] |= 0x80; /* LBPME */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001081 if (scsi_debug_lbprz)
1082 arr[14] |= 0x40; /* LBPRZ */
1083 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001084
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001085 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001086
1087 if (scsi_debug_dif) {
1088 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1089 arr[12] |= 1; /* PROT_EN */
1090 }
1091
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001092 return fill_from_dev_buffer(scp, arr,
1093 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1094}
1095
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001096#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1097
1098static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1099 struct sdebug_dev_info * devip)
1100{
1101 unsigned char *cmd = (unsigned char *)scp->cmnd;
1102 unsigned char * arr;
1103 int host_no = devip->sdbg_host->shost->host_no;
1104 int n, ret, alen, rlen;
1105 int port_group_a, port_group_b, port_a, port_b;
1106
1107 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1108 + cmd[9]);
1109
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001110 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1111 if (! arr)
1112 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001113 /*
1114 * EVPD page 0x88 states we have two ports, one
1115 * real and a fake port with no device connected.
1116 * So we create two port groups with one port each
1117 * and set the group with port B to unavailable.
1118 */
1119 port_a = 0x1; /* relative port A */
1120 port_b = 0x2; /* relative port B */
1121 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1122 (devip->channel & 0x7f);
1123 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1124 (devip->channel & 0x7f) + 0x80;
1125
1126 /*
1127 * The asymmetric access state is cycled according to the host_id.
1128 */
1129 n = 4;
1130 if (0 == scsi_debug_vpd_use_hostno) {
1131 arr[n++] = host_no % 3; /* Asymm access state */
1132 arr[n++] = 0x0F; /* claim: all states are supported */
1133 } else {
1134 arr[n++] = 0x0; /* Active/Optimized path */
1135 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1136 }
1137 arr[n++] = (port_group_a >> 8) & 0xff;
1138 arr[n++] = port_group_a & 0xff;
1139 arr[n++] = 0; /* Reserved */
1140 arr[n++] = 0; /* Status code */
1141 arr[n++] = 0; /* Vendor unique */
1142 arr[n++] = 0x1; /* One port per group */
1143 arr[n++] = 0; /* Reserved */
1144 arr[n++] = 0; /* Reserved */
1145 arr[n++] = (port_a >> 8) & 0xff;
1146 arr[n++] = port_a & 0xff;
1147 arr[n++] = 3; /* Port unavailable */
1148 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1149 arr[n++] = (port_group_b >> 8) & 0xff;
1150 arr[n++] = port_group_b & 0xff;
1151 arr[n++] = 0; /* Reserved */
1152 arr[n++] = 0; /* Status code */
1153 arr[n++] = 0; /* Vendor unique */
1154 arr[n++] = 0x1; /* One port per group */
1155 arr[n++] = 0; /* Reserved */
1156 arr[n++] = 0; /* Reserved */
1157 arr[n++] = (port_b >> 8) & 0xff;
1158 arr[n++] = port_b & 0xff;
1159
1160 rlen = n - 4;
1161 arr[0] = (rlen >> 24) & 0xff;
1162 arr[1] = (rlen >> 16) & 0xff;
1163 arr[2] = (rlen >> 8) & 0xff;
1164 arr[3] = rlen & 0xff;
1165
1166 /*
1167 * Return the smallest value of either
1168 * - The allocated length
1169 * - The constructed command length
1170 * - The maximum array size
1171 */
1172 rlen = min(alen,n);
1173 ret = fill_from_dev_buffer(scp, arr,
1174 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1175 kfree(arr);
1176 return ret;
1177}
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179/* <<Following mode page info copied from ST318451LW>> */
1180
1181static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1182{ /* Read-Write Error Recovery page for mode_sense */
1183 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1184 5, 0, 0xff, 0xff};
1185
1186 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1187 if (1 == pcontrol)
1188 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1189 return sizeof(err_recov_pg);
1190}
1191
1192static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1193{ /* Disconnect-Reconnect page for mode_sense */
1194 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1195 0, 0, 0, 0, 0, 0, 0, 0};
1196
1197 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1198 if (1 == pcontrol)
1199 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1200 return sizeof(disconnect_pg);
1201}
1202
1203static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1204{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001205 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1206 0, 0, 0, 0, 0, 0, 0, 0,
1207 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Martin K. Petersen597136a2008-06-05 00:12:59 -04001209 memcpy(p, format_pg, sizeof(format_pg));
1210 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1211 p[11] = sdebug_sectors_per & 0xff;
1212 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1213 p[13] = scsi_debug_sector_size & 0xff;
1214 if (DEV_REMOVEABLE(target))
1215 p[20] |= 0x20; /* should agree with INQUIRY */
1216 if (1 == pcontrol)
1217 memset(p + 2, 0, sizeof(format_pg) - 2);
1218 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219}
1220
1221static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1222{ /* Caching page for mode_sense */
1223 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1224 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1225
1226 memcpy(p, caching_pg, sizeof(caching_pg));
1227 if (1 == pcontrol)
1228 memset(p + 2, 0, sizeof(caching_pg) - 2);
1229 return sizeof(caching_pg);
1230}
1231
1232static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1233{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001234 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1235 0, 0, 0, 0};
1236 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 0, 0, 0x2, 0x4b};
1238
1239 if (scsi_debug_dsense)
1240 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001241 else
1242 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001243
1244 if (scsi_debug_ato)
1245 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1246
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1248 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001249 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1250 else if (2 == pcontrol)
1251 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 return sizeof(ctrl_m_pg);
1253}
1254
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1257{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001258 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1259 0, 0, 0x0, 0x0};
1260 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1261 0, 0, 0x0, 0x0};
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1264 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001265 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1266 else if (2 == pcontrol)
1267 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return sizeof(iec_m_pg);
1269}
1270
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001271static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1272{ /* SAS SSP mode page - short format for mode_sense */
1273 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1274 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1275
1276 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1277 if (1 == pcontrol)
1278 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1279 return sizeof(sas_sf_m_pg);
1280}
1281
1282
1283static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1284 int target_dev_id)
1285{ /* SAS phy control and discover mode page for mode_sense */
1286 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1287 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1288 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1289 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1290 0x2, 0, 0, 0, 0, 0, 0, 0,
1291 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1292 0, 0, 0, 0, 0, 0, 0, 0,
1293 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1294 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1295 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1296 0x3, 0, 0, 0, 0, 0, 0, 0,
1297 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1298 0, 0, 0, 0, 0, 0, 0, 0,
1299 };
1300 int port_a, port_b;
1301
1302 port_a = target_dev_id + 1;
1303 port_b = port_a + 1;
1304 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1305 p[20] = (port_a >> 24);
1306 p[21] = (port_a >> 16) & 0xff;
1307 p[22] = (port_a >> 8) & 0xff;
1308 p[23] = port_a & 0xff;
1309 p[48 + 20] = (port_b >> 24);
1310 p[48 + 21] = (port_b >> 16) & 0xff;
1311 p[48 + 22] = (port_b >> 8) & 0xff;
1312 p[48 + 23] = port_b & 0xff;
1313 if (1 == pcontrol)
1314 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1315 return sizeof(sas_pcd_m_pg);
1316}
1317
1318static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1319{ /* SAS SSP shared protocol specific port mode subpage */
1320 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1321 0, 0, 0, 0, 0, 0, 0, 0,
1322 };
1323
1324 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1325 if (1 == pcontrol)
1326 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1327 return sizeof(sas_sha_m_pg);
1328}
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330#define SDEBUG_MAX_MSENSE_SZ 256
1331
1332static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1333 struct sdebug_dev_info * devip)
1334{
Douglas Gilbert23183912006-09-16 20:30:47 -04001335 unsigned char dbd, llbaa;
1336 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001338 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 unsigned char * ap;
1340 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1341 unsigned char *cmd = (unsigned char *)scp->cmnd;
1342
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001343 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001345 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 pcontrol = (cmd[2] & 0xc0) >> 6;
1347 pcode = cmd[2] & 0x3f;
1348 subpcode = cmd[3];
1349 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001350 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1351 if ((0 == scsi_debug_ptype) && (0 == dbd))
1352 bd_len = llbaa ? 16 : 8;
1353 else
1354 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1356 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1357 if (0x3 == pcontrol) { /* Saving values not supported */
1358 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1359 0);
1360 return check_condition_result;
1361 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001362 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1363 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001364 /* set DPOFUA bit for disks */
1365 if (0 == scsi_debug_ptype)
1366 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1367 else
1368 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 if (msense_6) {
1370 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001371 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 offset = 4;
1373 } else {
1374 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001375 if (16 == bd_len)
1376 arr[4] = 0x1; /* set LONGLBA bit */
1377 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 offset = 8;
1379 }
1380 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001381 if ((bd_len > 0) && (!sdebug_capacity))
1382 sdebug_capacity = get_sdebug_capacity();
1383
Douglas Gilbert23183912006-09-16 20:30:47 -04001384 if (8 == bd_len) {
1385 if (sdebug_capacity > 0xfffffffe) {
1386 ap[0] = 0xff;
1387 ap[1] = 0xff;
1388 ap[2] = 0xff;
1389 ap[3] = 0xff;
1390 } else {
1391 ap[0] = (sdebug_capacity >> 24) & 0xff;
1392 ap[1] = (sdebug_capacity >> 16) & 0xff;
1393 ap[2] = (sdebug_capacity >> 8) & 0xff;
1394 ap[3] = sdebug_capacity & 0xff;
1395 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001396 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1397 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001398 offset += bd_len;
1399 ap = arr + offset;
1400 } else if (16 == bd_len) {
1401 unsigned long long capac = sdebug_capacity;
1402
1403 for (k = 0; k < 8; ++k, capac >>= 8)
1404 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001405 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1406 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1407 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1408 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001409 offset += bd_len;
1410 ap = arr + offset;
1411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001413 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1414 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1416 0);
1417 return check_condition_result;
1418 }
1419 switch (pcode) {
1420 case 0x1: /* Read-Write error recovery page, direct access */
1421 len = resp_err_recov_pg(ap, pcontrol, target);
1422 offset += len;
1423 break;
1424 case 0x2: /* Disconnect-Reconnect page, all devices */
1425 len = resp_disconnect_pg(ap, pcontrol, target);
1426 offset += len;
1427 break;
1428 case 0x3: /* Format device page, direct access */
1429 len = resp_format_pg(ap, pcontrol, target);
1430 offset += len;
1431 break;
1432 case 0x8: /* Caching page, direct access */
1433 len = resp_caching_pg(ap, pcontrol, target);
1434 offset += len;
1435 break;
1436 case 0xa: /* Control Mode page, all devices */
1437 len = resp_ctrl_m_pg(ap, pcontrol, target);
1438 offset += len;
1439 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001440 case 0x19: /* if spc==1 then sas phy, control+discover */
1441 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1442 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1443 INVALID_FIELD_IN_CDB, 0);
1444 return check_condition_result;
1445 }
1446 len = 0;
1447 if ((0x0 == subpcode) || (0xff == subpcode))
1448 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1449 if ((0x1 == subpcode) || (0xff == subpcode))
1450 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1451 target_dev_id);
1452 if ((0x2 == subpcode) || (0xff == subpcode))
1453 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1454 offset += len;
1455 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 case 0x1c: /* Informational Exceptions Mode page, all devices */
1457 len = resp_iec_m_pg(ap, pcontrol, target);
1458 offset += len;
1459 break;
1460 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001461 if ((0 == subpcode) || (0xff == subpcode)) {
1462 len = resp_err_recov_pg(ap, pcontrol, target);
1463 len += resp_disconnect_pg(ap + len, pcontrol, target);
1464 len += resp_format_pg(ap + len, pcontrol, target);
1465 len += resp_caching_pg(ap + len, pcontrol, target);
1466 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1467 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1468 if (0xff == subpcode) {
1469 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1470 target, target_dev_id);
1471 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1472 }
1473 len += resp_iec_m_pg(ap + len, pcontrol, target);
1474 } else {
1475 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1476 INVALID_FIELD_IN_CDB, 0);
1477 return check_condition_result;
1478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 offset += len;
1480 break;
1481 default:
1482 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1483 0);
1484 return check_condition_result;
1485 }
1486 if (msense_6)
1487 arr[0] = offset - 1;
1488 else {
1489 arr[0] = ((offset - 2) >> 8) & 0xff;
1490 arr[1] = (offset - 2) & 0xff;
1491 }
1492 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1493}
1494
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001495#define SDEBUG_MAX_MSELECT_SZ 512
1496
1497static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1498 struct sdebug_dev_info * devip)
1499{
1500 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1501 int param_len, res, errsts, mpage;
1502 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1503 unsigned char *cmd = (unsigned char *)scp->cmnd;
1504
1505 if ((errsts = check_readiness(scp, 1, devip)))
1506 return errsts;
1507 memset(arr, 0, sizeof(arr));
1508 pf = cmd[1] & 0x10;
1509 sp = cmd[1] & 0x1;
1510 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1511 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1512 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1513 INVALID_FIELD_IN_CDB, 0);
1514 return check_condition_result;
1515 }
1516 res = fetch_to_dev_buffer(scp, arr, param_len);
1517 if (-1 == res)
1518 return (DID_ERROR << 16);
1519 else if ((res < param_len) &&
1520 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1521 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1522 " IO sent=%d bytes\n", param_len, res);
1523 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1524 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001525 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001526 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1527 INVALID_FIELD_IN_PARAM_LIST, 0);
1528 return check_condition_result;
1529 }
1530 off = bd_len + (mselect6 ? 4 : 8);
1531 mpage = arr[off] & 0x3f;
1532 ps = !!(arr[off] & 0x80);
1533 if (ps) {
1534 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1535 INVALID_FIELD_IN_PARAM_LIST, 0);
1536 return check_condition_result;
1537 }
1538 spf = !!(arr[off] & 0x40);
1539 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1540 (arr[off + 1] + 2);
1541 if ((pg_len + off) > param_len) {
1542 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1543 PARAMETER_LIST_LENGTH_ERR, 0);
1544 return check_condition_result;
1545 }
1546 switch (mpage) {
1547 case 0xa: /* Control Mode page */
1548 if (ctrl_m_pg[1] == arr[off + 1]) {
1549 memcpy(ctrl_m_pg + 2, arr + off + 2,
1550 sizeof(ctrl_m_pg) - 2);
1551 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1552 return 0;
1553 }
1554 break;
1555 case 0x1c: /* Informational Exceptions Mode page */
1556 if (iec_m_pg[1] == arr[off + 1]) {
1557 memcpy(iec_m_pg + 2, arr + off + 2,
1558 sizeof(iec_m_pg) - 2);
1559 return 0;
1560 }
1561 break;
1562 default:
1563 break;
1564 }
1565 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1566 INVALID_FIELD_IN_PARAM_LIST, 0);
1567 return check_condition_result;
1568}
1569
1570static int resp_temp_l_pg(unsigned char * arr)
1571{
1572 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1573 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1574 };
1575
1576 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1577 return sizeof(temp_l_pg);
1578}
1579
1580static int resp_ie_l_pg(unsigned char * arr)
1581{
1582 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1583 };
1584
1585 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1586 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1587 arr[4] = THRESHOLD_EXCEEDED;
1588 arr[5] = 0xff;
1589 }
1590 return sizeof(ie_l_pg);
1591}
1592
1593#define SDEBUG_MAX_LSENSE_SZ 512
1594
1595static int resp_log_sense(struct scsi_cmnd * scp,
1596 struct sdebug_dev_info * devip)
1597{
Douglas Gilbert23183912006-09-16 20:30:47 -04001598 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001599 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1600 unsigned char *cmd = (unsigned char *)scp->cmnd;
1601
1602 if ((errsts = check_readiness(scp, 1, devip)))
1603 return errsts;
1604 memset(arr, 0, sizeof(arr));
1605 ppc = cmd[1] & 0x2;
1606 sp = cmd[1] & 0x1;
1607 if (ppc || sp) {
1608 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1609 INVALID_FIELD_IN_CDB, 0);
1610 return check_condition_result;
1611 }
1612 pcontrol = (cmd[2] & 0xc0) >> 6;
1613 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001614 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001615 alloc_len = (cmd[7] << 8) + cmd[8];
1616 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001617 if (0 == subpcode) {
1618 switch (pcode) {
1619 case 0x0: /* Supported log pages log page */
1620 n = 4;
1621 arr[n++] = 0x0; /* this page */
1622 arr[n++] = 0xd; /* Temperature */
1623 arr[n++] = 0x2f; /* Informational exceptions */
1624 arr[3] = n - 4;
1625 break;
1626 case 0xd: /* Temperature log page */
1627 arr[3] = resp_temp_l_pg(arr + 4);
1628 break;
1629 case 0x2f: /* Informational exceptions log page */
1630 arr[3] = resp_ie_l_pg(arr + 4);
1631 break;
1632 default:
1633 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1634 INVALID_FIELD_IN_CDB, 0);
1635 return check_condition_result;
1636 }
1637 } else if (0xff == subpcode) {
1638 arr[0] |= 0x40;
1639 arr[1] = subpcode;
1640 switch (pcode) {
1641 case 0x0: /* Supported log pages and subpages log page */
1642 n = 4;
1643 arr[n++] = 0x0;
1644 arr[n++] = 0x0; /* 0,0 page */
1645 arr[n++] = 0x0;
1646 arr[n++] = 0xff; /* this page */
1647 arr[n++] = 0xd;
1648 arr[n++] = 0x0; /* Temperature */
1649 arr[n++] = 0x2f;
1650 arr[n++] = 0x0; /* Informational exceptions */
1651 arr[3] = n - 4;
1652 break;
1653 case 0xd: /* Temperature subpages */
1654 n = 4;
1655 arr[n++] = 0xd;
1656 arr[n++] = 0x0; /* Temperature */
1657 arr[3] = n - 4;
1658 break;
1659 case 0x2f: /* Informational exceptions subpages */
1660 n = 4;
1661 arr[n++] = 0x2f;
1662 arr[n++] = 0x0; /* Informational exceptions */
1663 arr[3] = n - 4;
1664 break;
1665 default:
1666 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1667 INVALID_FIELD_IN_CDB, 0);
1668 return check_condition_result;
1669 }
1670 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001671 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1672 INVALID_FIELD_IN_CDB, 0);
1673 return check_condition_result;
1674 }
1675 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1676 return fill_from_dev_buffer(scp, arr,
1677 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1678}
1679
FUJITA Tomonori19789102008-03-30 00:59:56 +09001680static int check_device_access_params(struct sdebug_dev_info *devi,
1681 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001683 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001684 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 return check_condition_result;
1686 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001687 /* transfer length excessive (tie in to block limits VPD page) */
1688 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001689 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001690 return check_condition_result;
1691 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001692 return 0;
1693}
1694
1695static int do_device_access(struct scsi_cmnd *scmd,
1696 struct sdebug_dev_info *devi,
1697 unsigned long long lba, unsigned int num, int write)
1698{
1699 int ret;
Darrick J. Wonga361cc02011-01-31 18:47:54 -08001700 unsigned long long block, rest = 0;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001701 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1702
1703 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1704
1705 block = do_div(lba, sdebug_store_sectors);
1706 if (block + num > sdebug_store_sectors)
1707 rest = block + num - sdebug_store_sectors;
1708
Martin K. Petersen597136a2008-06-05 00:12:59 -04001709 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1710 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001711 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001712 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001713
1714 return ret;
1715}
1716
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001717static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001718 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001719{
1720 unsigned int i, resid;
1721 struct scatterlist *psgl;
1722 struct sd_dif_tuple *sdt;
1723 sector_t sector;
1724 sector_t tmp_sec = start_sec;
1725 void *paddr;
1726
1727 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1728
1729 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1730
1731 for (i = 0 ; i < sectors ; i++) {
1732 u16 csum;
1733
1734 if (sdt[i].app_tag == 0xffff)
1735 continue;
1736
1737 sector = start_sec + i;
1738
1739 switch (scsi_debug_guard) {
1740 case 1:
1741 csum = ip_compute_csum(fake_storep +
1742 sector * scsi_debug_sector_size,
1743 scsi_debug_sector_size);
1744 break;
1745 case 0:
1746 csum = crc_t10dif(fake_storep +
1747 sector * scsi_debug_sector_size,
1748 scsi_debug_sector_size);
1749 csum = cpu_to_be16(csum);
1750 break;
1751 default:
1752 BUG();
1753 }
1754
1755 if (sdt[i].guard_tag != csum) {
1756 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1757 " rcvd 0x%04x, data 0x%04x\n", __func__,
1758 (unsigned long)sector,
1759 be16_to_cpu(sdt[i].guard_tag),
1760 be16_to_cpu(csum));
1761 dif_errors++;
1762 return 0x01;
1763 }
1764
Martin K. Petersen395cef02009-09-18 17:33:03 -04001765 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001766 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1767 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1768 __func__, (unsigned long)sector);
1769 dif_errors++;
1770 return 0x03;
1771 }
Martin K. Petersen395cef02009-09-18 17:33:03 -04001772
1773 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1774 be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1775 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1776 __func__, (unsigned long)sector);
1777 dif_errors++;
1778 return 0x03;
1779 }
1780
1781 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001782 }
1783
1784 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1785 sector = start_sec;
1786
1787 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1788 int len = min(psgl->length, resid);
1789
1790 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1791 memcpy(paddr, dif_storep + dif_offset(sector), len);
1792
1793 sector += len >> 3;
1794 if (sector >= sdebug_store_sectors) {
1795 /* Force wrap */
1796 tmp_sec = sector;
1797 sector = do_div(tmp_sec, sdebug_store_sectors);
1798 }
1799 resid -= len;
1800 kunmap_atomic(paddr, KM_IRQ0);
1801 }
1802
1803 dix_reads++;
1804
1805 return 0;
1806}
1807
FUJITA Tomonori19789102008-03-30 00:59:56 +09001808static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001809 unsigned int num, struct sdebug_dev_info *devip,
1810 u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001811{
1812 unsigned long iflags;
1813 int ret;
1814
1815 ret = check_device_access_params(devip, lba, num);
1816 if (ret)
1817 return ret;
1818
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05001820 (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001821 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1822 /* claim unrecoverable read error */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05001823 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001824 /* set info field and valid bit for fixed descriptor */
1825 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1826 devip->sense_buff[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05001827 ret = (lba < OPT_MEDIUM_ERR_ADDR)
1828 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001829 devip->sense_buff[3] = (ret >> 24) & 0xff;
1830 devip->sense_buff[4] = (ret >> 16) & 0xff;
1831 devip->sense_buff[5] = (ret >> 8) & 0xff;
1832 devip->sense_buff[6] = ret & 0xff;
1833 }
Douglas Gilberta87e3a62010-12-17 19:16:06 -05001834 scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 return check_condition_result;
1836 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001837
1838 /* DIX + T10 DIF */
1839 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001840 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001841
1842 if (prot_ret) {
1843 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1844 return illegal_condition_result;
1845 }
1846 }
1847
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001849 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 read_unlock_irqrestore(&atomic_rw, iflags);
1851 return ret;
1852}
1853
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001854void dump_sector(unsigned char *buf, int len)
1855{
1856 int i, j;
1857
1858 printk(KERN_ERR ">>> Sector Dump <<<\n");
1859
1860 for (i = 0 ; i < len ; i += 16) {
1861 printk(KERN_ERR "%04d: ", i);
1862
1863 for (j = 0 ; j < 16 ; j++) {
1864 unsigned char c = buf[i+j];
1865 if (c >= 0x20 && c < 0x7e)
1866 printk(" %c ", buf[i+j]);
1867 else
1868 printk("%02x ", buf[i+j]);
1869 }
1870
1871 printk("\n");
1872 }
1873}
1874
1875static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001876 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001877{
1878 int i, j, ret;
1879 struct sd_dif_tuple *sdt;
1880 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1881 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1882 void *daddr, *paddr;
1883 sector_t tmp_sec = start_sec;
1884 sector_t sector;
1885 int ppage_offset;
1886 unsigned short csum;
1887
1888 sector = do_div(tmp_sec, sdebug_store_sectors);
1889
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001890 BUG_ON(scsi_sg_count(SCpnt) == 0);
1891 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1892
1893 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1894 ppage_offset = 0;
1895
1896 /* For each data page */
1897 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1898 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1899
1900 /* For each sector-sized chunk in data page */
1901 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1902
1903 /* If we're at the end of the current
1904 * protection page advance to the next one
1905 */
1906 if (ppage_offset >= psgl->length) {
1907 kunmap_atomic(paddr, KM_IRQ1);
1908 psgl = sg_next(psgl);
1909 BUG_ON(psgl == NULL);
1910 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1911 + psgl->offset;
1912 ppage_offset = 0;
1913 }
1914
1915 sdt = paddr + ppage_offset;
1916
1917 switch (scsi_debug_guard) {
1918 case 1:
1919 csum = ip_compute_csum(daddr,
1920 scsi_debug_sector_size);
1921 break;
1922 case 0:
1923 csum = cpu_to_be16(crc_t10dif(daddr,
1924 scsi_debug_sector_size));
1925 break;
1926 default:
1927 BUG();
1928 ret = 0;
1929 goto out;
1930 }
1931
1932 if (sdt->guard_tag != csum) {
1933 printk(KERN_ERR
1934 "%s: GUARD check failed on sector %lu " \
1935 "rcvd 0x%04x, calculated 0x%04x\n",
1936 __func__, (unsigned long)sector,
1937 be16_to_cpu(sdt->guard_tag),
1938 be16_to_cpu(csum));
1939 ret = 0x01;
1940 dump_sector(daddr, scsi_debug_sector_size);
1941 goto out;
1942 }
1943
Martin K. Petersen395cef02009-09-18 17:33:03 -04001944 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001945 be32_to_cpu(sdt->ref_tag)
1946 != (start_sec & 0xffffffff)) {
1947 printk(KERN_ERR
1948 "%s: REF check failed on sector %lu\n",
1949 __func__, (unsigned long)sector);
1950 ret = 0x03;
1951 dump_sector(daddr, scsi_debug_sector_size);
1952 goto out;
1953 }
1954
Martin K. Petersen395cef02009-09-18 17:33:03 -04001955 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1956 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1957 printk(KERN_ERR
1958 "%s: REF check failed on sector %lu\n",
1959 __func__, (unsigned long)sector);
1960 ret = 0x03;
1961 dump_sector(daddr, scsi_debug_sector_size);
1962 goto out;
1963 }
1964
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001965 /* Would be great to copy this in bigger
1966 * chunks. However, for the sake of
1967 * correctness we need to verify each sector
1968 * before writing it to "stable" storage
1969 */
1970 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1971
1972 sector++;
1973
1974 if (sector == sdebug_store_sectors)
1975 sector = 0; /* Force wrap */
1976
1977 start_sec++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001978 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001979 daddr += scsi_debug_sector_size;
1980 ppage_offset += sizeof(struct sd_dif_tuple);
1981 }
1982
1983 kunmap_atomic(daddr, KM_IRQ0);
1984 }
1985
1986 kunmap_atomic(paddr, KM_IRQ1);
1987
1988 dix_writes++;
1989
1990 return 0;
1991
1992out:
1993 dif_errors++;
1994 kunmap_atomic(daddr, KM_IRQ0);
1995 kunmap_atomic(paddr, KM_IRQ1);
1996 return ret;
1997}
1998
Martin K. Petersen44d92692009-10-15 14:45:27 -04001999static unsigned int map_state(sector_t lba, unsigned int *num)
2000{
2001 unsigned int granularity, alignment, mapped;
2002 sector_t block, next, end;
2003
2004 granularity = scsi_debug_unmap_granularity;
2005 alignment = granularity - scsi_debug_unmap_alignment;
2006 block = lba + alignment;
2007 do_div(block, granularity);
2008
2009 mapped = test_bit(block, map_storep);
2010
2011 if (mapped)
2012 next = find_next_zero_bit(map_storep, map_size, block);
2013 else
2014 next = find_next_bit(map_storep, map_size, block);
2015
2016 end = next * granularity - scsi_debug_unmap_alignment;
2017 *num = end - lba;
2018
2019 return mapped;
2020}
2021
2022static void map_region(sector_t lba, unsigned int len)
2023{
2024 unsigned int granularity, alignment;
2025 sector_t end = lba + len;
2026
2027 granularity = scsi_debug_unmap_granularity;
2028 alignment = granularity - scsi_debug_unmap_alignment;
2029
2030 while (lba < end) {
2031 sector_t block, rem;
2032
2033 block = lba + alignment;
2034 rem = do_div(block, granularity);
2035
FUJITA Tomonori9ab98f52010-06-28 01:04:45 +09002036 if (block < map_size)
2037 set_bit(block, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002038
2039 lba += granularity - rem;
2040 }
2041}
2042
2043static void unmap_region(sector_t lba, unsigned int len)
2044{
2045 unsigned int granularity, alignment;
2046 sector_t end = lba + len;
2047
2048 granularity = scsi_debug_unmap_granularity;
2049 alignment = granularity - scsi_debug_unmap_alignment;
2050
2051 while (lba < end) {
2052 sector_t block, rem;
2053
2054 block = lba + alignment;
2055 rem = do_div(block, granularity);
2056
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002057 if (rem == 0 && lba + granularity <= end && block < map_size) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04002058 clear_bit(block, map_storep);
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002059 if (scsi_debug_lbprz)
2060 memset(fake_storep +
2061 block * scsi_debug_sector_size, 0,
2062 scsi_debug_sector_size);
2063 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04002064 lba += granularity - rem;
2065 }
2066}
2067
FUJITA Tomonori19789102008-03-30 00:59:56 +09002068static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002069 unsigned int num, struct sdebug_dev_info *devip,
2070 u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071{
2072 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002073 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074
FUJITA Tomonori19789102008-03-30 00:59:56 +09002075 ret = check_device_access_params(devip, lba, num);
2076 if (ret)
2077 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002079 /* DIX + T10 DIF */
2080 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002081 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002082
2083 if (prot_ret) {
2084 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2085 return illegal_condition_result;
2086 }
2087 }
2088
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002090 ret = do_device_access(SCpnt, devip, lba, num, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002091 if (scsi_debug_unmap_granularity)
2092 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002094 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002096 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002098 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04002099 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002100
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 return 0;
2102}
2103
Martin K. Petersen44d92692009-10-15 14:45:27 -04002104static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
2105 unsigned int num, struct sdebug_dev_info *devip,
2106 u32 ei_lba, unsigned int unmap)
2107{
2108 unsigned long iflags;
2109 unsigned long long i;
2110 int ret;
2111
2112 ret = check_device_access_params(devip, lba, num);
2113 if (ret)
2114 return ret;
2115
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002116 if (num > scsi_debug_write_same_length) {
2117 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2118 0);
2119 return check_condition_result;
2120 }
2121
Martin K. Petersen44d92692009-10-15 14:45:27 -04002122 write_lock_irqsave(&atomic_rw, iflags);
2123
2124 if (unmap && scsi_debug_unmap_granularity) {
2125 unmap_region(lba, num);
2126 goto out;
2127 }
2128
2129 /* Else fetch one logical block */
2130 ret = fetch_to_dev_buffer(scmd,
2131 fake_storep + (lba * scsi_debug_sector_size),
2132 scsi_debug_sector_size);
2133
2134 if (-1 == ret) {
2135 write_unlock_irqrestore(&atomic_rw, iflags);
2136 return (DID_ERROR << 16);
2137 } else if ((ret < (num * scsi_debug_sector_size)) &&
2138 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2139 printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
2140 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
2141
2142 /* Copy first sector to remaining blocks */
2143 for (i = 1 ; i < num ; i++)
2144 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2145 fake_storep + (lba * scsi_debug_sector_size),
2146 scsi_debug_sector_size);
2147
2148 if (scsi_debug_unmap_granularity)
2149 map_region(lba, num);
2150out:
2151 write_unlock_irqrestore(&atomic_rw, iflags);
2152
2153 return 0;
2154}
2155
2156struct unmap_block_desc {
2157 __be64 lba;
2158 __be32 blocks;
2159 __be32 __reserved;
2160};
2161
2162static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2163{
2164 unsigned char *buf;
2165 struct unmap_block_desc *desc;
2166 unsigned int i, payload_len, descriptors;
2167 int ret;
2168
2169 ret = check_readiness(scmd, 1, devip);
2170 if (ret)
2171 return ret;
2172
2173 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2174 BUG_ON(scsi_bufflen(scmd) != payload_len);
2175
2176 descriptors = (payload_len - 8) / 16;
2177
2178 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2179 if (!buf)
2180 return check_condition_result;
2181
2182 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2183
2184 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2185 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2186
2187 desc = (void *)&buf[8];
2188
2189 for (i = 0 ; i < descriptors ; i++) {
2190 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2191 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2192
2193 ret = check_device_access_params(devip, lba, num);
2194 if (ret)
2195 goto out;
2196
2197 unmap_region(lba, num);
2198 }
2199
2200 ret = 0;
2201
2202out:
2203 kfree(buf);
2204
2205 return ret;
2206}
2207
2208#define SDEBUG_GET_LBA_STATUS_LEN 32
2209
2210static int resp_get_lba_status(struct scsi_cmnd * scmd,
2211 struct sdebug_dev_info * devip)
2212{
2213 unsigned long long lba;
2214 unsigned int alloc_len, mapped, num;
2215 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2216 int ret;
2217
2218 ret = check_readiness(scmd, 1, devip);
2219 if (ret)
2220 return ret;
2221
2222 lba = get_unaligned_be64(&scmd->cmnd[2]);
2223 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2224
2225 if (alloc_len < 24)
2226 return 0;
2227
2228 ret = check_device_access_params(devip, lba, 1);
2229 if (ret)
2230 return ret;
2231
2232 mapped = map_state(lba, &num);
2233
2234 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertde13e962012-01-19 19:30:00 -05002235 put_unaligned_be32(20, &arr[0]); /* Parameter Data Length */
Martin K. Petersen44d92692009-10-15 14:45:27 -04002236 put_unaligned_be64(lba, &arr[8]); /* LBA */
2237 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2238 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2239
2240 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2241}
2242
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002243#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
2245static int resp_report_luns(struct scsi_cmnd * scp,
2246 struct sdebug_dev_info * devip)
2247{
2248 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002249 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 unsigned char *cmd = (unsigned char *)scp->cmnd;
2251 int select_report = (int)cmd[2];
2252 struct scsi_lun *one_lun;
2253 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002254 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255
2256 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002257 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2259 0);
2260 return check_condition_result;
2261 }
2262 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2263 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2264 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002265 if (1 == select_report)
2266 lun_cnt = 0;
2267 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2268 --lun_cnt;
2269 wlun = (select_report > 0) ? 1 : 0;
2270 num = lun_cnt + wlun;
2271 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2272 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2273 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2274 sizeof(struct scsi_lun)), num);
2275 if (n < num) {
2276 wlun = 0;
2277 lun_cnt = n;
2278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002280 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2281 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2282 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2283 i++, lun++) {
2284 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 if (upper)
2286 one_lun[i].scsi_lun[0] =
2287 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002288 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002290 if (wlun) {
2291 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2292 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2293 i++;
2294 }
2295 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 return fill_from_dev_buffer(scp, arr,
2297 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2298}
2299
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002300static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2301 unsigned int num, struct sdebug_dev_info *devip)
2302{
2303 int i, j, ret = -1;
2304 unsigned char *kaddr, *buf;
2305 unsigned int offset;
2306 struct scatterlist *sg;
2307 struct scsi_data_buffer *sdb = scsi_in(scp);
2308
2309 /* better not to use temporary buffer. */
2310 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2311 if (!buf)
2312 return ret;
2313
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002314 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002315
2316 offset = 0;
2317 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2318 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2319 if (!kaddr)
2320 goto out;
2321
2322 for (j = 0; j < sg->length; j++)
2323 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2324
2325 offset += sg->length;
2326 kunmap_atomic(kaddr, KM_USER0);
2327 }
2328 ret = 0;
2329out:
2330 kfree(buf);
2331
2332 return ret;
2333}
2334
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335/* When timer goes off this function is called. */
2336static void timer_intr_handler(unsigned long indx)
2337{
2338 struct sdebug_queued_cmd * sqcp;
2339 unsigned long iflags;
2340
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002341 if (indx >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2343 "large\n");
2344 return;
2345 }
2346 spin_lock_irqsave(&queued_arr_lock, iflags);
2347 sqcp = &queued_arr[(int)indx];
2348 if (! sqcp->in_use) {
2349 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2350 "interrupt\n");
2351 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2352 return;
2353 }
2354 sqcp->in_use = 0;
2355 if (sqcp->done_funct) {
2356 sqcp->a_cmnd->result = sqcp->scsi_result;
2357 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2358 }
2359 sqcp->done_funct = NULL;
2360 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2361}
2362
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002364static struct sdebug_dev_info *
2365sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002366{
2367 struct sdebug_dev_info *devip;
2368
2369 devip = kzalloc(sizeof(*devip), flags);
2370 if (devip) {
2371 devip->sdbg_host = sdbg_host;
2372 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2373 }
2374 return devip;
2375}
2376
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2378{
2379 struct sdebug_host_info * sdbg_host;
2380 struct sdebug_dev_info * open_devip = NULL;
2381 struct sdebug_dev_info * devip =
2382 (struct sdebug_dev_info *)sdev->hostdata;
2383
2384 if (devip)
2385 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002386 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2387 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 printk(KERN_ERR "Host info NULL\n");
2389 return NULL;
2390 }
2391 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2392 if ((devip->used) && (devip->channel == sdev->channel) &&
2393 (devip->target == sdev->id) &&
2394 (devip->lun == sdev->lun))
2395 return devip;
2396 else {
2397 if ((!devip->used) && (!open_devip))
2398 open_devip = devip;
2399 }
2400 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002401 if (!open_devip) { /* try and make a new one */
2402 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2403 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002405 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 return NULL;
2407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002409
2410 open_devip->channel = sdev->channel;
2411 open_devip->target = sdev->id;
2412 open_devip->lun = sdev->lun;
2413 open_devip->sdbg_host = sdbg_host;
2414 open_devip->reset = 1;
2415 open_devip->used = 1;
2416 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2417 if (scsi_debug_dsense)
2418 open_devip->sense_buff[0] = 0x72;
2419 else {
2420 open_devip->sense_buff[0] = 0x70;
2421 open_devip->sense_buff[7] = 0xa;
2422 }
2423 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2424 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2425
2426 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427}
2428
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002429static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002431 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2432 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2433 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002434 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002435 return 0;
2436}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002438static int scsi_debug_slave_configure(struct scsi_device *sdp)
2439{
2440 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002441
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002443 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2444 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2445 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2446 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2447 devip = devInfoReg(sdp);
2448 if (NULL == devip)
2449 return 1; /* no resources, will be marked offline */
2450 sdp->hostdata = devip;
2451 if (sdp->host->cmd_per_lun)
2452 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2453 sdp->host->cmd_per_lun);
2454 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002455 if (scsi_debug_no_uld)
2456 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002457 return 0;
2458}
2459
2460static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2461{
2462 struct sdebug_dev_info *devip =
2463 (struct sdebug_dev_info *)sdp->hostdata;
2464
2465 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2466 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2467 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2468 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002469 /* make this slot available for re-use */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002470 devip->used = 0;
2471 sdp->hostdata = NULL;
2472 }
2473}
2474
2475/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2476static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2477{
2478 unsigned long iflags;
2479 int k;
2480 struct sdebug_queued_cmd *sqcp;
2481
2482 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002483 for (k = 0; k < scsi_debug_max_queue; ++k) {
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002484 sqcp = &queued_arr[k];
2485 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2486 del_timer_sync(&sqcp->cmnd_timer);
2487 sqcp->in_use = 0;
2488 sqcp->a_cmnd = NULL;
2489 break;
2490 }
2491 }
2492 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002493 return (k < scsi_debug_max_queue) ? 1 : 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002494}
2495
2496/* Deletes (stops) timers of all queued commands */
2497static void stop_all_queued(void)
2498{
2499 unsigned long iflags;
2500 int k;
2501 struct sdebug_queued_cmd *sqcp;
2502
2503 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002504 for (k = 0; k < scsi_debug_max_queue; ++k) {
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002505 sqcp = &queued_arr[k];
2506 if (sqcp->in_use && sqcp->a_cmnd) {
2507 del_timer_sync(&sqcp->cmnd_timer);
2508 sqcp->in_use = 0;
2509 sqcp->a_cmnd = NULL;
2510 }
2511 }
2512 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513}
2514
2515static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2516{
2517 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2518 printk(KERN_INFO "scsi_debug: abort\n");
2519 ++num_aborts;
2520 stop_queued_cmnd(SCpnt);
2521 return SUCCESS;
2522}
2523
2524static int scsi_debug_biosparam(struct scsi_device *sdev,
2525 struct block_device * bdev, sector_t capacity, int *info)
2526{
2527 int res;
2528 unsigned char *buf;
2529
2530 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2531 printk(KERN_INFO "scsi_debug: biosparam\n");
2532 buf = scsi_bios_ptable(bdev);
2533 if (buf) {
2534 res = scsi_partsize(buf, capacity,
2535 &info[2], &info[0], &info[1]);
2536 kfree(buf);
2537 if (! res)
2538 return res;
2539 }
2540 info[0] = sdebug_heads;
2541 info[1] = sdebug_sectors_per;
2542 info[2] = sdebug_cylinders_per;
2543 return 0;
2544}
2545
2546static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2547{
2548 struct sdebug_dev_info * devip;
2549
2550 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2551 printk(KERN_INFO "scsi_debug: device_reset\n");
2552 ++num_dev_resets;
2553 if (SCpnt) {
2554 devip = devInfoReg(SCpnt->device);
2555 if (devip)
2556 devip->reset = 1;
2557 }
2558 return SUCCESS;
2559}
2560
2561static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2562{
2563 struct sdebug_host_info *sdbg_host;
2564 struct sdebug_dev_info * dev_info;
2565 struct scsi_device * sdp;
2566 struct Scsi_Host * hp;
2567
2568 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2569 printk(KERN_INFO "scsi_debug: bus_reset\n");
2570 ++num_bus_resets;
2571 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002572 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 if (sdbg_host) {
2574 list_for_each_entry(dev_info,
2575 &sdbg_host->dev_info_list,
2576 dev_list)
2577 dev_info->reset = 1;
2578 }
2579 }
2580 return SUCCESS;
2581}
2582
2583static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2584{
2585 struct sdebug_host_info * sdbg_host;
2586 struct sdebug_dev_info * dev_info;
2587
2588 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2589 printk(KERN_INFO "scsi_debug: host_reset\n");
2590 ++num_host_resets;
2591 spin_lock(&sdebug_host_list_lock);
2592 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2593 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2594 dev_list)
2595 dev_info->reset = 1;
2596 }
2597 spin_unlock(&sdebug_host_list_lock);
2598 stop_all_queued();
2599 return SUCCESS;
2600}
2601
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602/* Initializes timers in queued array */
2603static void __init init_all_queued(void)
2604{
2605 unsigned long iflags;
2606 int k;
2607 struct sdebug_queued_cmd * sqcp;
2608
2609 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002610 for (k = 0; k < scsi_debug_max_queue; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 sqcp = &queued_arr[k];
2612 init_timer(&sqcp->cmnd_timer);
2613 sqcp->in_use = 0;
2614 sqcp->a_cmnd = NULL;
2615 }
2616 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2617}
2618
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002619static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002620 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621{
2622 struct partition * pp;
2623 int starts[SDEBUG_MAX_PARTS + 2];
2624 int sectors_per_part, num_sectors, k;
2625 int heads_by_sects, start_sec, end_sec;
2626
2627 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002628 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 return;
2630 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2631 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2632 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2633 "partitions to %d\n", SDEBUG_MAX_PARTS);
2634 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002635 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 sectors_per_part = (num_sectors - sdebug_sectors_per)
2637 / scsi_debug_num_parts;
2638 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2639 starts[0] = sdebug_sectors_per;
2640 for (k = 1; k < scsi_debug_num_parts; ++k)
2641 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2642 * heads_by_sects;
2643 starts[scsi_debug_num_parts] = num_sectors;
2644 starts[scsi_debug_num_parts + 1] = 0;
2645
2646 ramp[510] = 0x55; /* magic partition markings */
2647 ramp[511] = 0xAA;
2648 pp = (struct partition *)(ramp + 0x1be);
2649 for (k = 0; starts[k + 1]; ++k, ++pp) {
2650 start_sec = starts[k];
2651 end_sec = starts[k + 1] - 1;
2652 pp->boot_ind = 0;
2653
2654 pp->cyl = start_sec / heads_by_sects;
2655 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2656 / sdebug_sectors_per;
2657 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2658
2659 pp->end_cyl = end_sec / heads_by_sects;
2660 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2661 / sdebug_sectors_per;
2662 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2663
2664 pp->start_sect = start_sec;
2665 pp->nr_sects = end_sec - start_sec + 1;
2666 pp->sys_ind = 0x83; /* plain Linux partition */
2667 }
2668}
2669
2670static int schedule_resp(struct scsi_cmnd * cmnd,
2671 struct sdebug_dev_info * devip,
2672 done_funct_t done, int scsi_result, int delta_jiff)
2673{
2674 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2675 if (scsi_result) {
2676 struct scsi_device * sdp = cmnd->device;
2677
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002678 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2679 "non-zero result=0x%x\n", sdp->host->host_no,
2680 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 }
2682 }
2683 if (cmnd && devip) {
2684 /* simulate autosense by this driver */
2685 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2686 memcpy(cmnd->sense_buffer, devip->sense_buff,
2687 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2688 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2689 }
2690 if (delta_jiff <= 0) {
2691 if (cmnd)
2692 cmnd->result = scsi_result;
2693 if (done)
2694 done(cmnd);
2695 return 0;
2696 } else {
2697 unsigned long iflags;
2698 int k;
2699 struct sdebug_queued_cmd * sqcp = NULL;
2700
2701 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002702 for (k = 0; k < scsi_debug_max_queue; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 sqcp = &queued_arr[k];
2704 if (! sqcp->in_use)
2705 break;
2706 }
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002707 if (k >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2709 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2710 return 1; /* report busy to mid level */
2711 }
2712 sqcp->in_use = 1;
2713 sqcp->a_cmnd = cmnd;
2714 sqcp->scsi_result = scsi_result;
2715 sqcp->done_funct = done;
2716 sqcp->cmnd_timer.function = timer_intr_handler;
2717 sqcp->cmnd_timer.data = k;
2718 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2719 add_timer(&sqcp->cmnd_timer);
2720 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2721 if (cmnd)
2722 cmnd->result = 0;
2723 return 0;
2724 }
2725}
Douglas Gilbert23183912006-09-16 20:30:47 -04002726/* Note: The following macros create attribute files in the
2727 /sys/module/scsi_debug/parameters directory. Unfortunately this
2728 driver is unaware of a change and cannot trigger auxiliary actions
2729 as it can when the corresponding attribute in the
2730 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2731 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002732module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002733module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002734module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2735module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002736module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2737module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002738module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2739module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002740module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002741module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2742module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO);
2743module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO);
2744module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO);
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002745module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002746module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002747module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002748module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002749module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002750module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002751module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2752module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002753module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002754module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002755module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002756module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2757module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002758module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
2759module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
2760module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
2761module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
2762module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002763module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002764module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2765 S_IRUGO | S_IWUSR);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002766module_param_named(write_same_length, scsi_debug_write_same_length, int,
2767 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
2769MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2770MODULE_DESCRIPTION("SCSI debug adapter driver");
2771MODULE_LICENSE("GPL");
2772MODULE_VERSION(SCSI_DEBUG_VERSION);
2773
2774MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002775MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002777MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002778MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2779MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002780MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002781MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002782MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002783MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2784MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
2785MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
2786MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002787MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002788MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002789MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002790MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002791MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002792MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002794MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002795MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002796MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002797MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2799MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002800MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05002801MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
2802MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04002803MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
2804MODULE_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 -05002805MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
2806MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
2807MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809static char sdebug_info[256];
2810
2811static const char * scsi_debug_info(struct Scsi_Host * shp)
2812{
2813 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2814 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2815 scsi_debug_version_date, scsi_debug_dev_size_mb,
2816 scsi_debug_opts);
2817 return sdebug_info;
2818}
2819
2820/* scsi_debug_proc_info
2821 * Used if the driver currently has no own support for /proc/scsi
2822 */
2823static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2824 int length, int inout)
2825{
2826 int len, pos, begin;
2827 int orig_length;
2828
2829 orig_length = length;
2830
2831 if (inout == 1) {
2832 char arr[16];
2833 int minLen = length > 15 ? 15 : length;
2834
2835 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2836 return -EACCES;
2837 memcpy(arr, buffer, minLen);
2838 arr[minLen] = '\0';
2839 if (1 != sscanf(arr, "%d", &pos))
2840 return -EINVAL;
2841 scsi_debug_opts = pos;
2842 if (scsi_debug_every_nth != 0)
2843 scsi_debug_cmnd_count = 0;
2844 return length;
2845 }
2846 begin = 0;
2847 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2848 "%s [%s]\n"
2849 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2850 "every_nth=%d(curr:%d)\n"
2851 "delay=%d, max_luns=%d, scsi_level=%d\n"
2852 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2853 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002854 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2856 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2857 scsi_debug_cmnd_count, scsi_debug_delay,
2858 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002859 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2860 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002861 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 if (pos < offset) {
2863 len = 0;
2864 begin = pos;
2865 }
2866 *start = buffer + (offset - begin); /* Start of wanted data */
2867 len -= (offset - begin);
2868 if (len > length)
2869 len = length;
2870 return len;
2871}
2872
2873static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2874{
2875 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2876}
2877
2878static ssize_t sdebug_delay_store(struct device_driver * ddp,
2879 const char * buf, size_t count)
2880{
2881 int delay;
2882 char work[20];
2883
2884 if (1 == sscanf(buf, "%10s", work)) {
2885 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2886 scsi_debug_delay = delay;
2887 return count;
2888 }
2889 }
2890 return -EINVAL;
2891}
2892DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2893 sdebug_delay_store);
2894
2895static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2896{
2897 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2898}
2899
2900static ssize_t sdebug_opts_store(struct device_driver * ddp,
2901 const char * buf, size_t count)
2902{
2903 int opts;
2904 char work[20];
2905
2906 if (1 == sscanf(buf, "%10s", work)) {
2907 if (0 == strnicmp(work,"0x", 2)) {
2908 if (1 == sscanf(&work[2], "%x", &opts))
2909 goto opts_done;
2910 } else {
2911 if (1 == sscanf(work, "%d", &opts))
2912 goto opts_done;
2913 }
2914 }
2915 return -EINVAL;
2916opts_done:
2917 scsi_debug_opts = opts;
2918 scsi_debug_cmnd_count = 0;
2919 return count;
2920}
2921DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2922 sdebug_opts_store);
2923
2924static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2925{
2926 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2927}
2928static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2929 const char * buf, size_t count)
2930{
2931 int n;
2932
2933 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2934 scsi_debug_ptype = n;
2935 return count;
2936 }
2937 return -EINVAL;
2938}
2939DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2940
2941static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2942{
2943 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2944}
2945static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2946 const char * buf, size_t count)
2947{
2948 int n;
2949
2950 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2951 scsi_debug_dsense = n;
2952 return count;
2953 }
2954 return -EINVAL;
2955}
2956DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2957 sdebug_dsense_store);
2958
Douglas Gilbert23183912006-09-16 20:30:47 -04002959static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2960{
2961 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2962}
2963static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2964 const char * buf, size_t count)
2965{
2966 int n;
2967
2968 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2969 scsi_debug_fake_rw = n;
2970 return count;
2971 }
2972 return -EINVAL;
2973}
2974DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2975 sdebug_fake_rw_store);
2976
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002977static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2978{
2979 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2980}
2981static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2982 const char * buf, size_t count)
2983{
2984 int n;
2985
2986 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2987 scsi_debug_no_lun_0 = n;
2988 return count;
2989 }
2990 return -EINVAL;
2991}
2992DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2993 sdebug_no_lun_0_store);
2994
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2996{
2997 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2998}
2999static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
3000 const char * buf, size_t count)
3001{
3002 int n;
3003
3004 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3005 scsi_debug_num_tgts = n;
3006 sdebug_max_tgts_luns();
3007 return count;
3008 }
3009 return -EINVAL;
3010}
3011DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
3012 sdebug_num_tgts_store);
3013
3014static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
3015{
3016 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
3017}
3018DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
3019
3020static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
3021{
3022 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
3023}
3024DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
3025
3026static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
3027{
3028 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
3029}
3030static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
3031 const char * buf, size_t count)
3032{
3033 int nth;
3034
3035 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
3036 scsi_debug_every_nth = nth;
3037 scsi_debug_cmnd_count = 0;
3038 return count;
3039 }
3040 return -EINVAL;
3041}
3042DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
3043 sdebug_every_nth_store);
3044
3045static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
3046{
3047 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
3048}
3049static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
3050 const char * buf, size_t count)
3051{
3052 int n;
3053
3054 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3055 scsi_debug_max_luns = n;
3056 sdebug_max_tgts_luns();
3057 return count;
3058 }
3059 return -EINVAL;
3060}
3061DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
3062 sdebug_max_luns_store);
3063
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003064static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
3065{
3066 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
3067}
3068static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
3069 const char * buf, size_t count)
3070{
3071 int n;
3072
3073 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
3074 (n <= SCSI_DEBUG_CANQUEUE)) {
3075 scsi_debug_max_queue = n;
3076 return count;
3077 }
3078 return -EINVAL;
3079}
3080DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
3081 sdebug_max_queue_store);
3082
3083static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
3084{
3085 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
3086}
3087DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
3088
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
3090{
3091 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
3092}
3093DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
3094
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003095static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
3096{
3097 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3098}
3099static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
3100 const char * buf, size_t count)
3101{
3102 int n;
3103
3104 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3105 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003106
3107 sdebug_capacity = get_sdebug_capacity();
3108
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003109 return count;
3110 }
3111 return -EINVAL;
3112}
3113DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
3114 sdebug_virtual_gb_store);
3115
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
3117{
3118 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
3119}
3120
3121static ssize_t sdebug_add_host_store(struct device_driver * ddp,
3122 const char * buf, size_t count)
3123{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003124 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003126 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 if (delta_hosts > 0) {
3129 do {
3130 sdebug_add_adapter();
3131 } while (--delta_hosts);
3132 } else if (delta_hosts < 0) {
3133 do {
3134 sdebug_remove_adapter();
3135 } while (++delta_hosts);
3136 }
3137 return count;
3138}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003139DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 sdebug_add_host_store);
3141
Douglas Gilbert23183912006-09-16 20:30:47 -04003142static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
3143 char * buf)
3144{
3145 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3146}
3147static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
3148 const char * buf, size_t count)
3149{
3150 int n;
3151
3152 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3153 scsi_debug_vpd_use_hostno = n;
3154 return count;
3155 }
3156 return -EINVAL;
3157}
3158DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
3159 sdebug_vpd_use_hostno_store);
3160
Martin K. Petersen597136a2008-06-05 00:12:59 -04003161static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3162{
3163 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3164}
3165DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3166
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003167static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3168{
3169 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3170}
3171DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3172
3173static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3174{
3175 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3176}
3177DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3178
3179static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3180{
3181 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3182}
3183DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3184
3185static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3186{
3187 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3188}
3189DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3190
Martin K. Petersen44d92692009-10-15 14:45:27 -04003191static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
3192{
3193 ssize_t count;
3194
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003195 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003196 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3197 sdebug_store_sectors);
3198
3199 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3200
3201 buf[count++] = '\n';
3202 buf[count++] = 0;
3203
3204 return count;
3205}
3206DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
3207
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003208
Douglas Gilbert23183912006-09-16 20:30:47 -04003209/* Note: The following function creates attribute files in the
3210 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3211 files (over those found in the /sys/module/scsi_debug/parameters
3212 directory) is that auxiliary actions can be triggered when an attribute
3213 is changed. For example see: sdebug_add_host_store() above.
3214 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003215static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003217 int ret;
3218
3219 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3220 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
3221 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3222 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3223 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04003224 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003225 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003226 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
Douglas Gilbert23183912006-09-16 20:30:47 -04003227 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003228 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003229 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003230 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003231 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3232 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
3233 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04003234 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
3235 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003236 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003237 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3238 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3239 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3240 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003241 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003242 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243}
3244
3245static void do_remove_driverfs_files(void)
3246{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003247 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003248 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3249 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3250 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3251 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003252 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04003253 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3254 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
3256 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
3257 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003259 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003260 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
Douglas Gilbert23183912006-09-16 20:30:47 -04003261 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003262 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003264 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
3266 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3267 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3268 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
3269 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3270}
3271
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003272struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003273
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274static int __init scsi_debug_init(void)
3275{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003276 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 int host_to_add;
3278 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003279 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
Martin K. Petersen597136a2008-06-05 00:12:59 -04003281 switch (scsi_debug_sector_size) {
3282 case 512:
3283 case 1024:
3284 case 2048:
3285 case 4096:
3286 break;
3287 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003288 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04003289 scsi_debug_sector_size);
3290 return -EINVAL;
3291 }
3292
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003293 switch (scsi_debug_dif) {
3294
3295 case SD_DIF_TYPE0_PROTECTION:
3296 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003297 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003298 case SD_DIF_TYPE3_PROTECTION:
3299 break;
3300
3301 default:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003302 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003303 return -EINVAL;
3304 }
3305
3306 if (scsi_debug_guard > 1) {
3307 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3308 return -EINVAL;
3309 }
3310
3311 if (scsi_debug_ato > 1) {
3312 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3313 return -EINVAL;
3314 }
3315
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003316 if (scsi_debug_physblk_exp > 15) {
3317 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3318 scsi_debug_physblk_exp);
3319 return -EINVAL;
3320 }
3321
3322 if (scsi_debug_lowest_aligned > 0x3fff) {
3323 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3324 scsi_debug_lowest_aligned);
3325 return -EINVAL;
3326 }
3327
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 if (scsi_debug_dev_size_mb < 1)
3329 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003330 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003331 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003332 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333
3334 /* play around with geometry, don't waste too much on track 0 */
3335 sdebug_heads = 8;
3336 sdebug_sectors_per = 32;
3337 if (scsi_debug_dev_size_mb >= 16)
3338 sdebug_heads = 32;
3339 else if (scsi_debug_dev_size_mb >= 256)
3340 sdebug_heads = 64;
3341 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3342 (sdebug_sectors_per * sdebug_heads);
3343 if (sdebug_cylinders_per >= 1024) {
3344 /* other LLDs do this; implies >= 1GB ram disk ... */
3345 sdebug_heads = 255;
3346 sdebug_sectors_per = 63;
3347 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3348 (sdebug_sectors_per * sdebug_heads);
3349 }
3350
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 fake_storep = vmalloc(sz);
3352 if (NULL == fake_storep) {
3353 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
3354 return -ENOMEM;
3355 }
3356 memset(fake_storep, 0, sz);
3357 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003358 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003360 if (scsi_debug_dif) {
3361 int dif_size;
3362
3363 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3364 dif_storep = vmalloc(dif_size);
3365
3366 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3367 dif_size, dif_storep);
3368
3369 if (dif_storep == NULL) {
3370 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3371 ret = -ENOMEM;
3372 goto free_vm;
3373 }
3374
3375 memset(dif_storep, 0xff, dif_size);
3376 }
3377
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003378 /* Logical Block Provisioning */
3379 if (scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003380 unsigned int map_bytes;
3381
Martin K. Petersen60147592010-08-19 11:49:00 -04003382 scsi_debug_unmap_max_blocks =
3383 clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
3384
3385 scsi_debug_unmap_max_desc =
3386 clamp(scsi_debug_unmap_max_desc, 0U, 256U);
3387
3388 scsi_debug_unmap_granularity =
3389 clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);
3390
3391 if (scsi_debug_unmap_alignment &&
3392 scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003393 printk(KERN_ERR
3394 "%s: ERR: unmap_granularity < unmap_alignment\n",
3395 __func__);
3396 return -EINVAL;
3397 }
3398
3399 map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
3400 map_bytes = map_size >> 3;
3401 map_storep = vmalloc(map_bytes);
3402
3403 printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
3404 map_size);
3405
3406 if (map_storep == NULL) {
3407 printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
3408 ret = -ENOMEM;
3409 goto free_vm;
3410 }
3411
3412 memset(map_storep, 0x0, map_bytes);
3413
3414 /* Map first 1KB for partition table */
3415 if (scsi_debug_num_parts)
3416 map_region(0, 2);
3417 }
3418
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003419 pseudo_primary = root_device_register("pseudo_0");
3420 if (IS_ERR(pseudo_primary)) {
3421 printk(KERN_WARNING "scsi_debug: root_device_register() error\n");
3422 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003423 goto free_vm;
3424 }
3425 ret = bus_register(&pseudo_lld_bus);
3426 if (ret < 0) {
3427 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
3428 ret);
3429 goto dev_unreg;
3430 }
3431 ret = driver_register(&sdebug_driverfs_driver);
3432 if (ret < 0) {
3433 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
3434 ret);
3435 goto bus_unreg;
3436 }
3437 ret = do_create_driverfs_files();
3438 if (ret < 0) {
3439 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
3440 ret);
3441 goto del_files;
3442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003444 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 host_to_add = scsi_debug_add_host;
3447 scsi_debug_add_host = 0;
3448
3449 for (k = 0; k < host_to_add; k++) {
3450 if (sdebug_add_adapter()) {
3451 printk(KERN_ERR "scsi_debug_init: "
3452 "sdebug_add_adapter failed k=%d\n", k);
3453 break;
3454 }
3455 }
3456
3457 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3458 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
3459 scsi_debug_add_host);
3460 }
3461 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003462
3463del_files:
3464 do_remove_driverfs_files();
3465 driver_unregister(&sdebug_driverfs_driver);
3466bus_unreg:
3467 bus_unregister(&pseudo_lld_bus);
3468dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003469 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003470free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003471 if (map_storep)
3472 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003473 if (dif_storep)
3474 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003475 vfree(fake_storep);
3476
3477 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478}
3479
3480static void __exit scsi_debug_exit(void)
3481{
3482 int k = scsi_debug_add_host;
3483
3484 stop_all_queued();
3485 for (; k; k--)
3486 sdebug_remove_adapter();
3487 do_remove_driverfs_files();
3488 driver_unregister(&sdebug_driverfs_driver);
3489 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003490 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003492 if (dif_storep)
3493 vfree(dif_storep);
3494
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 vfree(fake_storep);
3496}
3497
3498device_initcall(scsi_debug_init);
3499module_exit(scsi_debug_exit);
3500
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501static void sdebug_release_adapter(struct device * dev)
3502{
3503 struct sdebug_host_info *sdbg_host;
3504
3505 sdbg_host = to_sdebug_host(dev);
3506 kfree(sdbg_host);
3507}
3508
3509static int sdebug_add_adapter(void)
3510{
3511 int k, devs_per_host;
3512 int error = 0;
3513 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003514 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003516 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 if (NULL == sdbg_host) {
3518 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003519 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 return -ENOMEM;
3521 }
3522
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3524
3525 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3526 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003527 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3528 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003530 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 error = -ENOMEM;
3532 goto clean;
3533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 }
3535
3536 spin_lock(&sdebug_host_list_lock);
3537 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3538 spin_unlock(&sdebug_host_list_lock);
3539
3540 sdbg_host->dev.bus = &pseudo_lld_bus;
Nicholas Bellinger9b906772010-09-06 17:24:28 -07003541 sdbg_host->dev.parent = pseudo_primary;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003543 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544
3545 error = device_register(&sdbg_host->dev);
3546
3547 if (error)
3548 goto clean;
3549
3550 ++scsi_debug_add_host;
3551 return error;
3552
3553clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003554 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3555 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 list_del(&sdbg_devinfo->dev_list);
3557 kfree(sdbg_devinfo);
3558 }
3559
3560 kfree(sdbg_host);
3561 return error;
3562}
3563
3564static void sdebug_remove_adapter(void)
3565{
3566 struct sdebug_host_info * sdbg_host = NULL;
3567
3568 spin_lock(&sdebug_host_list_lock);
3569 if (!list_empty(&sdebug_host_list)) {
3570 sdbg_host = list_entry(sdebug_host_list.prev,
3571 struct sdebug_host_info, host_list);
3572 list_del(&sdbg_host->host_list);
3573 }
3574 spin_unlock(&sdebug_host_list_lock);
3575
3576 if (!sdbg_host)
3577 return;
3578
3579 device_unregister(&sdbg_host->dev);
3580 --scsi_debug_add_host;
3581}
3582
FUJITA Tomonori639db472008-03-20 11:09:19 +09003583static
Jeff Garzikf2812332010-11-16 02:10:29 -05003584int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)
FUJITA Tomonori639db472008-03-20 11:09:19 +09003585{
3586 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3587 int len, k;
3588 unsigned int num;
3589 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003590 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003591 int errsts = 0;
3592 int target = SCpnt->device->id;
3593 struct sdebug_dev_info *devip = NULL;
3594 int inj_recovered = 0;
3595 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003596 int inj_dif = 0;
3597 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003598 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003599 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003600
3601 scsi_set_resid(SCpnt, 0);
3602 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3603 printk(KERN_INFO "scsi_debug: cmd ");
3604 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3605 printk("%02x ", (int)cmd[k]);
3606 printk("\n");
3607 }
3608
3609 if (target == SCpnt->device->host->hostt->this_id) {
3610 printk(KERN_INFO "scsi_debug: initiator's id used as "
3611 "target!\n");
3612 return schedule_resp(SCpnt, NULL, done,
3613 DID_NO_CONNECT << 16, 0);
3614 }
3615
3616 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3617 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3618 return schedule_resp(SCpnt, NULL, done,
3619 DID_NO_CONNECT << 16, 0);
3620 devip = devInfoReg(SCpnt->device);
3621 if (NULL == devip)
3622 return schedule_resp(SCpnt, NULL, done,
3623 DID_NO_CONNECT << 16, 0);
3624
3625 if ((scsi_debug_every_nth != 0) &&
3626 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3627 scsi_debug_cmnd_count = 0;
3628 if (scsi_debug_every_nth < -1)
3629 scsi_debug_every_nth = -1;
3630 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3631 return 0; /* ignore command causing timeout */
Martin K. Petersen18a4d0a2012-02-09 13:48:53 -05003632 else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
3633 scsi_medium_access_command(SCpnt))
3634 return 0; /* time out reads and writes */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003635 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3636 inj_recovered = 1; /* to reads and writes below */
3637 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3638 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003639 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3640 inj_dif = 1; /* to reads and writes below */
3641 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3642 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003643 }
3644
3645 if (devip->wlun) {
3646 switch (*cmd) {
3647 case INQUIRY:
3648 case REQUEST_SENSE:
3649 case TEST_UNIT_READY:
3650 case REPORT_LUNS:
3651 break; /* only allowable wlun commands */
3652 default:
3653 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3654 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3655 "not supported for wlun\n", *cmd);
3656 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3657 INVALID_OPCODE, 0);
3658 errsts = check_condition_result;
3659 return schedule_resp(SCpnt, devip, done, errsts,
3660 0);
3661 }
3662 }
3663
3664 switch (*cmd) {
3665 case INQUIRY: /* mandatory, ignore unit attention */
3666 delay_override = 1;
3667 errsts = resp_inquiry(SCpnt, target, devip);
3668 break;
3669 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3670 delay_override = 1;
3671 errsts = resp_requests(SCpnt, devip);
3672 break;
3673 case REZERO_UNIT: /* actually this is REWIND for SSC */
3674 case START_STOP:
3675 errsts = resp_start_stop(SCpnt, devip);
3676 break;
3677 case ALLOW_MEDIUM_REMOVAL:
3678 errsts = check_readiness(SCpnt, 1, devip);
3679 if (errsts)
3680 break;
3681 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3682 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3683 cmd[4] ? "inhibited" : "enabled");
3684 break;
3685 case SEND_DIAGNOSTIC: /* mandatory */
3686 errsts = check_readiness(SCpnt, 1, devip);
3687 break;
3688 case TEST_UNIT_READY: /* mandatory */
3689 delay_override = 1;
3690 errsts = check_readiness(SCpnt, 0, devip);
3691 break;
3692 case RESERVE:
3693 errsts = check_readiness(SCpnt, 1, devip);
3694 break;
3695 case RESERVE_10:
3696 errsts = check_readiness(SCpnt, 1, devip);
3697 break;
3698 case RELEASE:
3699 errsts = check_readiness(SCpnt, 1, devip);
3700 break;
3701 case RELEASE_10:
3702 errsts = check_readiness(SCpnt, 1, devip);
3703 break;
3704 case READ_CAPACITY:
3705 errsts = resp_readcap(SCpnt, devip);
3706 break;
3707 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003708 if (cmd[1] == SAI_READ_CAPACITY_16)
3709 errsts = resp_readcap16(SCpnt, devip);
3710 else if (cmd[1] == SAI_GET_LBA_STATUS) {
3711
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003712 if (scsi_debug_lbp() == 0) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003713 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3714 INVALID_COMMAND_OPCODE, 0);
3715 errsts = check_condition_result;
3716 } else
3717 errsts = resp_get_lba_status(SCpnt, devip);
3718 } else {
FUJITA Tomonori639db472008-03-20 11:09:19 +09003719 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3720 INVALID_OPCODE, 0);
3721 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003722 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09003723 break;
3724 case MAINTENANCE_IN:
3725 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3726 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3727 INVALID_OPCODE, 0);
3728 errsts = check_condition_result;
3729 break;
3730 }
3731 errsts = resp_report_tgtpgs(SCpnt, devip);
3732 break;
3733 case READ_16:
3734 case READ_12:
3735 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003736 /* READ{10,12,16} and DIF Type 2 are natural enemies */
3737 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3738 cmd[1] & 0xe0) {
3739 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3740 INVALID_COMMAND_OPCODE, 0);
3741 errsts = check_condition_result;
3742 break;
3743 }
3744
3745 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3746 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3747 (cmd[1] & 0xe0) == 0)
3748 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3749
3750 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003751 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003752read:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003753 errsts = check_readiness(SCpnt, 0, devip);
3754 if (errsts)
3755 break;
3756 if (scsi_debug_fake_rw)
3757 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003758 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3759 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003760 if (inj_recovered && (0 == errsts)) {
3761 mk_sense_buffer(devip, RECOVERED_ERROR,
3762 THRESHOLD_EXCEEDED, 0);
3763 errsts = check_condition_result;
3764 } else if (inj_transport && (0 == errsts)) {
3765 mk_sense_buffer(devip, ABORTED_COMMAND,
3766 TRANSPORT_PROBLEM, ACK_NAK_TO);
3767 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003768 } else if (inj_dif && (0 == errsts)) {
3769 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3770 errsts = illegal_condition_result;
3771 } else if (inj_dix && (0 == errsts)) {
3772 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3773 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003774 }
3775 break;
3776 case REPORT_LUNS: /* mandatory, ignore unit attention */
3777 delay_override = 1;
3778 errsts = resp_report_luns(SCpnt, devip);
3779 break;
3780 case VERIFY: /* 10 byte SBC-2 command */
3781 errsts = check_readiness(SCpnt, 0, devip);
3782 break;
3783 case WRITE_16:
3784 case WRITE_12:
3785 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003786 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3787 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3788 cmd[1] & 0xe0) {
3789 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3790 INVALID_COMMAND_OPCODE, 0);
3791 errsts = check_condition_result;
3792 break;
3793 }
3794
3795 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3796 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3797 (cmd[1] & 0xe0) == 0)
3798 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3799
3800 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003801 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003802write:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003803 errsts = check_readiness(SCpnt, 0, devip);
3804 if (errsts)
3805 break;
3806 if (scsi_debug_fake_rw)
3807 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003808 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3809 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003810 if (inj_recovered && (0 == errsts)) {
3811 mk_sense_buffer(devip, RECOVERED_ERROR,
3812 THRESHOLD_EXCEEDED, 0);
3813 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003814 } else if (inj_dif && (0 == errsts)) {
3815 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3816 errsts = illegal_condition_result;
3817 } else if (inj_dix && (0 == errsts)) {
3818 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3819 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003820 }
3821 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003822 case WRITE_SAME_16:
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003823 case WRITE_SAME:
Martin K. Petersen60147592010-08-19 11:49:00 -04003824 if (cmd[1] & 0x8) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003825 if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
3826 (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
Martin K. Petersen60147592010-08-19 11:49:00 -04003827 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3828 INVALID_FIELD_IN_CDB, 0);
3829 errsts = check_condition_result;
3830 } else
3831 unmap = 1;
3832 }
3833 if (errsts)
3834 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003835 errsts = check_readiness(SCpnt, 0, devip);
3836 if (errsts)
3837 break;
3838 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3839 errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
3840 break;
3841 case UNMAP:
3842 errsts = check_readiness(SCpnt, 0, devip);
3843 if (errsts)
3844 break;
3845
Martin K. Petersen5b94e232011-03-08 02:08:11 -05003846 if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003847 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3848 INVALID_COMMAND_OPCODE, 0);
3849 errsts = check_condition_result;
3850 } else
3851 errsts = resp_unmap(SCpnt, devip);
3852 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003853 case MODE_SENSE:
3854 case MODE_SENSE_10:
3855 errsts = resp_mode_sense(SCpnt, target, devip);
3856 break;
3857 case MODE_SELECT:
3858 errsts = resp_mode_select(SCpnt, 1, devip);
3859 break;
3860 case MODE_SELECT_10:
3861 errsts = resp_mode_select(SCpnt, 0, devip);
3862 break;
3863 case LOG_SENSE:
3864 errsts = resp_log_sense(SCpnt, devip);
3865 break;
3866 case SYNCHRONIZE_CACHE:
3867 delay_override = 1;
3868 errsts = check_readiness(SCpnt, 0, devip);
3869 break;
3870 case WRITE_BUFFER:
3871 errsts = check_readiness(SCpnt, 1, devip);
3872 break;
3873 case XDWRITEREAD_10:
3874 if (!scsi_bidi_cmnd(SCpnt)) {
3875 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3876 INVALID_FIELD_IN_CDB, 0);
3877 errsts = check_condition_result;
3878 break;
3879 }
3880
3881 errsts = check_readiness(SCpnt, 0, devip);
3882 if (errsts)
3883 break;
3884 if (scsi_debug_fake_rw)
3885 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003886 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3887 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003888 if (errsts)
3889 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003890 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003891 if (errsts)
3892 break;
3893 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3894 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003895 case VARIABLE_LENGTH_CMD:
3896 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3897
3898 if ((cmd[10] & 0xe0) == 0)
3899 printk(KERN_ERR
3900 "Unprotected RD/WR to DIF device\n");
3901
3902 if (cmd[9] == READ_32) {
3903 BUG_ON(SCpnt->cmd_len < 32);
3904 goto read;
3905 }
3906
3907 if (cmd[9] == WRITE_32) {
3908 BUG_ON(SCpnt->cmd_len < 32);
3909 goto write;
3910 }
3911 }
3912
3913 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3914 INVALID_FIELD_IN_CDB, 0);
3915 errsts = check_condition_result;
3916 break;
3917
FUJITA Tomonori639db472008-03-20 11:09:19 +09003918 default:
3919 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3920 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3921 "supported\n", *cmd);
3922 errsts = check_readiness(SCpnt, 1, devip);
3923 if (errsts)
3924 break; /* Unit attention takes precedence */
3925 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3926 errsts = check_condition_result;
3927 break;
3928 }
3929 return schedule_resp(SCpnt, devip, done, errsts,
3930 (delay_override ? 0 : scsi_debug_delay));
3931}
3932
Jeff Garzikf2812332010-11-16 02:10:29 -05003933static DEF_SCSI_QCMD(scsi_debug_queuecommand)
3934
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003935static struct scsi_host_template sdebug_driver_template = {
3936 .proc_info = scsi_debug_proc_info,
3937 .proc_name = sdebug_proc_name,
3938 .name = "SCSI DEBUG",
3939 .info = scsi_debug_info,
3940 .slave_alloc = scsi_debug_slave_alloc,
3941 .slave_configure = scsi_debug_slave_configure,
3942 .slave_destroy = scsi_debug_slave_destroy,
3943 .ioctl = scsi_debug_ioctl,
3944 .queuecommand = scsi_debug_queuecommand,
3945 .eh_abort_handler = scsi_debug_abort,
3946 .eh_bus_reset_handler = scsi_debug_bus_reset,
3947 .eh_device_reset_handler = scsi_debug_device_reset,
3948 .eh_host_reset_handler = scsi_debug_host_reset,
3949 .bios_param = scsi_debug_biosparam,
3950 .can_queue = SCSI_DEBUG_CANQUEUE,
3951 .this_id = 7,
3952 .sg_tablesize = 256,
3953 .cmd_per_lun = 16,
3954 .max_sectors = 0xffff,
3955 .use_clustering = DISABLE_CLUSTERING,
3956 .module = THIS_MODULE,
3957};
3958
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959static int sdebug_driver_probe(struct device * dev)
3960{
3961 int error = 0;
3962 struct sdebug_host_info *sdbg_host;
3963 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003964 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965
3966 sdbg_host = to_sdebug_host(dev);
3967
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003968 sdebug_driver_template.can_queue = scsi_debug_max_queue;
3969 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3970 if (NULL == hpnt) {
3971 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
3972 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975
3976 sdbg_host->shost = hpnt;
3977 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3978 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3979 hpnt->max_id = scsi_debug_num_tgts + 1;
3980 else
3981 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003982 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003984 host_prot = 0;
3985
3986 switch (scsi_debug_dif) {
3987
3988 case SD_DIF_TYPE1_PROTECTION:
3989 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3990 if (scsi_debug_dix)
3991 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3992 break;
3993
3994 case SD_DIF_TYPE2_PROTECTION:
3995 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3996 if (scsi_debug_dix)
3997 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3998 break;
3999
4000 case SD_DIF_TYPE3_PROTECTION:
4001 host_prot = SHOST_DIF_TYPE3_PROTECTION;
4002 if (scsi_debug_dix)
4003 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
4004 break;
4005
4006 default:
4007 if (scsi_debug_dix)
4008 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
4009 break;
4010 }
4011
4012 scsi_host_set_prot(hpnt, host_prot);
4013
4014 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
4015 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
4016 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
4017 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
4018 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
4019 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
4020 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
4021 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
4022
4023 if (scsi_debug_guard == 1)
4024 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
4025 else
4026 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
4027
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 error = scsi_add_host(hpnt, &sdbg_host->dev);
4029 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004030 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 error = -ENODEV;
4032 scsi_host_put(hpnt);
4033 } else
4034 scsi_scan_host(hpnt);
4035
4036
4037 return error;
4038}
4039
4040static int sdebug_driver_remove(struct device * dev)
4041{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004043 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
4045 sdbg_host = to_sdebug_host(dev);
4046
4047 if (!sdbg_host) {
4048 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07004049 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 return -ENODEV;
4051 }
4052
4053 scsi_remove_host(sdbg_host->shost);
4054
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09004055 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
4056 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 list_del(&sdbg_devinfo->dev_list);
4058 kfree(sdbg_devinfo);
4059 }
4060
4061 scsi_host_put(sdbg_host->shost);
4062 return 0;
4063}
4064
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004065static int pseudo_lld_bus_match(struct device *dev,
4066 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004068 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004070
4071static struct bus_type pseudo_lld_bus = {
4072 .name = "pseudo",
4073 .match = pseudo_lld_bus_match,
4074 .probe = sdebug_driver_probe,
4075 .remove = sdebug_driver_remove,
4076};