blob: c4103bef41b59cc8988be725fa74822bba9e5d5d [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 *
15 * For documentation see http://www.torque.net/sg/sdebug26.html
16 *
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>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/genhd.h>
36#include <linux/fs.h>
37#include <linux/init.h>
38#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/vmalloc.h>
40#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020041#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050043#include <linux/crc-t10dif.h>
44
45#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090046
47#include <scsi/scsi.h>
48#include <scsi/scsi_cmnd.h>
49#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <scsi/scsi_host.h>
51#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090052#include <scsi/scsi_eh.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040053#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Martin K. Petersenc6a44282009-01-04 03:08:19 -050055#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050058#define SCSI_DEBUG_VERSION "1.81"
59static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050061/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040062#define NO_ADDITIONAL_SENSE 0x0
63#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040065#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#define INVALID_OPCODE 0x20
67#define ADDR_OUT_OF_RANGE 0x21
Martin K. Petersen395cef02009-09-18 17:33:03 -040068#define INVALID_COMMAND_OPCODE 0x20
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define POWERON_RESET 0x29
72#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050073#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040074#define THRESHOLD_EXCEEDED 0x5d
75#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050077/* Additional Sense Code Qualifier (ASCQ) */
78#define ACK_NAK_TO 0x3
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
81
82/* Default values for driver parameters */
83#define DEF_NUM_HOST 1
84#define DEF_NUM_TGTS 1
85#define DEF_MAX_LUNS 1
86/* With these defaults, this driver will make 1 host with 1 target
87 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
88 */
89#define DEF_DELAY 1
90#define DEF_DEV_SIZE_MB 8
91#define DEF_EVERY_NTH 0
92#define DEF_NUM_PARTS 0
93#define DEF_OPTS 0
94#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
95#define DEF_PTYPE 0
96#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040097#define DEF_NO_LUN_0 0
98#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040099#define DEF_FAKE_RW 0
100#define DEF_VPD_USE_HOSTNO 1
Martin K. Petersen597136a2008-06-05 00:12:59 -0400101#define DEF_SECTOR_SIZE 512
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500102#define DEF_DIX 0
103#define DEF_DIF 0
104#define DEF_GUARD 0
105#define DEF_ATO 1
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400106#define DEF_PHYSBLK_EXP 0
107#define DEF_LOWEST_ALIGNED 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
109/* bit mask values for scsi_debug_opts */
110#define SCSI_DEBUG_OPT_NOISE 1
111#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
112#define SCSI_DEBUG_OPT_TIMEOUT 4
113#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500114#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500115#define SCSI_DEBUG_OPT_DIF_ERR 32
116#define SCSI_DEBUG_OPT_DIX_ERR 64
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/* When "every_nth" > 0 then modulo "every_nth" commands:
118 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
119 * - a RECOVERED_ERROR is simulated on successful read and write
120 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500121 * - a TRANSPORT_ERROR is simulated on successful read and write
122 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 *
124 * When "every_nth" < 0 then after "- every_nth" commands:
125 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
126 * - a RECOVERED_ERROR is simulated on successful read and write
127 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500128 * - a TRANSPORT_ERROR is simulated on successful read and write
129 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 * This will continue until some other action occurs (e.g. the user
131 * writing a new value (other than -1 or 1) to every_nth via sysfs).
132 */
133
134/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
135 * sector on read commands: */
136#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
137
138/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
139 * or "peripheral device" addressing (value 0) */
140#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400141#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143static int scsi_debug_add_host = DEF_NUM_HOST;
144static int scsi_debug_delay = DEF_DELAY;
145static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
146static int scsi_debug_every_nth = DEF_EVERY_NTH;
147static int scsi_debug_max_luns = DEF_MAX_LUNS;
148static int scsi_debug_num_parts = DEF_NUM_PARTS;
149static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
150static int scsi_debug_opts = DEF_OPTS;
151static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
152static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
153static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400154static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
155static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400156static int scsi_debug_fake_rw = DEF_FAKE_RW;
157static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400158static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500159static int scsi_debug_dix = DEF_DIX;
160static int scsi_debug_dif = DEF_DIF;
161static int scsi_debug_guard = DEF_GUARD;
162static int scsi_debug_ato = DEF_ATO;
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400163static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
164static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166static int scsi_debug_cmnd_count = 0;
167
168#define DEV_READONLY(TGT) (0)
169#define DEV_REMOVEABLE(TGT) (0)
170
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400171static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static sector_t sdebug_capacity; /* in sectors */
173
174/* old BIOS stuff, kernel may get rid of them but some mode sense pages
175 may still need them */
176static int sdebug_heads; /* heads per disk */
177static int sdebug_cylinders_per; /* cylinders per surface */
178static int sdebug_sectors_per; /* sectors per cylinder */
179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180#define SDEBUG_MAX_PARTS 4
181
182#define SDEBUG_SENSE_LEN 32
183
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900184#define SCSI_DEBUG_CANQUEUE 255
Martin K. Petersen395cef02009-09-18 17:33:03 -0400185#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187struct sdebug_dev_info {
188 struct list_head dev_list;
189 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
190 unsigned int channel;
191 unsigned int target;
192 unsigned int lun;
193 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400194 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400196 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 char used;
198};
199
200struct sdebug_host_info {
201 struct list_head host_list;
202 struct Scsi_Host *shost;
203 struct device dev;
204 struct list_head dev_info_list;
205};
206
207#define to_sdebug_host(d) \
208 container_of(d, struct sdebug_host_info, dev)
209
210static LIST_HEAD(sdebug_host_list);
211static DEFINE_SPINLOCK(sdebug_host_list_lock);
212
213typedef void (* done_funct_t) (struct scsi_cmnd *);
214
215struct sdebug_queued_cmd {
216 int in_use;
217 struct timer_list cmnd_timer;
218 done_funct_t done_funct;
219 struct scsi_cmnd * a_cmnd;
220 int scsi_result;
221};
222static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224static unsigned char * fake_storep; /* ramdisk storage */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500225static unsigned char *dif_storep; /* protection info */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
227static int num_aborts = 0;
228static int num_dev_resets = 0;
229static int num_bus_resets = 0;
230static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500231static int dix_writes;
232static int dix_reads;
233static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235static DEFINE_SPINLOCK(queued_arr_lock);
236static DEFINE_RWLOCK(atomic_rw);
237
238static char sdebug_proc_name[] = "scsi_debug";
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240static struct bus_type pseudo_lld_bus;
241
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500242static inline sector_t dif_offset(sector_t sector)
243{
244 return sector << 3;
245}
246
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247static struct device_driver sdebug_driverfs_driver = {
248 .name = sdebug_proc_name,
249 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250};
251
252static const int check_condition_result =
253 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
254
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500255static const int illegal_condition_result =
256 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
257
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400258static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
259 0, 0, 0x2, 0x4b};
260static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
261 0, 0, 0x0, 0x0};
262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263static int sdebug_add_adapter(void);
264static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900266static void sdebug_max_tgts_luns(void)
267{
268 struct sdebug_host_info *sdbg_host;
269 struct Scsi_Host *hpnt;
270
271 spin_lock(&sdebug_host_list_lock);
272 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
273 hpnt = sdbg_host->shost;
274 if ((hpnt->this_id >= 0) &&
275 (scsi_debug_num_tgts > hpnt->this_id))
276 hpnt->max_id = scsi_debug_num_tgts + 1;
277 else
278 hpnt->max_id = scsi_debug_num_tgts;
279 /* scsi_debug_max_luns; */
280 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
281 }
282 spin_unlock(&sdebug_host_list_lock);
283}
284
285static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
286 int asc, int asq)
287{
288 unsigned char *sbuff;
289
290 sbuff = devip->sense_buff;
291 memset(sbuff, 0, SDEBUG_SENSE_LEN);
292
293 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
294
295 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
296 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
297 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
298}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900300static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400301 unsigned long long *lba, unsigned int *num,
302 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900303{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400304 *ei_lba = 0;
305
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900306 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400307 case VARIABLE_LENGTH_CMD:
308 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
309 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
310 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
311 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
312
313 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
314 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
315
316 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
317 (u32)cmd[28] << 24;
318 break;
319
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900320 case WRITE_16:
321 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900322 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
323 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
324 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
325 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
326
327 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
328 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900329 break;
330 case WRITE_12:
331 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900332 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
333 (u32)cmd[2] << 24;
334
335 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
336 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900337 break;
338 case WRITE_10:
339 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900340 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900341 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
342 (u32)cmd[2] << 24;
343
344 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900345 break;
346 case WRITE_6:
347 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900348 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
349 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900350 *num = (0 == cmd[4]) ? 256 : cmd[4];
351 break;
352 default:
353 break;
354 }
355}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
358{
359 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
360 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
361 }
362 return -EINVAL;
363 /* return -ENOTTY; // correct return but upsets fdisk */
364}
365
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400366static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
367 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 if (devip->reset) {
370 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
371 printk(KERN_INFO "scsi_debug: Reporting Unit "
372 "attention: power on reset\n");
373 devip->reset = 0;
374 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
375 return check_condition_result;
376 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400377 if ((0 == reset_only) && devip->stopped) {
378 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
379 printk(KERN_INFO "scsi_debug: Reporting Not "
380 "ready: initializing command required\n");
381 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
382 0x2);
383 return check_condition_result;
384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 return 0;
386}
387
388/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900389static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 int arr_len)
391{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900392 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900393 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900395 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900397 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900399
400 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
401 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900402 if (sdb->resid)
403 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400404 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900405 sdb->resid = scsi_bufflen(scp) - act_len;
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 return 0;
408}
409
410/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900411static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
412 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900414 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900416 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900418
419 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420}
421
422
423static const char * inq_vendor_id = "Linux ";
424static const char * inq_product_id = "scsi_debug ";
425static const char * inq_product_rev = "0004";
426
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200427static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
428 int target_dev_id, int dev_id_num,
429 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400430 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400432 int num, port_a;
433 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400435 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 /* T10 vendor identifier field format (faked) */
437 arr[0] = 0x2; /* ASCII */
438 arr[1] = 0x1;
439 arr[2] = 0x0;
440 memcpy(&arr[4], inq_vendor_id, 8);
441 memcpy(&arr[12], inq_product_id, 16);
442 memcpy(&arr[28], dev_id_str, dev_id_str_len);
443 num = 8 + 16 + dev_id_str_len;
444 arr[3] = num;
445 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400446 if (dev_id_num >= 0) {
447 /* NAA-5, Logical unit identifier (binary) */
448 arr[num++] = 0x1; /* binary (not necessarily sas) */
449 arr[num++] = 0x3; /* PIV=0, lu, naa */
450 arr[num++] = 0x0;
451 arr[num++] = 0x8;
452 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
453 arr[num++] = 0x33;
454 arr[num++] = 0x33;
455 arr[num++] = 0x30;
456 arr[num++] = (dev_id_num >> 24);
457 arr[num++] = (dev_id_num >> 16) & 0xff;
458 arr[num++] = (dev_id_num >> 8) & 0xff;
459 arr[num++] = dev_id_num & 0xff;
460 /* Target relative port number */
461 arr[num++] = 0x61; /* proto=sas, binary */
462 arr[num++] = 0x94; /* PIV=1, target port, rel port */
463 arr[num++] = 0x0; /* reserved */
464 arr[num++] = 0x4; /* length */
465 arr[num++] = 0x0; /* reserved */
466 arr[num++] = 0x0; /* reserved */
467 arr[num++] = 0x0;
468 arr[num++] = 0x1; /* relative port A */
469 }
470 /* NAA-5, Target port identifier */
471 arr[num++] = 0x61; /* proto=sas, binary */
472 arr[num++] = 0x93; /* piv=1, target port, naa */
473 arr[num++] = 0x0;
474 arr[num++] = 0x8;
475 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
476 arr[num++] = 0x22;
477 arr[num++] = 0x22;
478 arr[num++] = 0x20;
479 arr[num++] = (port_a >> 24);
480 arr[num++] = (port_a >> 16) & 0xff;
481 arr[num++] = (port_a >> 8) & 0xff;
482 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200483 /* NAA-5, Target port group identifier */
484 arr[num++] = 0x61; /* proto=sas, binary */
485 arr[num++] = 0x95; /* piv=1, target port group id */
486 arr[num++] = 0x0;
487 arr[num++] = 0x4;
488 arr[num++] = 0;
489 arr[num++] = 0;
490 arr[num++] = (port_group_id >> 8) & 0xff;
491 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400492 /* NAA-5, Target device identifier */
493 arr[num++] = 0x61; /* proto=sas, binary */
494 arr[num++] = 0xa3; /* piv=1, target device, naa */
495 arr[num++] = 0x0;
496 arr[num++] = 0x8;
497 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
498 arr[num++] = 0x22;
499 arr[num++] = 0x22;
500 arr[num++] = 0x20;
501 arr[num++] = (target_dev_id >> 24);
502 arr[num++] = (target_dev_id >> 16) & 0xff;
503 arr[num++] = (target_dev_id >> 8) & 0xff;
504 arr[num++] = target_dev_id & 0xff;
505 /* SCSI name string: Target device identifier */
506 arr[num++] = 0x63; /* proto=sas, UTF-8 */
507 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
508 arr[num++] = 0x0;
509 arr[num++] = 24;
510 memcpy(arr + num, "naa.52222220", 12);
511 num += 12;
512 snprintf(b, sizeof(b), "%08X", target_dev_id);
513 memcpy(arr + num, b, 8);
514 num += 8;
515 memset(arr + num, 0, 4);
516 num += 4;
517 return num;
518}
519
520
521static unsigned char vpd84_data[] = {
522/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
523 0x22,0x22,0x22,0x0,0xbb,0x1,
524 0x22,0x22,0x22,0x0,0xbb,0x2,
525};
526
527static int inquiry_evpd_84(unsigned char * arr)
528{
529 memcpy(arr, vpd84_data, sizeof(vpd84_data));
530 return sizeof(vpd84_data);
531}
532
533static int inquiry_evpd_85(unsigned char * arr)
534{
535 int num = 0;
536 const char * na1 = "https://www.kernel.org/config";
537 const char * na2 = "http://www.kernel.org/log";
538 int plen, olen;
539
540 arr[num++] = 0x1; /* lu, storage config */
541 arr[num++] = 0x0; /* reserved */
542 arr[num++] = 0x0;
543 olen = strlen(na1);
544 plen = olen + 1;
545 if (plen % 4)
546 plen = ((plen / 4) + 1) * 4;
547 arr[num++] = plen; /* length, null termianted, padded */
548 memcpy(arr + num, na1, olen);
549 memset(arr + num + olen, 0, plen - olen);
550 num += plen;
551
552 arr[num++] = 0x4; /* lu, logging */
553 arr[num++] = 0x0; /* reserved */
554 arr[num++] = 0x0;
555 olen = strlen(na2);
556 plen = olen + 1;
557 if (plen % 4)
558 plen = ((plen / 4) + 1) * 4;
559 arr[num++] = plen; /* length, null terminated, padded */
560 memcpy(arr + num, na2, olen);
561 memset(arr + num + olen, 0, plen - olen);
562 num += plen;
563
564 return num;
565}
566
567/* SCSI ports VPD page */
568static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
569{
570 int num = 0;
571 int port_a, port_b;
572
573 port_a = target_dev_id + 1;
574 port_b = port_a + 1;
575 arr[num++] = 0x0; /* reserved */
576 arr[num++] = 0x0; /* reserved */
577 arr[num++] = 0x0;
578 arr[num++] = 0x1; /* relative port 1 (primary) */
579 memset(arr + num, 0, 6);
580 num += 6;
581 arr[num++] = 0x0;
582 arr[num++] = 12; /* length tp descriptor */
583 /* naa-5 target port identifier (A) */
584 arr[num++] = 0x61; /* proto=sas, binary */
585 arr[num++] = 0x93; /* PIV=1, target port, NAA */
586 arr[num++] = 0x0; /* reserved */
587 arr[num++] = 0x8; /* length */
588 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
589 arr[num++] = 0x22;
590 arr[num++] = 0x22;
591 arr[num++] = 0x20;
592 arr[num++] = (port_a >> 24);
593 arr[num++] = (port_a >> 16) & 0xff;
594 arr[num++] = (port_a >> 8) & 0xff;
595 arr[num++] = port_a & 0xff;
596
597 arr[num++] = 0x0; /* reserved */
598 arr[num++] = 0x0; /* reserved */
599 arr[num++] = 0x0;
600 arr[num++] = 0x2; /* relative port 2 (secondary) */
601 memset(arr + num, 0, 6);
602 num += 6;
603 arr[num++] = 0x0;
604 arr[num++] = 12; /* length tp descriptor */
605 /* naa-5 target port identifier (B) */
606 arr[num++] = 0x61; /* proto=sas, binary */
607 arr[num++] = 0x93; /* PIV=1, target port, NAA */
608 arr[num++] = 0x0; /* reserved */
609 arr[num++] = 0x8; /* length */
610 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
611 arr[num++] = 0x22;
612 arr[num++] = 0x22;
613 arr[num++] = 0x20;
614 arr[num++] = (port_b >> 24);
615 arr[num++] = (port_b >> 16) & 0xff;
616 arr[num++] = (port_b >> 8) & 0xff;
617 arr[num++] = port_b & 0xff;
618
619 return num;
620}
621
622
623static unsigned char vpd89_data[] = {
624/* from 4th byte */ 0,0,0,0,
625'l','i','n','u','x',' ',' ',' ',
626'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
627'1','2','3','4',
6280x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6290xec,0,0,0,
6300x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6310,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6320x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6330x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6340x53,0x41,
6350x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6360x20,0x20,
6370x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6380x10,0x80,
6390,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6400x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6410x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6420,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6430x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6440x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6450,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6470,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6490x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6500,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6510xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6520,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6530,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6540,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6550,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6570,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6590,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6610,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6620,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6640,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
665};
666
667static int inquiry_evpd_89(unsigned char * arr)
668{
669 memcpy(arr, vpd89_data, sizeof(vpd89_data));
670 return sizeof(vpd89_data);
671}
672
673
674static unsigned char vpdb0_data[] = {
675 /* from 4th byte */ 0,0,0,4,
676 0,0,0x4,0,
677 0,0,0,64,
678};
679
680static int inquiry_evpd_b0(unsigned char * arr)
681{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400682 unsigned int gran;
683
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400684 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400685 gran = 1 << scsi_debug_physblk_exp;
686 arr[2] = (gran >> 8) & 0xff;
687 arr[3] = gran & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400688 if (sdebug_store_sectors > 0x400) {
689 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
690 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
691 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
692 arr[7] = sdebug_store_sectors & 0xff;
693 }
694 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695}
696
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600697static int inquiry_evpd_b1(unsigned char *arr)
698{
699 memset(arr, 0, 0x3c);
700 arr[0] = 0;
701 arr[1] = 1;
702
703 return 0x3c;
704}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400707#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709static int resp_inquiry(struct scsi_cmnd * scp, int target,
710 struct sdebug_dev_info * devip)
711{
712 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200713 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200715 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500718 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
719 if (! arr)
720 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400721 if (devip->wlun)
722 pq_pdt = 0x1e; /* present, wlun */
723 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
724 pq_pdt = 0x7f; /* not present, no device type */
725 else
726 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 arr[0] = pq_pdt;
728 if (0x2 & cmd[1]) { /* CMDDT bit set */
729 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
730 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200731 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 return check_condition_result;
733 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200734 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400735 char lu_id_str[6];
736 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200738 port_group_id = (((host_no + 1) & 0x7f) << 8) +
739 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400740 if (0 == scsi_debug_vpd_use_hostno)
741 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400742 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
743 (devip->target * 1000) + devip->lun);
744 target_dev_id = ((host_no + 1) * 2000) +
745 (devip->target * 1000) - 3;
746 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400748 arr[1] = cmd[2]; /*sanity */
749 n = 4;
750 arr[n++] = 0x0; /* this page */
751 arr[n++] = 0x80; /* unit serial number */
752 arr[n++] = 0x83; /* device identification */
753 arr[n++] = 0x84; /* software interface ident. */
754 arr[n++] = 0x85; /* management network addresses */
755 arr[n++] = 0x86; /* extended inquiry */
756 arr[n++] = 0x87; /* mode page policy */
757 arr[n++] = 0x88; /* SCSI ports */
758 arr[n++] = 0x89; /* ATA information */
759 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600760 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400761 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400763 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400765 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400767 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200768 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
769 target_dev_id, lu_id_num,
770 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400771 } else if (0x84 == cmd[2]) { /* Software interface ident. */
772 arr[1] = cmd[2]; /*sanity */
773 arr[3] = inquiry_evpd_84(&arr[4]);
774 } else if (0x85 == cmd[2]) { /* Management network addresses */
775 arr[1] = cmd[2]; /*sanity */
776 arr[3] = inquiry_evpd_85(&arr[4]);
777 } else if (0x86 == cmd[2]) { /* extended inquiry */
778 arr[1] = cmd[2]; /*sanity */
779 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500780 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
781 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
782 else if (scsi_debug_dif)
783 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
784 else
785 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400786 arr[5] = 0x7; /* head of q, ordered + simple q's */
787 } else if (0x87 == cmd[2]) { /* mode page policy */
788 arr[1] = cmd[2]; /*sanity */
789 arr[3] = 0x8; /* number of following entries */
790 arr[4] = 0x2; /* disconnect-reconnect mp */
791 arr[6] = 0x80; /* mlus, shared */
792 arr[8] = 0x18; /* protocol specific lu */
793 arr[10] = 0x82; /* mlus, per initiator port */
794 } else if (0x88 == cmd[2]) { /* SCSI Ports */
795 arr[1] = cmd[2]; /*sanity */
796 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
797 } else if (0x89 == cmd[2]) { /* ATA information */
798 arr[1] = cmd[2]; /*sanity */
799 n = inquiry_evpd_89(&arr[4]);
800 arr[2] = (n >> 8);
801 arr[3] = (n & 0xff);
802 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
803 arr[1] = cmd[2]; /*sanity */
804 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600805 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
806 arr[1] = cmd[2]; /*sanity */
807 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 } else {
809 /* Illegal request, invalid field in cdb */
810 mk_sense_buffer(devip, ILLEGAL_REQUEST,
811 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200812 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 return check_condition_result;
814 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400815 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200816 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400817 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200818 kfree(arr);
819 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 }
821 /* drops through here for a standard inquiry */
822 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
823 arr[2] = scsi_debug_scsi_level;
824 arr[3] = 2; /* response_data_format==2 */
825 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500826 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200827 if (0 == scsi_debug_vpd_use_hostno)
828 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400829 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400831 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 memcpy(&arr[8], inq_vendor_id, 8);
833 memcpy(&arr[16], inq_product_id, 16);
834 memcpy(&arr[32], inq_product_rev, 4);
835 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400836 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
837 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
838 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400840 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400842 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400844 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200845 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200847 kfree(arr);
848 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849}
850
851static int resp_requests(struct scsi_cmnd * scp,
852 struct sdebug_dev_info * devip)
853{
854 unsigned char * sbuff;
855 unsigned char *cmd = (unsigned char *)scp->cmnd;
856 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400857 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 int len = 18;
859
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400860 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400862 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
863 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400865 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
866 if (want_dsense) {
867 arr[0] = 0x72;
868 arr[1] = 0x0; /* NO_SENSE in sense_key */
869 arr[2] = THRESHOLD_EXCEEDED;
870 arr[3] = 0xff; /* TEST set and MRIE==6 */
871 } else {
872 arr[0] = 0x70;
873 arr[2] = 0x0; /* NO_SENSE in sense_key */
874 arr[7] = 0xa; /* 18 byte sense buffer */
875 arr[12] = THRESHOLD_EXCEEDED;
876 arr[13] = 0xff; /* TEST set and MRIE==6 */
877 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400878 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400880 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
881 /* DESC bit set and sense_buff in fixed format */
882 memset(arr, 0, sizeof(arr));
883 arr[0] = 0x72;
884 arr[1] = sbuff[2]; /* sense key */
885 arr[2] = sbuff[12]; /* asc */
886 arr[3] = sbuff[13]; /* ascq */
887 len = 8;
888 }
889 }
890 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 return fill_from_dev_buffer(scp, arr, len);
892}
893
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400894static int resp_start_stop(struct scsi_cmnd * scp,
895 struct sdebug_dev_info * devip)
896{
897 unsigned char *cmd = (unsigned char *)scp->cmnd;
898 int power_cond, errsts, start;
899
900 if ((errsts = check_readiness(scp, 1, devip)))
901 return errsts;
902 power_cond = (cmd[4] & 0xf0) >> 4;
903 if (power_cond) {
904 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
905 0);
906 return check_condition_result;
907 }
908 start = cmd[4] & 1;
909 if (start == devip->stopped)
910 devip->stopped = !start;
911 return 0;
912}
913
FUJITA Tomonori28898872008-03-30 00:59:55 +0900914static sector_t get_sdebug_capacity(void)
915{
916 if (scsi_debug_virtual_gb > 0)
FUJITA Tomonori73da9c12009-04-22 17:42:25 -0700917 return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
FUJITA Tomonori28898872008-03-30 00:59:55 +0900918 else
919 return sdebug_store_sectors;
920}
921
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922#define SDEBUG_READCAP_ARR_SZ 8
923static int resp_readcap(struct scsi_cmnd * scp,
924 struct sdebug_dev_info * devip)
925{
926 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400927 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 int errsts;
929
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400930 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400932 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900933 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400935 if (sdebug_capacity < 0xffffffff) {
936 capac = (unsigned int)sdebug_capacity - 1;
937 arr[0] = (capac >> 24);
938 arr[1] = (capac >> 16) & 0xff;
939 arr[2] = (capac >> 8) & 0xff;
940 arr[3] = capac & 0xff;
941 } else {
942 arr[0] = 0xff;
943 arr[1] = 0xff;
944 arr[2] = 0xff;
945 arr[3] = 0xff;
946 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400947 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
948 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
950}
951
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400952#define SDEBUG_READCAP16_ARR_SZ 32
953static int resp_readcap16(struct scsi_cmnd * scp,
954 struct sdebug_dev_info * devip)
955{
956 unsigned char *cmd = (unsigned char *)scp->cmnd;
957 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
958 unsigned long long capac;
959 int errsts, k, alloc_len;
960
961 if ((errsts = check_readiness(scp, 1, devip)))
962 return errsts;
963 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
964 + cmd[13]);
965 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900966 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400967 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
968 capac = sdebug_capacity - 1;
969 for (k = 0; k < 8; ++k, capac >>= 8)
970 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400971 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
972 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
973 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
974 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400975 arr[13] = scsi_debug_physblk_exp & 0xf;
976 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
977 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500978
979 if (scsi_debug_dif) {
980 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
981 arr[12] |= 1; /* PROT_EN */
982 }
983
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400984 return fill_from_dev_buffer(scp, arr,
985 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
986}
987
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200988#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
989
990static int resp_report_tgtpgs(struct scsi_cmnd * scp,
991 struct sdebug_dev_info * devip)
992{
993 unsigned char *cmd = (unsigned char *)scp->cmnd;
994 unsigned char * arr;
995 int host_no = devip->sdbg_host->shost->host_no;
996 int n, ret, alen, rlen;
997 int port_group_a, port_group_b, port_a, port_b;
998
999 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1000 + cmd[9]);
1001
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001002 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1003 if (! arr)
1004 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001005 /*
1006 * EVPD page 0x88 states we have two ports, one
1007 * real and a fake port with no device connected.
1008 * So we create two port groups with one port each
1009 * and set the group with port B to unavailable.
1010 */
1011 port_a = 0x1; /* relative port A */
1012 port_b = 0x2; /* relative port B */
1013 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1014 (devip->channel & 0x7f);
1015 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1016 (devip->channel & 0x7f) + 0x80;
1017
1018 /*
1019 * The asymmetric access state is cycled according to the host_id.
1020 */
1021 n = 4;
1022 if (0 == scsi_debug_vpd_use_hostno) {
1023 arr[n++] = host_no % 3; /* Asymm access state */
1024 arr[n++] = 0x0F; /* claim: all states are supported */
1025 } else {
1026 arr[n++] = 0x0; /* Active/Optimized path */
1027 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1028 }
1029 arr[n++] = (port_group_a >> 8) & 0xff;
1030 arr[n++] = port_group_a & 0xff;
1031 arr[n++] = 0; /* Reserved */
1032 arr[n++] = 0; /* Status code */
1033 arr[n++] = 0; /* Vendor unique */
1034 arr[n++] = 0x1; /* One port per group */
1035 arr[n++] = 0; /* Reserved */
1036 arr[n++] = 0; /* Reserved */
1037 arr[n++] = (port_a >> 8) & 0xff;
1038 arr[n++] = port_a & 0xff;
1039 arr[n++] = 3; /* Port unavailable */
1040 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1041 arr[n++] = (port_group_b >> 8) & 0xff;
1042 arr[n++] = port_group_b & 0xff;
1043 arr[n++] = 0; /* Reserved */
1044 arr[n++] = 0; /* Status code */
1045 arr[n++] = 0; /* Vendor unique */
1046 arr[n++] = 0x1; /* One port per group */
1047 arr[n++] = 0; /* Reserved */
1048 arr[n++] = 0; /* Reserved */
1049 arr[n++] = (port_b >> 8) & 0xff;
1050 arr[n++] = port_b & 0xff;
1051
1052 rlen = n - 4;
1053 arr[0] = (rlen >> 24) & 0xff;
1054 arr[1] = (rlen >> 16) & 0xff;
1055 arr[2] = (rlen >> 8) & 0xff;
1056 arr[3] = rlen & 0xff;
1057
1058 /*
1059 * Return the smallest value of either
1060 * - The allocated length
1061 * - The constructed command length
1062 * - The maximum array size
1063 */
1064 rlen = min(alen,n);
1065 ret = fill_from_dev_buffer(scp, arr,
1066 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1067 kfree(arr);
1068 return ret;
1069}
1070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071/* <<Following mode page info copied from ST318451LW>> */
1072
1073static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1074{ /* Read-Write Error Recovery page for mode_sense */
1075 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1076 5, 0, 0xff, 0xff};
1077
1078 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1079 if (1 == pcontrol)
1080 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1081 return sizeof(err_recov_pg);
1082}
1083
1084static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1085{ /* Disconnect-Reconnect page for mode_sense */
1086 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1087 0, 0, 0, 0, 0, 0, 0, 0};
1088
1089 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1090 if (1 == pcontrol)
1091 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1092 return sizeof(disconnect_pg);
1093}
1094
1095static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1096{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001097 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1098 0, 0, 0, 0, 0, 0, 0, 0,
1099 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
Martin K. Petersen597136a2008-06-05 00:12:59 -04001101 memcpy(p, format_pg, sizeof(format_pg));
1102 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1103 p[11] = sdebug_sectors_per & 0xff;
1104 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1105 p[13] = scsi_debug_sector_size & 0xff;
1106 if (DEV_REMOVEABLE(target))
1107 p[20] |= 0x20; /* should agree with INQUIRY */
1108 if (1 == pcontrol)
1109 memset(p + 2, 0, sizeof(format_pg) - 2);
1110 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111}
1112
1113static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1114{ /* Caching page for mode_sense */
1115 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1116 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1117
1118 memcpy(p, caching_pg, sizeof(caching_pg));
1119 if (1 == pcontrol)
1120 memset(p + 2, 0, sizeof(caching_pg) - 2);
1121 return sizeof(caching_pg);
1122}
1123
1124static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1125{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001126 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1127 0, 0, 0, 0};
1128 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 0, 0, 0x2, 0x4b};
1130
1131 if (scsi_debug_dsense)
1132 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001133 else
1134 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001135
1136 if (scsi_debug_ato)
1137 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1140 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001141 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1142 else if (2 == pcontrol)
1143 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return sizeof(ctrl_m_pg);
1145}
1146
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001147
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1149{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001150 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1151 0, 0, 0x0, 0x0};
1152 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1153 0, 0, 0x0, 0x0};
1154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1156 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001157 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1158 else if (2 == pcontrol)
1159 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 return sizeof(iec_m_pg);
1161}
1162
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001163static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1164{ /* SAS SSP mode page - short format for mode_sense */
1165 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1166 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1167
1168 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1169 if (1 == pcontrol)
1170 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1171 return sizeof(sas_sf_m_pg);
1172}
1173
1174
1175static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1176 int target_dev_id)
1177{ /* SAS phy control and discover mode page for mode_sense */
1178 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1179 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1180 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1181 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1182 0x2, 0, 0, 0, 0, 0, 0, 0,
1183 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1184 0, 0, 0, 0, 0, 0, 0, 0,
1185 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1186 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1187 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1188 0x3, 0, 0, 0, 0, 0, 0, 0,
1189 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1190 0, 0, 0, 0, 0, 0, 0, 0,
1191 };
1192 int port_a, port_b;
1193
1194 port_a = target_dev_id + 1;
1195 port_b = port_a + 1;
1196 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1197 p[20] = (port_a >> 24);
1198 p[21] = (port_a >> 16) & 0xff;
1199 p[22] = (port_a >> 8) & 0xff;
1200 p[23] = port_a & 0xff;
1201 p[48 + 20] = (port_b >> 24);
1202 p[48 + 21] = (port_b >> 16) & 0xff;
1203 p[48 + 22] = (port_b >> 8) & 0xff;
1204 p[48 + 23] = port_b & 0xff;
1205 if (1 == pcontrol)
1206 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1207 return sizeof(sas_pcd_m_pg);
1208}
1209
1210static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1211{ /* SAS SSP shared protocol specific port mode subpage */
1212 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1213 0, 0, 0, 0, 0, 0, 0, 0,
1214 };
1215
1216 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1217 if (1 == pcontrol)
1218 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1219 return sizeof(sas_sha_m_pg);
1220}
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222#define SDEBUG_MAX_MSENSE_SZ 256
1223
1224static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1225 struct sdebug_dev_info * devip)
1226{
Douglas Gilbert23183912006-09-16 20:30:47 -04001227 unsigned char dbd, llbaa;
1228 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001230 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 unsigned char * ap;
1232 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1233 unsigned char *cmd = (unsigned char *)scp->cmnd;
1234
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001235 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001237 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 pcontrol = (cmd[2] & 0xc0) >> 6;
1239 pcode = cmd[2] & 0x3f;
1240 subpcode = cmd[3];
1241 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001242 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1243 if ((0 == scsi_debug_ptype) && (0 == dbd))
1244 bd_len = llbaa ? 16 : 8;
1245 else
1246 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1248 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1249 if (0x3 == pcontrol) { /* Saving values not supported */
1250 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1251 0);
1252 return check_condition_result;
1253 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001254 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1255 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001256 /* set DPOFUA bit for disks */
1257 if (0 == scsi_debug_ptype)
1258 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1259 else
1260 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 if (msense_6) {
1262 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001263 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 offset = 4;
1265 } else {
1266 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001267 if (16 == bd_len)
1268 arr[4] = 0x1; /* set LONGLBA bit */
1269 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 offset = 8;
1271 }
1272 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001273 if ((bd_len > 0) && (!sdebug_capacity))
1274 sdebug_capacity = get_sdebug_capacity();
1275
Douglas Gilbert23183912006-09-16 20:30:47 -04001276 if (8 == bd_len) {
1277 if (sdebug_capacity > 0xfffffffe) {
1278 ap[0] = 0xff;
1279 ap[1] = 0xff;
1280 ap[2] = 0xff;
1281 ap[3] = 0xff;
1282 } else {
1283 ap[0] = (sdebug_capacity >> 24) & 0xff;
1284 ap[1] = (sdebug_capacity >> 16) & 0xff;
1285 ap[2] = (sdebug_capacity >> 8) & 0xff;
1286 ap[3] = sdebug_capacity & 0xff;
1287 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001288 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1289 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001290 offset += bd_len;
1291 ap = arr + offset;
1292 } else if (16 == bd_len) {
1293 unsigned long long capac = sdebug_capacity;
1294
1295 for (k = 0; k < 8; ++k, capac >>= 8)
1296 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001297 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1298 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1299 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1300 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001301 offset += bd_len;
1302 ap = arr + offset;
1303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001305 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1306 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1308 0);
1309 return check_condition_result;
1310 }
1311 switch (pcode) {
1312 case 0x1: /* Read-Write error recovery page, direct access */
1313 len = resp_err_recov_pg(ap, pcontrol, target);
1314 offset += len;
1315 break;
1316 case 0x2: /* Disconnect-Reconnect page, all devices */
1317 len = resp_disconnect_pg(ap, pcontrol, target);
1318 offset += len;
1319 break;
1320 case 0x3: /* Format device page, direct access */
1321 len = resp_format_pg(ap, pcontrol, target);
1322 offset += len;
1323 break;
1324 case 0x8: /* Caching page, direct access */
1325 len = resp_caching_pg(ap, pcontrol, target);
1326 offset += len;
1327 break;
1328 case 0xa: /* Control Mode page, all devices */
1329 len = resp_ctrl_m_pg(ap, pcontrol, target);
1330 offset += len;
1331 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001332 case 0x19: /* if spc==1 then sas phy, control+discover */
1333 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1334 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1335 INVALID_FIELD_IN_CDB, 0);
1336 return check_condition_result;
1337 }
1338 len = 0;
1339 if ((0x0 == subpcode) || (0xff == subpcode))
1340 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1341 if ((0x1 == subpcode) || (0xff == subpcode))
1342 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1343 target_dev_id);
1344 if ((0x2 == subpcode) || (0xff == subpcode))
1345 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1346 offset += len;
1347 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 case 0x1c: /* Informational Exceptions Mode page, all devices */
1349 len = resp_iec_m_pg(ap, pcontrol, target);
1350 offset += len;
1351 break;
1352 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001353 if ((0 == subpcode) || (0xff == subpcode)) {
1354 len = resp_err_recov_pg(ap, pcontrol, target);
1355 len += resp_disconnect_pg(ap + len, pcontrol, target);
1356 len += resp_format_pg(ap + len, pcontrol, target);
1357 len += resp_caching_pg(ap + len, pcontrol, target);
1358 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1359 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1360 if (0xff == subpcode) {
1361 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1362 target, target_dev_id);
1363 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1364 }
1365 len += resp_iec_m_pg(ap + len, pcontrol, target);
1366 } else {
1367 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1368 INVALID_FIELD_IN_CDB, 0);
1369 return check_condition_result;
1370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 offset += len;
1372 break;
1373 default:
1374 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1375 0);
1376 return check_condition_result;
1377 }
1378 if (msense_6)
1379 arr[0] = offset - 1;
1380 else {
1381 arr[0] = ((offset - 2) >> 8) & 0xff;
1382 arr[1] = (offset - 2) & 0xff;
1383 }
1384 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1385}
1386
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001387#define SDEBUG_MAX_MSELECT_SZ 512
1388
1389static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1390 struct sdebug_dev_info * devip)
1391{
1392 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1393 int param_len, res, errsts, mpage;
1394 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1395 unsigned char *cmd = (unsigned char *)scp->cmnd;
1396
1397 if ((errsts = check_readiness(scp, 1, devip)))
1398 return errsts;
1399 memset(arr, 0, sizeof(arr));
1400 pf = cmd[1] & 0x10;
1401 sp = cmd[1] & 0x1;
1402 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1403 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1404 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1405 INVALID_FIELD_IN_CDB, 0);
1406 return check_condition_result;
1407 }
1408 res = fetch_to_dev_buffer(scp, arr, param_len);
1409 if (-1 == res)
1410 return (DID_ERROR << 16);
1411 else if ((res < param_len) &&
1412 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1413 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1414 " IO sent=%d bytes\n", param_len, res);
1415 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1416 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001417 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001418 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1419 INVALID_FIELD_IN_PARAM_LIST, 0);
1420 return check_condition_result;
1421 }
1422 off = bd_len + (mselect6 ? 4 : 8);
1423 mpage = arr[off] & 0x3f;
1424 ps = !!(arr[off] & 0x80);
1425 if (ps) {
1426 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1427 INVALID_FIELD_IN_PARAM_LIST, 0);
1428 return check_condition_result;
1429 }
1430 spf = !!(arr[off] & 0x40);
1431 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1432 (arr[off + 1] + 2);
1433 if ((pg_len + off) > param_len) {
1434 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1435 PARAMETER_LIST_LENGTH_ERR, 0);
1436 return check_condition_result;
1437 }
1438 switch (mpage) {
1439 case 0xa: /* Control Mode page */
1440 if (ctrl_m_pg[1] == arr[off + 1]) {
1441 memcpy(ctrl_m_pg + 2, arr + off + 2,
1442 sizeof(ctrl_m_pg) - 2);
1443 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1444 return 0;
1445 }
1446 break;
1447 case 0x1c: /* Informational Exceptions Mode page */
1448 if (iec_m_pg[1] == arr[off + 1]) {
1449 memcpy(iec_m_pg + 2, arr + off + 2,
1450 sizeof(iec_m_pg) - 2);
1451 return 0;
1452 }
1453 break;
1454 default:
1455 break;
1456 }
1457 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1458 INVALID_FIELD_IN_PARAM_LIST, 0);
1459 return check_condition_result;
1460}
1461
1462static int resp_temp_l_pg(unsigned char * arr)
1463{
1464 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1465 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1466 };
1467
1468 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1469 return sizeof(temp_l_pg);
1470}
1471
1472static int resp_ie_l_pg(unsigned char * arr)
1473{
1474 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1475 };
1476
1477 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1478 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1479 arr[4] = THRESHOLD_EXCEEDED;
1480 arr[5] = 0xff;
1481 }
1482 return sizeof(ie_l_pg);
1483}
1484
1485#define SDEBUG_MAX_LSENSE_SZ 512
1486
1487static int resp_log_sense(struct scsi_cmnd * scp,
1488 struct sdebug_dev_info * devip)
1489{
Douglas Gilbert23183912006-09-16 20:30:47 -04001490 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001491 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1492 unsigned char *cmd = (unsigned char *)scp->cmnd;
1493
1494 if ((errsts = check_readiness(scp, 1, devip)))
1495 return errsts;
1496 memset(arr, 0, sizeof(arr));
1497 ppc = cmd[1] & 0x2;
1498 sp = cmd[1] & 0x1;
1499 if (ppc || sp) {
1500 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1501 INVALID_FIELD_IN_CDB, 0);
1502 return check_condition_result;
1503 }
1504 pcontrol = (cmd[2] & 0xc0) >> 6;
1505 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001506 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001507 alloc_len = (cmd[7] << 8) + cmd[8];
1508 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001509 if (0 == subpcode) {
1510 switch (pcode) {
1511 case 0x0: /* Supported log pages log page */
1512 n = 4;
1513 arr[n++] = 0x0; /* this page */
1514 arr[n++] = 0xd; /* Temperature */
1515 arr[n++] = 0x2f; /* Informational exceptions */
1516 arr[3] = n - 4;
1517 break;
1518 case 0xd: /* Temperature log page */
1519 arr[3] = resp_temp_l_pg(arr + 4);
1520 break;
1521 case 0x2f: /* Informational exceptions log page */
1522 arr[3] = resp_ie_l_pg(arr + 4);
1523 break;
1524 default:
1525 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1526 INVALID_FIELD_IN_CDB, 0);
1527 return check_condition_result;
1528 }
1529 } else if (0xff == subpcode) {
1530 arr[0] |= 0x40;
1531 arr[1] = subpcode;
1532 switch (pcode) {
1533 case 0x0: /* Supported log pages and subpages log page */
1534 n = 4;
1535 arr[n++] = 0x0;
1536 arr[n++] = 0x0; /* 0,0 page */
1537 arr[n++] = 0x0;
1538 arr[n++] = 0xff; /* this page */
1539 arr[n++] = 0xd;
1540 arr[n++] = 0x0; /* Temperature */
1541 arr[n++] = 0x2f;
1542 arr[n++] = 0x0; /* Informational exceptions */
1543 arr[3] = n - 4;
1544 break;
1545 case 0xd: /* Temperature subpages */
1546 n = 4;
1547 arr[n++] = 0xd;
1548 arr[n++] = 0x0; /* Temperature */
1549 arr[3] = n - 4;
1550 break;
1551 case 0x2f: /* Informational exceptions subpages */
1552 n = 4;
1553 arr[n++] = 0x2f;
1554 arr[n++] = 0x0; /* Informational exceptions */
1555 arr[3] = n - 4;
1556 break;
1557 default:
1558 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1559 INVALID_FIELD_IN_CDB, 0);
1560 return check_condition_result;
1561 }
1562 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001563 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1564 INVALID_FIELD_IN_CDB, 0);
1565 return check_condition_result;
1566 }
1567 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1568 return fill_from_dev_buffer(scp, arr,
1569 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1570}
1571
FUJITA Tomonori19789102008-03-30 00:59:56 +09001572static int check_device_access_params(struct sdebug_dev_info *devi,
1573 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001575 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001576 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 return check_condition_result;
1578 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001579 /* transfer length excessive (tie in to block limits VPD page) */
1580 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001581 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001582 return check_condition_result;
1583 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001584 return 0;
1585}
1586
1587static int do_device_access(struct scsi_cmnd *scmd,
1588 struct sdebug_dev_info *devi,
1589 unsigned long long lba, unsigned int num, int write)
1590{
1591 int ret;
1592 unsigned int block, rest = 0;
1593 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1594
1595 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1596
1597 block = do_div(lba, sdebug_store_sectors);
1598 if (block + num > sdebug_store_sectors)
1599 rest = block + num - sdebug_store_sectors;
1600
Martin K. Petersen597136a2008-06-05 00:12:59 -04001601 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1602 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001603 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001604 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001605
1606 return ret;
1607}
1608
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001609static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001610 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001611{
1612 unsigned int i, resid;
1613 struct scatterlist *psgl;
1614 struct sd_dif_tuple *sdt;
1615 sector_t sector;
1616 sector_t tmp_sec = start_sec;
1617 void *paddr;
1618
1619 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1620
1621 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1622
1623 for (i = 0 ; i < sectors ; i++) {
1624 u16 csum;
1625
1626 if (sdt[i].app_tag == 0xffff)
1627 continue;
1628
1629 sector = start_sec + i;
1630
1631 switch (scsi_debug_guard) {
1632 case 1:
1633 csum = ip_compute_csum(fake_storep +
1634 sector * scsi_debug_sector_size,
1635 scsi_debug_sector_size);
1636 break;
1637 case 0:
1638 csum = crc_t10dif(fake_storep +
1639 sector * scsi_debug_sector_size,
1640 scsi_debug_sector_size);
1641 csum = cpu_to_be16(csum);
1642 break;
1643 default:
1644 BUG();
1645 }
1646
1647 if (sdt[i].guard_tag != csum) {
1648 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1649 " rcvd 0x%04x, data 0x%04x\n", __func__,
1650 (unsigned long)sector,
1651 be16_to_cpu(sdt[i].guard_tag),
1652 be16_to_cpu(csum));
1653 dif_errors++;
1654 return 0x01;
1655 }
1656
Martin K. Petersen395cef02009-09-18 17:33:03 -04001657 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001658 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1659 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1660 __func__, (unsigned long)sector);
1661 dif_errors++;
1662 return 0x03;
1663 }
Martin K. Petersen395cef02009-09-18 17:33:03 -04001664
1665 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1666 be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1667 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1668 __func__, (unsigned long)sector);
1669 dif_errors++;
1670 return 0x03;
1671 }
1672
1673 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001674 }
1675
1676 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1677 sector = start_sec;
1678
1679 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1680 int len = min(psgl->length, resid);
1681
1682 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1683 memcpy(paddr, dif_storep + dif_offset(sector), len);
1684
1685 sector += len >> 3;
1686 if (sector >= sdebug_store_sectors) {
1687 /* Force wrap */
1688 tmp_sec = sector;
1689 sector = do_div(tmp_sec, sdebug_store_sectors);
1690 }
1691 resid -= len;
1692 kunmap_atomic(paddr, KM_IRQ0);
1693 }
1694
1695 dix_reads++;
1696
1697 return 0;
1698}
1699
FUJITA Tomonori19789102008-03-30 00:59:56 +09001700static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001701 unsigned int num, struct sdebug_dev_info *devip,
1702 u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001703{
1704 unsigned long iflags;
1705 int ret;
1706
1707 ret = check_device_access_params(devip, lba, num);
1708 if (ret)
1709 return ret;
1710
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001712 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1713 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1714 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1716 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001717 /* set info field and valid bit for fixed descriptor */
1718 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1719 devip->sense_buff[0] |= 0x80; /* Valid bit */
1720 ret = OPT_MEDIUM_ERR_ADDR;
1721 devip->sense_buff[3] = (ret >> 24) & 0xff;
1722 devip->sense_buff[4] = (ret >> 16) & 0xff;
1723 devip->sense_buff[5] = (ret >> 8) & 0xff;
1724 devip->sense_buff[6] = ret & 0xff;
1725 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 return check_condition_result;
1727 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001728
1729 /* DIX + T10 DIF */
1730 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001731 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001732
1733 if (prot_ret) {
1734 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1735 return illegal_condition_result;
1736 }
1737 }
1738
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001740 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 read_unlock_irqrestore(&atomic_rw, iflags);
1742 return ret;
1743}
1744
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001745void dump_sector(unsigned char *buf, int len)
1746{
1747 int i, j;
1748
1749 printk(KERN_ERR ">>> Sector Dump <<<\n");
1750
1751 for (i = 0 ; i < len ; i += 16) {
1752 printk(KERN_ERR "%04d: ", i);
1753
1754 for (j = 0 ; j < 16 ; j++) {
1755 unsigned char c = buf[i+j];
1756 if (c >= 0x20 && c < 0x7e)
1757 printk(" %c ", buf[i+j]);
1758 else
1759 printk("%02x ", buf[i+j]);
1760 }
1761
1762 printk("\n");
1763 }
1764}
1765
1766static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001767 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001768{
1769 int i, j, ret;
1770 struct sd_dif_tuple *sdt;
1771 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1772 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1773 void *daddr, *paddr;
1774 sector_t tmp_sec = start_sec;
1775 sector_t sector;
1776 int ppage_offset;
1777 unsigned short csum;
1778
1779 sector = do_div(tmp_sec, sdebug_store_sectors);
1780
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001781 BUG_ON(scsi_sg_count(SCpnt) == 0);
1782 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1783
1784 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1785 ppage_offset = 0;
1786
1787 /* For each data page */
1788 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1789 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1790
1791 /* For each sector-sized chunk in data page */
1792 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1793
1794 /* If we're at the end of the current
1795 * protection page advance to the next one
1796 */
1797 if (ppage_offset >= psgl->length) {
1798 kunmap_atomic(paddr, KM_IRQ1);
1799 psgl = sg_next(psgl);
1800 BUG_ON(psgl == NULL);
1801 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1802 + psgl->offset;
1803 ppage_offset = 0;
1804 }
1805
1806 sdt = paddr + ppage_offset;
1807
1808 switch (scsi_debug_guard) {
1809 case 1:
1810 csum = ip_compute_csum(daddr,
1811 scsi_debug_sector_size);
1812 break;
1813 case 0:
1814 csum = cpu_to_be16(crc_t10dif(daddr,
1815 scsi_debug_sector_size));
1816 break;
1817 default:
1818 BUG();
1819 ret = 0;
1820 goto out;
1821 }
1822
1823 if (sdt->guard_tag != csum) {
1824 printk(KERN_ERR
1825 "%s: GUARD check failed on sector %lu " \
1826 "rcvd 0x%04x, calculated 0x%04x\n",
1827 __func__, (unsigned long)sector,
1828 be16_to_cpu(sdt->guard_tag),
1829 be16_to_cpu(csum));
1830 ret = 0x01;
1831 dump_sector(daddr, scsi_debug_sector_size);
1832 goto out;
1833 }
1834
Martin K. Petersen395cef02009-09-18 17:33:03 -04001835 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001836 be32_to_cpu(sdt->ref_tag)
1837 != (start_sec & 0xffffffff)) {
1838 printk(KERN_ERR
1839 "%s: REF check failed on sector %lu\n",
1840 __func__, (unsigned long)sector);
1841 ret = 0x03;
1842 dump_sector(daddr, scsi_debug_sector_size);
1843 goto out;
1844 }
1845
Martin K. Petersen395cef02009-09-18 17:33:03 -04001846 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1847 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1848 printk(KERN_ERR
1849 "%s: REF check failed on sector %lu\n",
1850 __func__, (unsigned long)sector);
1851 ret = 0x03;
1852 dump_sector(daddr, scsi_debug_sector_size);
1853 goto out;
1854 }
1855
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001856 /* Would be great to copy this in bigger
1857 * chunks. However, for the sake of
1858 * correctness we need to verify each sector
1859 * before writing it to "stable" storage
1860 */
1861 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1862
1863 sector++;
1864
1865 if (sector == sdebug_store_sectors)
1866 sector = 0; /* Force wrap */
1867
1868 start_sec++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001869 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001870 daddr += scsi_debug_sector_size;
1871 ppage_offset += sizeof(struct sd_dif_tuple);
1872 }
1873
1874 kunmap_atomic(daddr, KM_IRQ0);
1875 }
1876
1877 kunmap_atomic(paddr, KM_IRQ1);
1878
1879 dix_writes++;
1880
1881 return 0;
1882
1883out:
1884 dif_errors++;
1885 kunmap_atomic(daddr, KM_IRQ0);
1886 kunmap_atomic(paddr, KM_IRQ1);
1887 return ret;
1888}
1889
FUJITA Tomonori19789102008-03-30 00:59:56 +09001890static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001891 unsigned int num, struct sdebug_dev_info *devip,
1892 u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893{
1894 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001895 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
FUJITA Tomonori19789102008-03-30 00:59:56 +09001897 ret = check_device_access_params(devip, lba, num);
1898 if (ret)
1899 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001901 /* DIX + T10 DIF */
1902 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001903 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001904
1905 if (prot_ret) {
1906 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
1907 return illegal_condition_result;
1908 }
1909 }
1910
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001912 ret = do_device_access(SCpnt, devip, lba, num, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001914 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04001916 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001918 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04001919 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 return 0;
1921}
1922
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001923#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924
1925static int resp_report_luns(struct scsi_cmnd * scp,
1926 struct sdebug_dev_info * devip)
1927{
1928 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001929 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 unsigned char *cmd = (unsigned char *)scp->cmnd;
1931 int select_report = (int)cmd[2];
1932 struct scsi_lun *one_lun;
1933 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001934 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935
1936 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001937 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1939 0);
1940 return check_condition_result;
1941 }
1942 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1943 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1944 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001945 if (1 == select_report)
1946 lun_cnt = 0;
1947 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1948 --lun_cnt;
1949 wlun = (select_report > 0) ? 1 : 0;
1950 num = lun_cnt + wlun;
1951 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1952 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1953 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1954 sizeof(struct scsi_lun)), num);
1955 if (n < num) {
1956 wlun = 0;
1957 lun_cnt = n;
1958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001960 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1961 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1962 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1963 i++, lun++) {
1964 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 if (upper)
1966 one_lun[i].scsi_lun[0] =
1967 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001968 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001970 if (wlun) {
1971 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1972 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1973 i++;
1974 }
1975 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 return fill_from_dev_buffer(scp, arr,
1977 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1978}
1979
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001980static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1981 unsigned int num, struct sdebug_dev_info *devip)
1982{
1983 int i, j, ret = -1;
1984 unsigned char *kaddr, *buf;
1985 unsigned int offset;
1986 struct scatterlist *sg;
1987 struct scsi_data_buffer *sdb = scsi_in(scp);
1988
1989 /* better not to use temporary buffer. */
1990 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1991 if (!buf)
1992 return ret;
1993
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001994 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001995
1996 offset = 0;
1997 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1998 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1999 if (!kaddr)
2000 goto out;
2001
2002 for (j = 0; j < sg->length; j++)
2003 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2004
2005 offset += sg->length;
2006 kunmap_atomic(kaddr, KM_USER0);
2007 }
2008 ret = 0;
2009out:
2010 kfree(buf);
2011
2012 return ret;
2013}
2014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015/* When timer goes off this function is called. */
2016static void timer_intr_handler(unsigned long indx)
2017{
2018 struct sdebug_queued_cmd * sqcp;
2019 unsigned long iflags;
2020
2021 if (indx >= SCSI_DEBUG_CANQUEUE) {
2022 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2023 "large\n");
2024 return;
2025 }
2026 spin_lock_irqsave(&queued_arr_lock, iflags);
2027 sqcp = &queued_arr[(int)indx];
2028 if (! sqcp->in_use) {
2029 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2030 "interrupt\n");
2031 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2032 return;
2033 }
2034 sqcp->in_use = 0;
2035 if (sqcp->done_funct) {
2036 sqcp->a_cmnd->result = sqcp->scsi_result;
2037 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2038 }
2039 sqcp->done_funct = NULL;
2040 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2041}
2042
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002044static struct sdebug_dev_info *
2045sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002046{
2047 struct sdebug_dev_info *devip;
2048
2049 devip = kzalloc(sizeof(*devip), flags);
2050 if (devip) {
2051 devip->sdbg_host = sdbg_host;
2052 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2053 }
2054 return devip;
2055}
2056
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2058{
2059 struct sdebug_host_info * sdbg_host;
2060 struct sdebug_dev_info * open_devip = NULL;
2061 struct sdebug_dev_info * devip =
2062 (struct sdebug_dev_info *)sdev->hostdata;
2063
2064 if (devip)
2065 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002066 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2067 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 printk(KERN_ERR "Host info NULL\n");
2069 return NULL;
2070 }
2071 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2072 if ((devip->used) && (devip->channel == sdev->channel) &&
2073 (devip->target == sdev->id) &&
2074 (devip->lun == sdev->lun))
2075 return devip;
2076 else {
2077 if ((!devip->used) && (!open_devip))
2078 open_devip = devip;
2079 }
2080 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002081 if (!open_devip) { /* try and make a new one */
2082 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2083 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002085 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 return NULL;
2087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002089
2090 open_devip->channel = sdev->channel;
2091 open_devip->target = sdev->id;
2092 open_devip->lun = sdev->lun;
2093 open_devip->sdbg_host = sdbg_host;
2094 open_devip->reset = 1;
2095 open_devip->used = 1;
2096 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2097 if (scsi_debug_dsense)
2098 open_devip->sense_buff[0] = 0x72;
2099 else {
2100 open_devip->sense_buff[0] = 0x70;
2101 open_devip->sense_buff[7] = 0xa;
2102 }
2103 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2104 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2105
2106 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107}
2108
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002109static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002111 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2112 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2113 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002114 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002115 return 0;
2116}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002118static int scsi_debug_slave_configure(struct scsi_device *sdp)
2119{
2120 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002121
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002123 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2124 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2125 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2126 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2127 devip = devInfoReg(sdp);
2128 if (NULL == devip)
2129 return 1; /* no resources, will be marked offline */
2130 sdp->hostdata = devip;
2131 if (sdp->host->cmd_per_lun)
2132 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2133 sdp->host->cmd_per_lun);
2134 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
2135 return 0;
2136}
2137
2138static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2139{
2140 struct sdebug_dev_info *devip =
2141 (struct sdebug_dev_info *)sdp->hostdata;
2142
2143 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2144 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2145 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2146 if (devip) {
2147 /* make this slot avaliable for re-use */
2148 devip->used = 0;
2149 sdp->hostdata = NULL;
2150 }
2151}
2152
2153/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2154static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2155{
2156 unsigned long iflags;
2157 int k;
2158 struct sdebug_queued_cmd *sqcp;
2159
2160 spin_lock_irqsave(&queued_arr_lock, iflags);
2161 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2162 sqcp = &queued_arr[k];
2163 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2164 del_timer_sync(&sqcp->cmnd_timer);
2165 sqcp->in_use = 0;
2166 sqcp->a_cmnd = NULL;
2167 break;
2168 }
2169 }
2170 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2171 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2172}
2173
2174/* Deletes (stops) timers of all queued commands */
2175static void stop_all_queued(void)
2176{
2177 unsigned long iflags;
2178 int k;
2179 struct sdebug_queued_cmd *sqcp;
2180
2181 spin_lock_irqsave(&queued_arr_lock, iflags);
2182 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2183 sqcp = &queued_arr[k];
2184 if (sqcp->in_use && sqcp->a_cmnd) {
2185 del_timer_sync(&sqcp->cmnd_timer);
2186 sqcp->in_use = 0;
2187 sqcp->a_cmnd = NULL;
2188 }
2189 }
2190 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191}
2192
2193static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2194{
2195 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2196 printk(KERN_INFO "scsi_debug: abort\n");
2197 ++num_aborts;
2198 stop_queued_cmnd(SCpnt);
2199 return SUCCESS;
2200}
2201
2202static int scsi_debug_biosparam(struct scsi_device *sdev,
2203 struct block_device * bdev, sector_t capacity, int *info)
2204{
2205 int res;
2206 unsigned char *buf;
2207
2208 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2209 printk(KERN_INFO "scsi_debug: biosparam\n");
2210 buf = scsi_bios_ptable(bdev);
2211 if (buf) {
2212 res = scsi_partsize(buf, capacity,
2213 &info[2], &info[0], &info[1]);
2214 kfree(buf);
2215 if (! res)
2216 return res;
2217 }
2218 info[0] = sdebug_heads;
2219 info[1] = sdebug_sectors_per;
2220 info[2] = sdebug_cylinders_per;
2221 return 0;
2222}
2223
2224static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2225{
2226 struct sdebug_dev_info * devip;
2227
2228 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2229 printk(KERN_INFO "scsi_debug: device_reset\n");
2230 ++num_dev_resets;
2231 if (SCpnt) {
2232 devip = devInfoReg(SCpnt->device);
2233 if (devip)
2234 devip->reset = 1;
2235 }
2236 return SUCCESS;
2237}
2238
2239static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2240{
2241 struct sdebug_host_info *sdbg_host;
2242 struct sdebug_dev_info * dev_info;
2243 struct scsi_device * sdp;
2244 struct Scsi_Host * hp;
2245
2246 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2247 printk(KERN_INFO "scsi_debug: bus_reset\n");
2248 ++num_bus_resets;
2249 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002250 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 if (sdbg_host) {
2252 list_for_each_entry(dev_info,
2253 &sdbg_host->dev_info_list,
2254 dev_list)
2255 dev_info->reset = 1;
2256 }
2257 }
2258 return SUCCESS;
2259}
2260
2261static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2262{
2263 struct sdebug_host_info * sdbg_host;
2264 struct sdebug_dev_info * dev_info;
2265
2266 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2267 printk(KERN_INFO "scsi_debug: host_reset\n");
2268 ++num_host_resets;
2269 spin_lock(&sdebug_host_list_lock);
2270 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2271 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2272 dev_list)
2273 dev_info->reset = 1;
2274 }
2275 spin_unlock(&sdebug_host_list_lock);
2276 stop_all_queued();
2277 return SUCCESS;
2278}
2279
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280/* Initializes timers in queued array */
2281static void __init init_all_queued(void)
2282{
2283 unsigned long iflags;
2284 int k;
2285 struct sdebug_queued_cmd * sqcp;
2286
2287 spin_lock_irqsave(&queued_arr_lock, iflags);
2288 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2289 sqcp = &queued_arr[k];
2290 init_timer(&sqcp->cmnd_timer);
2291 sqcp->in_use = 0;
2292 sqcp->a_cmnd = NULL;
2293 }
2294 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2295}
2296
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002297static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002298 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299{
2300 struct partition * pp;
2301 int starts[SDEBUG_MAX_PARTS + 2];
2302 int sectors_per_part, num_sectors, k;
2303 int heads_by_sects, start_sec, end_sec;
2304
2305 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002306 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 return;
2308 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2309 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2310 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2311 "partitions to %d\n", SDEBUG_MAX_PARTS);
2312 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002313 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 sectors_per_part = (num_sectors - sdebug_sectors_per)
2315 / scsi_debug_num_parts;
2316 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2317 starts[0] = sdebug_sectors_per;
2318 for (k = 1; k < scsi_debug_num_parts; ++k)
2319 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2320 * heads_by_sects;
2321 starts[scsi_debug_num_parts] = num_sectors;
2322 starts[scsi_debug_num_parts + 1] = 0;
2323
2324 ramp[510] = 0x55; /* magic partition markings */
2325 ramp[511] = 0xAA;
2326 pp = (struct partition *)(ramp + 0x1be);
2327 for (k = 0; starts[k + 1]; ++k, ++pp) {
2328 start_sec = starts[k];
2329 end_sec = starts[k + 1] - 1;
2330 pp->boot_ind = 0;
2331
2332 pp->cyl = start_sec / heads_by_sects;
2333 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2334 / sdebug_sectors_per;
2335 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2336
2337 pp->end_cyl = end_sec / heads_by_sects;
2338 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2339 / sdebug_sectors_per;
2340 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2341
2342 pp->start_sect = start_sec;
2343 pp->nr_sects = end_sec - start_sec + 1;
2344 pp->sys_ind = 0x83; /* plain Linux partition */
2345 }
2346}
2347
2348static int schedule_resp(struct scsi_cmnd * cmnd,
2349 struct sdebug_dev_info * devip,
2350 done_funct_t done, int scsi_result, int delta_jiff)
2351{
2352 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2353 if (scsi_result) {
2354 struct scsi_device * sdp = cmnd->device;
2355
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002356 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2357 "non-zero result=0x%x\n", sdp->host->host_no,
2358 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 }
2360 }
2361 if (cmnd && devip) {
2362 /* simulate autosense by this driver */
2363 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2364 memcpy(cmnd->sense_buffer, devip->sense_buff,
2365 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2366 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2367 }
2368 if (delta_jiff <= 0) {
2369 if (cmnd)
2370 cmnd->result = scsi_result;
2371 if (done)
2372 done(cmnd);
2373 return 0;
2374 } else {
2375 unsigned long iflags;
2376 int k;
2377 struct sdebug_queued_cmd * sqcp = NULL;
2378
2379 spin_lock_irqsave(&queued_arr_lock, iflags);
2380 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2381 sqcp = &queued_arr[k];
2382 if (! sqcp->in_use)
2383 break;
2384 }
2385 if (k >= SCSI_DEBUG_CANQUEUE) {
2386 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2387 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2388 return 1; /* report busy to mid level */
2389 }
2390 sqcp->in_use = 1;
2391 sqcp->a_cmnd = cmnd;
2392 sqcp->scsi_result = scsi_result;
2393 sqcp->done_funct = done;
2394 sqcp->cmnd_timer.function = timer_intr_handler;
2395 sqcp->cmnd_timer.data = k;
2396 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2397 add_timer(&sqcp->cmnd_timer);
2398 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2399 if (cmnd)
2400 cmnd->result = 0;
2401 return 0;
2402 }
2403}
Douglas Gilbert23183912006-09-16 20:30:47 -04002404/* Note: The following macros create attribute files in the
2405 /sys/module/scsi_debug/parameters directory. Unfortunately this
2406 driver is unaware of a change and cannot trigger auxiliary actions
2407 as it can when the corresponding attribute in the
2408 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2409 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002410module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2411module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2412module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2413module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2414module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002415module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002416module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2417module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2418module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2419module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2420module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2421module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2422module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2423module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002424module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2425 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002426module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002427module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2428module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2429module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2430module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002431module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2432module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
2434MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2435MODULE_DESCRIPTION("SCSI debug adapter driver");
2436MODULE_LICENSE("GPL");
2437MODULE_VERSION(SCSI_DEBUG_VERSION);
2438
2439MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2440MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002441MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2442MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002443MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002444MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002445MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2446MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002448MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002449MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2451MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002452MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002453MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002454MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
2455MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
2456MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002457MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2458MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2459MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2460MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461
2462static char sdebug_info[256];
2463
2464static const char * scsi_debug_info(struct Scsi_Host * shp)
2465{
2466 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2467 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2468 scsi_debug_version_date, scsi_debug_dev_size_mb,
2469 scsi_debug_opts);
2470 return sdebug_info;
2471}
2472
2473/* scsi_debug_proc_info
2474 * Used if the driver currently has no own support for /proc/scsi
2475 */
2476static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2477 int length, int inout)
2478{
2479 int len, pos, begin;
2480 int orig_length;
2481
2482 orig_length = length;
2483
2484 if (inout == 1) {
2485 char arr[16];
2486 int minLen = length > 15 ? 15 : length;
2487
2488 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2489 return -EACCES;
2490 memcpy(arr, buffer, minLen);
2491 arr[minLen] = '\0';
2492 if (1 != sscanf(arr, "%d", &pos))
2493 return -EINVAL;
2494 scsi_debug_opts = pos;
2495 if (scsi_debug_every_nth != 0)
2496 scsi_debug_cmnd_count = 0;
2497 return length;
2498 }
2499 begin = 0;
2500 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2501 "%s [%s]\n"
2502 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2503 "every_nth=%d(curr:%d)\n"
2504 "delay=%d, max_luns=%d, scsi_level=%d\n"
2505 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2506 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002507 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2509 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2510 scsi_debug_cmnd_count, scsi_debug_delay,
2511 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002512 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2513 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002514 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 if (pos < offset) {
2516 len = 0;
2517 begin = pos;
2518 }
2519 *start = buffer + (offset - begin); /* Start of wanted data */
2520 len -= (offset - begin);
2521 if (len > length)
2522 len = length;
2523 return len;
2524}
2525
2526static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2527{
2528 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2529}
2530
2531static ssize_t sdebug_delay_store(struct device_driver * ddp,
2532 const char * buf, size_t count)
2533{
2534 int delay;
2535 char work[20];
2536
2537 if (1 == sscanf(buf, "%10s", work)) {
2538 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2539 scsi_debug_delay = delay;
2540 return count;
2541 }
2542 }
2543 return -EINVAL;
2544}
2545DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2546 sdebug_delay_store);
2547
2548static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2549{
2550 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2551}
2552
2553static ssize_t sdebug_opts_store(struct device_driver * ddp,
2554 const char * buf, size_t count)
2555{
2556 int opts;
2557 char work[20];
2558
2559 if (1 == sscanf(buf, "%10s", work)) {
2560 if (0 == strnicmp(work,"0x", 2)) {
2561 if (1 == sscanf(&work[2], "%x", &opts))
2562 goto opts_done;
2563 } else {
2564 if (1 == sscanf(work, "%d", &opts))
2565 goto opts_done;
2566 }
2567 }
2568 return -EINVAL;
2569opts_done:
2570 scsi_debug_opts = opts;
2571 scsi_debug_cmnd_count = 0;
2572 return count;
2573}
2574DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2575 sdebug_opts_store);
2576
2577static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2578{
2579 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2580}
2581static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2582 const char * buf, size_t count)
2583{
2584 int n;
2585
2586 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2587 scsi_debug_ptype = n;
2588 return count;
2589 }
2590 return -EINVAL;
2591}
2592DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2593
2594static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2595{
2596 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2597}
2598static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2599 const char * buf, size_t count)
2600{
2601 int n;
2602
2603 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2604 scsi_debug_dsense = n;
2605 return count;
2606 }
2607 return -EINVAL;
2608}
2609DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2610 sdebug_dsense_store);
2611
Douglas Gilbert23183912006-09-16 20:30:47 -04002612static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2613{
2614 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2615}
2616static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2617 const char * buf, size_t count)
2618{
2619 int n;
2620
2621 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2622 scsi_debug_fake_rw = n;
2623 return count;
2624 }
2625 return -EINVAL;
2626}
2627DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2628 sdebug_fake_rw_store);
2629
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002630static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2631{
2632 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2633}
2634static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2635 const char * buf, size_t count)
2636{
2637 int n;
2638
2639 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2640 scsi_debug_no_lun_0 = n;
2641 return count;
2642 }
2643 return -EINVAL;
2644}
2645DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2646 sdebug_no_lun_0_store);
2647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2649{
2650 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2651}
2652static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2653 const char * buf, size_t count)
2654{
2655 int n;
2656
2657 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2658 scsi_debug_num_tgts = n;
2659 sdebug_max_tgts_luns();
2660 return count;
2661 }
2662 return -EINVAL;
2663}
2664DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2665 sdebug_num_tgts_store);
2666
2667static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2668{
2669 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2670}
2671DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2672
2673static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2674{
2675 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2676}
2677DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2678
2679static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2680{
2681 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2682}
2683static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2684 const char * buf, size_t count)
2685{
2686 int nth;
2687
2688 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2689 scsi_debug_every_nth = nth;
2690 scsi_debug_cmnd_count = 0;
2691 return count;
2692 }
2693 return -EINVAL;
2694}
2695DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2696 sdebug_every_nth_store);
2697
2698static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2699{
2700 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2701}
2702static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2703 const char * buf, size_t count)
2704{
2705 int n;
2706
2707 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2708 scsi_debug_max_luns = n;
2709 sdebug_max_tgts_luns();
2710 return count;
2711 }
2712 return -EINVAL;
2713}
2714DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2715 sdebug_max_luns_store);
2716
2717static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2718{
2719 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2720}
2721DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2722
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002723static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2724{
2725 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2726}
2727static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2728 const char * buf, size_t count)
2729{
2730 int n;
2731
2732 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2733 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002734
2735 sdebug_capacity = get_sdebug_capacity();
2736
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002737 return count;
2738 }
2739 return -EINVAL;
2740}
2741DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2742 sdebug_virtual_gb_store);
2743
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2745{
2746 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2747}
2748
2749static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2750 const char * buf, size_t count)
2751{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002752 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002754 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 if (delta_hosts > 0) {
2757 do {
2758 sdebug_add_adapter();
2759 } while (--delta_hosts);
2760 } else if (delta_hosts < 0) {
2761 do {
2762 sdebug_remove_adapter();
2763 } while (++delta_hosts);
2764 }
2765 return count;
2766}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002767DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 sdebug_add_host_store);
2769
Douglas Gilbert23183912006-09-16 20:30:47 -04002770static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2771 char * buf)
2772{
2773 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2774}
2775static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2776 const char * buf, size_t count)
2777{
2778 int n;
2779
2780 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2781 scsi_debug_vpd_use_hostno = n;
2782 return count;
2783 }
2784 return -EINVAL;
2785}
2786DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2787 sdebug_vpd_use_hostno_store);
2788
Martin K. Petersen597136a2008-06-05 00:12:59 -04002789static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
2790{
2791 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
2792}
2793DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
2794
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002795static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
2796{
2797 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
2798}
2799DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
2800
2801static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
2802{
2803 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
2804}
2805DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
2806
2807static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
2808{
2809 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
2810}
2811DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
2812
2813static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
2814{
2815 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
2816}
2817DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
2818
2819
Douglas Gilbert23183912006-09-16 20:30:47 -04002820/* Note: The following function creates attribute files in the
2821 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2822 files (over those found in the /sys/module/scsi_debug/parameters
2823 directory) is that auxiliary actions can be triggered when an attribute
2824 is changed. For example see: sdebug_add_host_store() above.
2825 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002826static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002828 int ret;
2829
2830 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2831 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2832 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2833 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2834 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002835 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002836 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002837 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002838 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002839 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002840 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2841 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2842 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002843 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2844 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002845 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002846 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
2847 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
2848 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
2849 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002850 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851}
2852
2853static void do_remove_driverfs_files(void)
2854{
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002855 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
2856 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
2857 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
2858 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002859 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04002860 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2861 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2863 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2864 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002866 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2867 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002869 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2871 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2872 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2873 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2874 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2875}
2876
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002877static void pseudo_0_release(struct device *dev)
2878{
2879 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2880 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2881}
2882
2883static struct device pseudo_primary = {
Kay Sievers71610f52008-12-03 22:41:36 +01002884 .init_name = "pseudo_0",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002885 .release = pseudo_0_release,
2886};
2887
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888static int __init scsi_debug_init(void)
2889{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002890 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 int host_to_add;
2892 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002893 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
Martin K. Petersen597136a2008-06-05 00:12:59 -04002895 switch (scsi_debug_sector_size) {
2896 case 512:
2897 case 1024:
2898 case 2048:
2899 case 4096:
2900 break;
2901 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002902 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04002903 scsi_debug_sector_size);
2904 return -EINVAL;
2905 }
2906
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002907 switch (scsi_debug_dif) {
2908
2909 case SD_DIF_TYPE0_PROTECTION:
2910 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04002911 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002912 case SD_DIF_TYPE3_PROTECTION:
2913 break;
2914
2915 default:
Martin K. Petersen395cef02009-09-18 17:33:03 -04002916 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002917 return -EINVAL;
2918 }
2919
2920 if (scsi_debug_guard > 1) {
2921 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
2922 return -EINVAL;
2923 }
2924
2925 if (scsi_debug_ato > 1) {
2926 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
2927 return -EINVAL;
2928 }
2929
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002930 if (scsi_debug_physblk_exp > 15) {
2931 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
2932 scsi_debug_physblk_exp);
2933 return -EINVAL;
2934 }
2935
2936 if (scsi_debug_lowest_aligned > 0x3fff) {
2937 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
2938 scsi_debug_lowest_aligned);
2939 return -EINVAL;
2940 }
2941
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 if (scsi_debug_dev_size_mb < 1)
2943 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002944 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04002945 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002946 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947
2948 /* play around with geometry, don't waste too much on track 0 */
2949 sdebug_heads = 8;
2950 sdebug_sectors_per = 32;
2951 if (scsi_debug_dev_size_mb >= 16)
2952 sdebug_heads = 32;
2953 else if (scsi_debug_dev_size_mb >= 256)
2954 sdebug_heads = 64;
2955 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2956 (sdebug_sectors_per * sdebug_heads);
2957 if (sdebug_cylinders_per >= 1024) {
2958 /* other LLDs do this; implies >= 1GB ram disk ... */
2959 sdebug_heads = 255;
2960 sdebug_sectors_per = 63;
2961 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2962 (sdebug_sectors_per * sdebug_heads);
2963 }
2964
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 fake_storep = vmalloc(sz);
2966 if (NULL == fake_storep) {
2967 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2968 return -ENOMEM;
2969 }
2970 memset(fake_storep, 0, sz);
2971 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002972 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002974 if (scsi_debug_dif) {
2975 int dif_size;
2976
2977 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
2978 dif_storep = vmalloc(dif_size);
2979
2980 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
2981 dif_size, dif_storep);
2982
2983 if (dif_storep == NULL) {
2984 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
2985 ret = -ENOMEM;
2986 goto free_vm;
2987 }
2988
2989 memset(dif_storep, 0xff, dif_size);
2990 }
2991
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002992 ret = device_register(&pseudo_primary);
2993 if (ret < 0) {
2994 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2995 ret);
2996 goto free_vm;
2997 }
2998 ret = bus_register(&pseudo_lld_bus);
2999 if (ret < 0) {
3000 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
3001 ret);
3002 goto dev_unreg;
3003 }
3004 ret = driver_register(&sdebug_driverfs_driver);
3005 if (ret < 0) {
3006 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
3007 ret);
3008 goto bus_unreg;
3009 }
3010 ret = do_create_driverfs_files();
3011 if (ret < 0) {
3012 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
3013 ret);
3014 goto del_files;
3015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003017 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 host_to_add = scsi_debug_add_host;
3020 scsi_debug_add_host = 0;
3021
3022 for (k = 0; k < host_to_add; k++) {
3023 if (sdebug_add_adapter()) {
3024 printk(KERN_ERR "scsi_debug_init: "
3025 "sdebug_add_adapter failed k=%d\n", k);
3026 break;
3027 }
3028 }
3029
3030 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3031 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
3032 scsi_debug_add_host);
3033 }
3034 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003035
3036del_files:
3037 do_remove_driverfs_files();
3038 driver_unregister(&sdebug_driverfs_driver);
3039bus_unreg:
3040 bus_unregister(&pseudo_lld_bus);
3041dev_unreg:
3042 device_unregister(&pseudo_primary);
3043free_vm:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003044 if (dif_storep)
3045 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003046 vfree(fake_storep);
3047
3048 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049}
3050
3051static void __exit scsi_debug_exit(void)
3052{
3053 int k = scsi_debug_add_host;
3054
3055 stop_all_queued();
3056 for (; k; k--)
3057 sdebug_remove_adapter();
3058 do_remove_driverfs_files();
3059 driver_unregister(&sdebug_driverfs_driver);
3060 bus_unregister(&pseudo_lld_bus);
3061 device_unregister(&pseudo_primary);
3062
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003063 if (dif_storep)
3064 vfree(dif_storep);
3065
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 vfree(fake_storep);
3067}
3068
3069device_initcall(scsi_debug_init);
3070module_exit(scsi_debug_exit);
3071
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072static void sdebug_release_adapter(struct device * dev)
3073{
3074 struct sdebug_host_info *sdbg_host;
3075
3076 sdbg_host = to_sdebug_host(dev);
3077 kfree(sdbg_host);
3078}
3079
3080static int sdebug_add_adapter(void)
3081{
3082 int k, devs_per_host;
3083 int error = 0;
3084 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003085 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003087 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 if (NULL == sdbg_host) {
3089 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003090 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 return -ENOMEM;
3092 }
3093
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3095
3096 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3097 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003098 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3099 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003101 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 error = -ENOMEM;
3103 goto clean;
3104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 }
3106
3107 spin_lock(&sdebug_host_list_lock);
3108 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3109 spin_unlock(&sdebug_host_list_lock);
3110
3111 sdbg_host->dev.bus = &pseudo_lld_bus;
3112 sdbg_host->dev.parent = &pseudo_primary;
3113 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003114 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
3116 error = device_register(&sdbg_host->dev);
3117
3118 if (error)
3119 goto clean;
3120
3121 ++scsi_debug_add_host;
3122 return error;
3123
3124clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003125 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3126 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 list_del(&sdbg_devinfo->dev_list);
3128 kfree(sdbg_devinfo);
3129 }
3130
3131 kfree(sdbg_host);
3132 return error;
3133}
3134
3135static void sdebug_remove_adapter(void)
3136{
3137 struct sdebug_host_info * sdbg_host = NULL;
3138
3139 spin_lock(&sdebug_host_list_lock);
3140 if (!list_empty(&sdebug_host_list)) {
3141 sdbg_host = list_entry(sdebug_host_list.prev,
3142 struct sdebug_host_info, host_list);
3143 list_del(&sdbg_host->host_list);
3144 }
3145 spin_unlock(&sdebug_host_list_lock);
3146
3147 if (!sdbg_host)
3148 return;
3149
3150 device_unregister(&sdbg_host->dev);
3151 --scsi_debug_add_host;
3152}
3153
FUJITA Tomonori639db472008-03-20 11:09:19 +09003154static
3155int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
3156{
3157 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3158 int len, k;
3159 unsigned int num;
3160 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003161 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003162 int errsts = 0;
3163 int target = SCpnt->device->id;
3164 struct sdebug_dev_info *devip = NULL;
3165 int inj_recovered = 0;
3166 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003167 int inj_dif = 0;
3168 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003169 int delay_override = 0;
3170
3171 scsi_set_resid(SCpnt, 0);
3172 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3173 printk(KERN_INFO "scsi_debug: cmd ");
3174 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3175 printk("%02x ", (int)cmd[k]);
3176 printk("\n");
3177 }
3178
3179 if (target == SCpnt->device->host->hostt->this_id) {
3180 printk(KERN_INFO "scsi_debug: initiator's id used as "
3181 "target!\n");
3182 return schedule_resp(SCpnt, NULL, done,
3183 DID_NO_CONNECT << 16, 0);
3184 }
3185
3186 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3187 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3188 return schedule_resp(SCpnt, NULL, done,
3189 DID_NO_CONNECT << 16, 0);
3190 devip = devInfoReg(SCpnt->device);
3191 if (NULL == devip)
3192 return schedule_resp(SCpnt, NULL, done,
3193 DID_NO_CONNECT << 16, 0);
3194
3195 if ((scsi_debug_every_nth != 0) &&
3196 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3197 scsi_debug_cmnd_count = 0;
3198 if (scsi_debug_every_nth < -1)
3199 scsi_debug_every_nth = -1;
3200 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3201 return 0; /* ignore command causing timeout */
3202 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3203 inj_recovered = 1; /* to reads and writes below */
3204 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3205 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003206 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3207 inj_dif = 1; /* to reads and writes below */
3208 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3209 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003210 }
3211
3212 if (devip->wlun) {
3213 switch (*cmd) {
3214 case INQUIRY:
3215 case REQUEST_SENSE:
3216 case TEST_UNIT_READY:
3217 case REPORT_LUNS:
3218 break; /* only allowable wlun commands */
3219 default:
3220 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3221 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3222 "not supported for wlun\n", *cmd);
3223 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3224 INVALID_OPCODE, 0);
3225 errsts = check_condition_result;
3226 return schedule_resp(SCpnt, devip, done, errsts,
3227 0);
3228 }
3229 }
3230
3231 switch (*cmd) {
3232 case INQUIRY: /* mandatory, ignore unit attention */
3233 delay_override = 1;
3234 errsts = resp_inquiry(SCpnt, target, devip);
3235 break;
3236 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3237 delay_override = 1;
3238 errsts = resp_requests(SCpnt, devip);
3239 break;
3240 case REZERO_UNIT: /* actually this is REWIND for SSC */
3241 case START_STOP:
3242 errsts = resp_start_stop(SCpnt, devip);
3243 break;
3244 case ALLOW_MEDIUM_REMOVAL:
3245 errsts = check_readiness(SCpnt, 1, devip);
3246 if (errsts)
3247 break;
3248 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3249 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3250 cmd[4] ? "inhibited" : "enabled");
3251 break;
3252 case SEND_DIAGNOSTIC: /* mandatory */
3253 errsts = check_readiness(SCpnt, 1, devip);
3254 break;
3255 case TEST_UNIT_READY: /* mandatory */
3256 delay_override = 1;
3257 errsts = check_readiness(SCpnt, 0, devip);
3258 break;
3259 case RESERVE:
3260 errsts = check_readiness(SCpnt, 1, devip);
3261 break;
3262 case RESERVE_10:
3263 errsts = check_readiness(SCpnt, 1, devip);
3264 break;
3265 case RELEASE:
3266 errsts = check_readiness(SCpnt, 1, devip);
3267 break;
3268 case RELEASE_10:
3269 errsts = check_readiness(SCpnt, 1, devip);
3270 break;
3271 case READ_CAPACITY:
3272 errsts = resp_readcap(SCpnt, devip);
3273 break;
3274 case SERVICE_ACTION_IN:
3275 if (SAI_READ_CAPACITY_16 != cmd[1]) {
3276 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3277 INVALID_OPCODE, 0);
3278 errsts = check_condition_result;
3279 break;
3280 }
3281 errsts = resp_readcap16(SCpnt, devip);
3282 break;
3283 case MAINTENANCE_IN:
3284 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3285 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3286 INVALID_OPCODE, 0);
3287 errsts = check_condition_result;
3288 break;
3289 }
3290 errsts = resp_report_tgtpgs(SCpnt, devip);
3291 break;
3292 case READ_16:
3293 case READ_12:
3294 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003295 /* READ{10,12,16} and DIF Type 2 are natural enemies */
3296 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3297 cmd[1] & 0xe0) {
3298 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3299 INVALID_COMMAND_OPCODE, 0);
3300 errsts = check_condition_result;
3301 break;
3302 }
3303
3304 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3305 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3306 (cmd[1] & 0xe0) == 0)
3307 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3308
3309 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003310 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003311read:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003312 errsts = check_readiness(SCpnt, 0, devip);
3313 if (errsts)
3314 break;
3315 if (scsi_debug_fake_rw)
3316 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003317 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3318 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003319 if (inj_recovered && (0 == errsts)) {
3320 mk_sense_buffer(devip, RECOVERED_ERROR,
3321 THRESHOLD_EXCEEDED, 0);
3322 errsts = check_condition_result;
3323 } else if (inj_transport && (0 == errsts)) {
3324 mk_sense_buffer(devip, ABORTED_COMMAND,
3325 TRANSPORT_PROBLEM, ACK_NAK_TO);
3326 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003327 } else if (inj_dif && (0 == errsts)) {
3328 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3329 errsts = illegal_condition_result;
3330 } else if (inj_dix && (0 == errsts)) {
3331 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3332 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003333 }
3334 break;
3335 case REPORT_LUNS: /* mandatory, ignore unit attention */
3336 delay_override = 1;
3337 errsts = resp_report_luns(SCpnt, devip);
3338 break;
3339 case VERIFY: /* 10 byte SBC-2 command */
3340 errsts = check_readiness(SCpnt, 0, devip);
3341 break;
3342 case WRITE_16:
3343 case WRITE_12:
3344 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003345 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3346 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3347 cmd[1] & 0xe0) {
3348 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3349 INVALID_COMMAND_OPCODE, 0);
3350 errsts = check_condition_result;
3351 break;
3352 }
3353
3354 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3355 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3356 (cmd[1] & 0xe0) == 0)
3357 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3358
3359 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003360 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003361write:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003362 errsts = check_readiness(SCpnt, 0, devip);
3363 if (errsts)
3364 break;
3365 if (scsi_debug_fake_rw)
3366 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003367 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3368 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003369 if (inj_recovered && (0 == errsts)) {
3370 mk_sense_buffer(devip, RECOVERED_ERROR,
3371 THRESHOLD_EXCEEDED, 0);
3372 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003373 } else if (inj_dif && (0 == errsts)) {
3374 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3375 errsts = illegal_condition_result;
3376 } else if (inj_dix && (0 == errsts)) {
3377 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3378 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003379 }
3380 break;
3381 case MODE_SENSE:
3382 case MODE_SENSE_10:
3383 errsts = resp_mode_sense(SCpnt, target, devip);
3384 break;
3385 case MODE_SELECT:
3386 errsts = resp_mode_select(SCpnt, 1, devip);
3387 break;
3388 case MODE_SELECT_10:
3389 errsts = resp_mode_select(SCpnt, 0, devip);
3390 break;
3391 case LOG_SENSE:
3392 errsts = resp_log_sense(SCpnt, devip);
3393 break;
3394 case SYNCHRONIZE_CACHE:
3395 delay_override = 1;
3396 errsts = check_readiness(SCpnt, 0, devip);
3397 break;
3398 case WRITE_BUFFER:
3399 errsts = check_readiness(SCpnt, 1, devip);
3400 break;
3401 case XDWRITEREAD_10:
3402 if (!scsi_bidi_cmnd(SCpnt)) {
3403 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3404 INVALID_FIELD_IN_CDB, 0);
3405 errsts = check_condition_result;
3406 break;
3407 }
3408
3409 errsts = check_readiness(SCpnt, 0, devip);
3410 if (errsts)
3411 break;
3412 if (scsi_debug_fake_rw)
3413 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003414 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3415 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003416 if (errsts)
3417 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003418 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003419 if (errsts)
3420 break;
3421 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3422 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003423 case VARIABLE_LENGTH_CMD:
3424 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3425
3426 if ((cmd[10] & 0xe0) == 0)
3427 printk(KERN_ERR
3428 "Unprotected RD/WR to DIF device\n");
3429
3430 if (cmd[9] == READ_32) {
3431 BUG_ON(SCpnt->cmd_len < 32);
3432 goto read;
3433 }
3434
3435 if (cmd[9] == WRITE_32) {
3436 BUG_ON(SCpnt->cmd_len < 32);
3437 goto write;
3438 }
3439 }
3440
3441 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3442 INVALID_FIELD_IN_CDB, 0);
3443 errsts = check_condition_result;
3444 break;
3445
FUJITA Tomonori639db472008-03-20 11:09:19 +09003446 default:
3447 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3448 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3449 "supported\n", *cmd);
3450 errsts = check_readiness(SCpnt, 1, devip);
3451 if (errsts)
3452 break; /* Unit attention takes precedence */
3453 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3454 errsts = check_condition_result;
3455 break;
3456 }
3457 return schedule_resp(SCpnt, devip, done, errsts,
3458 (delay_override ? 0 : scsi_debug_delay));
3459}
3460
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003461static struct scsi_host_template sdebug_driver_template = {
3462 .proc_info = scsi_debug_proc_info,
3463 .proc_name = sdebug_proc_name,
3464 .name = "SCSI DEBUG",
3465 .info = scsi_debug_info,
3466 .slave_alloc = scsi_debug_slave_alloc,
3467 .slave_configure = scsi_debug_slave_configure,
3468 .slave_destroy = scsi_debug_slave_destroy,
3469 .ioctl = scsi_debug_ioctl,
3470 .queuecommand = scsi_debug_queuecommand,
3471 .eh_abort_handler = scsi_debug_abort,
3472 .eh_bus_reset_handler = scsi_debug_bus_reset,
3473 .eh_device_reset_handler = scsi_debug_device_reset,
3474 .eh_host_reset_handler = scsi_debug_host_reset,
3475 .bios_param = scsi_debug_biosparam,
3476 .can_queue = SCSI_DEBUG_CANQUEUE,
3477 .this_id = 7,
3478 .sg_tablesize = 256,
3479 .cmd_per_lun = 16,
3480 .max_sectors = 0xffff,
3481 .use_clustering = DISABLE_CLUSTERING,
3482 .module = THIS_MODULE,
3483};
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485static int sdebug_driver_probe(struct device * dev)
3486{
3487 int error = 0;
3488 struct sdebug_host_info *sdbg_host;
3489 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003490 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
3492 sdbg_host = to_sdebug_host(dev);
3493
3494 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3495 if (NULL == hpnt) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003496 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 error = -ENODEV;
3498 return error;
3499 }
3500
3501 sdbg_host->shost = hpnt;
3502 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3503 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3504 hpnt->max_id = scsi_debug_num_tgts + 1;
3505 else
3506 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003507 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003509 host_prot = 0;
3510
3511 switch (scsi_debug_dif) {
3512
3513 case SD_DIF_TYPE1_PROTECTION:
3514 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3515 if (scsi_debug_dix)
3516 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3517 break;
3518
3519 case SD_DIF_TYPE2_PROTECTION:
3520 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3521 if (scsi_debug_dix)
3522 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3523 break;
3524
3525 case SD_DIF_TYPE3_PROTECTION:
3526 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3527 if (scsi_debug_dix)
3528 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3529 break;
3530
3531 default:
3532 if (scsi_debug_dix)
3533 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3534 break;
3535 }
3536
3537 scsi_host_set_prot(hpnt, host_prot);
3538
3539 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3540 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3541 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3542 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3543 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3544 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3545 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3546 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3547
3548 if (scsi_debug_guard == 1)
3549 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3550 else
3551 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3552
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 error = scsi_add_host(hpnt, &sdbg_host->dev);
3554 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003555 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 error = -ENODEV;
3557 scsi_host_put(hpnt);
3558 } else
3559 scsi_scan_host(hpnt);
3560
3561
3562 return error;
3563}
3564
3565static int sdebug_driver_remove(struct device * dev)
3566{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003568 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
3570 sdbg_host = to_sdebug_host(dev);
3571
3572 if (!sdbg_host) {
3573 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003574 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 return -ENODEV;
3576 }
3577
3578 scsi_remove_host(sdbg_host->shost);
3579
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003580 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3581 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 list_del(&sdbg_devinfo->dev_list);
3583 kfree(sdbg_devinfo);
3584 }
3585
3586 scsi_host_put(sdbg_host->shost);
3587 return 0;
3588}
3589
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003590static int pseudo_lld_bus_match(struct device *dev,
3591 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003593 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003595
3596static struct bus_type pseudo_lld_bus = {
3597 .name = "pseudo",
3598 .match = pseudo_lld_bus_match,
3599 .probe = sdebug_driver_probe,
3600 .remove = sdebug_driver_remove,
3601};