blob: e7b39f133482e82c03e63edc32efbc005d4f97da [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040015 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/types.h>
35#include <linux/string.h>
36#include <linux/genhd.h>
37#include <linux/fs.h>
38#include <linux/init.h>
39#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/vmalloc.h>
41#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020042#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050044#include <linux/crc-t10dif.h>
45
46#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090047
Martin K. Petersen44d92692009-10-15 14:45:27 -040048#include <asm/unaligned.h>
49
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090050#include <scsi/scsi.h>
51#include <scsi/scsi_cmnd.h>
52#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <scsi/scsi_host.h>
54#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090055#include <scsi/scsi_eh.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040056#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Martin K. Petersenc6a44282009-01-04 03:08:19 -050058#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040061#define SCSI_DEBUG_VERSION "1.82"
62static const char * scsi_debug_version_date = "20100324";
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050064/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040065#define NO_ADDITIONAL_SENSE 0x0
66#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#define INVALID_OPCODE 0x20
70#define ADDR_OUT_OF_RANGE 0x21
Martin K. Petersen395cef02009-09-18 17:33:03 -040071#define INVALID_COMMAND_OPCODE 0x20
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040073#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define POWERON_RESET 0x29
75#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050076#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040077#define THRESHOLD_EXCEEDED 0x5d
78#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050080/* Additional Sense Code Qualifier (ASCQ) */
81#define ACK_NAK_TO 0x3
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
84
85/* Default values for driver parameters */
86#define DEF_NUM_HOST 1
87#define DEF_NUM_TGTS 1
88#define DEF_MAX_LUNS 1
89/* With these defaults, this driver will make 1 host with 1 target
90 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
91 */
92#define DEF_DELAY 1
93#define DEF_DEV_SIZE_MB 8
94#define DEF_EVERY_NTH 0
95#define DEF_NUM_PARTS 0
96#define DEF_OPTS 0
97#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
98#define DEF_PTYPE 0
99#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400100#define DEF_NO_LUN_0 0
101#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -0400102#define DEF_FAKE_RW 0
103#define DEF_VPD_USE_HOSTNO 1
Martin K. Petersen597136a2008-06-05 00:12:59 -0400104#define DEF_SECTOR_SIZE 512
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500105#define DEF_DIX 0
106#define DEF_DIF 0
107#define DEF_GUARD 0
108#define DEF_ATO 1
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400109#define DEF_PHYSBLK_EXP 0
110#define DEF_LOWEST_ALIGNED 0
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400111#define DEF_OPT_BLKS 64
Martin K. Petersen44d92692009-10-15 14:45:27 -0400112#define DEF_UNMAP_MAX_BLOCKS 0
113#define DEF_UNMAP_MAX_DESC 0
114#define DEF_UNMAP_GRANULARITY 0
115#define DEF_UNMAP_ALIGNMENT 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117/* bit mask values for scsi_debug_opts */
118#define SCSI_DEBUG_OPT_NOISE 1
119#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
120#define SCSI_DEBUG_OPT_TIMEOUT 4
121#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500122#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500123#define SCSI_DEBUG_OPT_DIF_ERR 32
124#define SCSI_DEBUG_OPT_DIX_ERR 64
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125/* When "every_nth" > 0 then modulo "every_nth" commands:
126 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
127 * - a RECOVERED_ERROR is simulated on successful read and write
128 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500129 * - a TRANSPORT_ERROR is simulated on successful read and write
130 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 *
132 * When "every_nth" < 0 then after "- every_nth" commands:
133 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
134 * - a RECOVERED_ERROR is simulated on successful read and write
135 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500136 * - a TRANSPORT_ERROR is simulated on successful read and write
137 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 * This will continue until some other action occurs (e.g. the user
139 * writing a new value (other than -1 or 1) to every_nth via sysfs).
140 */
141
142/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
143 * sector on read commands: */
144#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
145
146/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
147 * or "peripheral device" addressing (value 0) */
148#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400149#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400151/* Can queue up to this number of commands. Typically commands that
152 * that have a non-zero delay are queued. */
153#define SCSI_DEBUG_CANQUEUE 255
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static int scsi_debug_add_host = DEF_NUM_HOST;
156static int scsi_debug_delay = DEF_DELAY;
157static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
158static int scsi_debug_every_nth = DEF_EVERY_NTH;
159static int scsi_debug_max_luns = DEF_MAX_LUNS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400160static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161static int scsi_debug_num_parts = DEF_NUM_PARTS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400162static int scsi_debug_no_uld = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
164static int scsi_debug_opts = DEF_OPTS;
165static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
166static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
167static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400168static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
169static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400170static int scsi_debug_fake_rw = DEF_FAKE_RW;
171static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400172static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500173static int scsi_debug_dix = DEF_DIX;
174static int scsi_debug_dif = DEF_DIF;
175static int scsi_debug_guard = DEF_GUARD;
176static int scsi_debug_ato = DEF_ATO;
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400177static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
178static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400179static int scsi_debug_opt_blks = DEF_OPT_BLKS;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400180static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
181static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
182static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
183static int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185static int scsi_debug_cmnd_count = 0;
186
187#define DEV_READONLY(TGT) (0)
188#define DEV_REMOVEABLE(TGT) (0)
189
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400190static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191static sector_t sdebug_capacity; /* in sectors */
192
193/* old BIOS stuff, kernel may get rid of them but some mode sense pages
194 may still need them */
195static int sdebug_heads; /* heads per disk */
196static int sdebug_cylinders_per; /* cylinders per surface */
197static int sdebug_sectors_per; /* sectors per cylinder */
198
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199#define SDEBUG_MAX_PARTS 4
200
201#define SDEBUG_SENSE_LEN 32
202
Martin K. Petersen395cef02009-09-18 17:33:03 -0400203#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205struct sdebug_dev_info {
206 struct list_head dev_list;
207 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
208 unsigned int channel;
209 unsigned int target;
210 unsigned int lun;
211 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400212 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400214 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 char used;
216};
217
218struct sdebug_host_info {
219 struct list_head host_list;
220 struct Scsi_Host *shost;
221 struct device dev;
222 struct list_head dev_info_list;
223};
224
225#define to_sdebug_host(d) \
226 container_of(d, struct sdebug_host_info, dev)
227
228static LIST_HEAD(sdebug_host_list);
229static DEFINE_SPINLOCK(sdebug_host_list_lock);
230
231typedef void (* done_funct_t) (struct scsi_cmnd *);
232
233struct sdebug_queued_cmd {
234 int in_use;
235 struct timer_list cmnd_timer;
236 done_funct_t done_funct;
237 struct scsi_cmnd * a_cmnd;
238 int scsi_result;
239};
240static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
241
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242static unsigned char * fake_storep; /* ramdisk storage */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500243static unsigned char *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400244static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Martin K. Petersen44d92692009-10-15 14:45:27 -0400246static unsigned long map_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247static int num_aborts = 0;
248static int num_dev_resets = 0;
249static int num_bus_resets = 0;
250static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500251static int dix_writes;
252static int dix_reads;
253static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255static DEFINE_SPINLOCK(queued_arr_lock);
256static DEFINE_RWLOCK(atomic_rw);
257
258static char sdebug_proc_name[] = "scsi_debug";
259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260static struct bus_type pseudo_lld_bus;
261
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500262static inline sector_t dif_offset(sector_t sector)
263{
264 return sector << 3;
265}
266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267static struct device_driver sdebug_driverfs_driver = {
268 .name = sdebug_proc_name,
269 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270};
271
272static const int check_condition_result =
273 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
274
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500275static const int illegal_condition_result =
276 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
277
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400278static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
279 0, 0, 0x2, 0x4b};
280static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
281 0, 0, 0x0, 0x0};
282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283static int sdebug_add_adapter(void);
284static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900286static void sdebug_max_tgts_luns(void)
287{
288 struct sdebug_host_info *sdbg_host;
289 struct Scsi_Host *hpnt;
290
291 spin_lock(&sdebug_host_list_lock);
292 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
293 hpnt = sdbg_host->shost;
294 if ((hpnt->this_id >= 0) &&
295 (scsi_debug_num_tgts > hpnt->this_id))
296 hpnt->max_id = scsi_debug_num_tgts + 1;
297 else
298 hpnt->max_id = scsi_debug_num_tgts;
299 /* scsi_debug_max_luns; */
300 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
301 }
302 spin_unlock(&sdebug_host_list_lock);
303}
304
305static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
306 int asc, int asq)
307{
308 unsigned char *sbuff;
309
310 sbuff = devip->sense_buff;
311 memset(sbuff, 0, SDEBUG_SENSE_LEN);
312
313 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
314
315 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
316 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
317 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
318}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900320static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400321 unsigned long long *lba, unsigned int *num,
322 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900323{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400324 *ei_lba = 0;
325
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900326 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400327 case VARIABLE_LENGTH_CMD:
328 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
329 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
330 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
331 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
332
333 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
334 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
335
336 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
337 (u32)cmd[28] << 24;
338 break;
339
Martin K. Petersen44d92692009-10-15 14:45:27 -0400340 case WRITE_SAME_16:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900341 case WRITE_16:
342 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900343 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
344 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
345 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
346 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
347
348 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
349 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900350 break;
351 case WRITE_12:
352 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900353 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
354 (u32)cmd[2] << 24;
355
356 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
357 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900358 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400359 case WRITE_SAME:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900360 case WRITE_10:
361 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900362 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900363 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
364 (u32)cmd[2] << 24;
365
366 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900367 break;
368 case WRITE_6:
369 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900370 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
371 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900372 *num = (0 == cmd[4]) ? 256 : cmd[4];
373 break;
374 default:
375 break;
376 }
377}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
380{
381 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
382 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
383 }
384 return -EINVAL;
385 /* return -ENOTTY; // correct return but upsets fdisk */
386}
387
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400388static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
389 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390{
391 if (devip->reset) {
392 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
393 printk(KERN_INFO "scsi_debug: Reporting Unit "
394 "attention: power on reset\n");
395 devip->reset = 0;
396 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
397 return check_condition_result;
398 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400399 if ((0 == reset_only) && devip->stopped) {
400 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
401 printk(KERN_INFO "scsi_debug: Reporting Not "
402 "ready: initializing command required\n");
403 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
404 0x2);
405 return check_condition_result;
406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 return 0;
408}
409
410/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900411static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 int arr_len)
413{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900414 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900415 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900417 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900419 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900421
422 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
423 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900424 if (sdb->resid)
425 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400426 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900427 sdb->resid = scsi_bufflen(scp) - act_len;
428
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return 0;
430}
431
432/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900433static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
434 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900436 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900438 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900440
441 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442}
443
444
445static const char * inq_vendor_id = "Linux ";
446static const char * inq_product_id = "scsi_debug ";
447static const char * inq_product_rev = "0004";
448
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200449static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
450 int target_dev_id, int dev_id_num,
451 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400452 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400454 int num, port_a;
455 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400457 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 /* T10 vendor identifier field format (faked) */
459 arr[0] = 0x2; /* ASCII */
460 arr[1] = 0x1;
461 arr[2] = 0x0;
462 memcpy(&arr[4], inq_vendor_id, 8);
463 memcpy(&arr[12], inq_product_id, 16);
464 memcpy(&arr[28], dev_id_str, dev_id_str_len);
465 num = 8 + 16 + dev_id_str_len;
466 arr[3] = num;
467 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400468 if (dev_id_num >= 0) {
469 /* NAA-5, Logical unit identifier (binary) */
470 arr[num++] = 0x1; /* binary (not necessarily sas) */
471 arr[num++] = 0x3; /* PIV=0, lu, naa */
472 arr[num++] = 0x0;
473 arr[num++] = 0x8;
474 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
475 arr[num++] = 0x33;
476 arr[num++] = 0x33;
477 arr[num++] = 0x30;
478 arr[num++] = (dev_id_num >> 24);
479 arr[num++] = (dev_id_num >> 16) & 0xff;
480 arr[num++] = (dev_id_num >> 8) & 0xff;
481 arr[num++] = dev_id_num & 0xff;
482 /* Target relative port number */
483 arr[num++] = 0x61; /* proto=sas, binary */
484 arr[num++] = 0x94; /* PIV=1, target port, rel port */
485 arr[num++] = 0x0; /* reserved */
486 arr[num++] = 0x4; /* length */
487 arr[num++] = 0x0; /* reserved */
488 arr[num++] = 0x0; /* reserved */
489 arr[num++] = 0x0;
490 arr[num++] = 0x1; /* relative port A */
491 }
492 /* NAA-5, Target port identifier */
493 arr[num++] = 0x61; /* proto=sas, binary */
494 arr[num++] = 0x93; /* piv=1, target port, 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++] = (port_a >> 24);
502 arr[num++] = (port_a >> 16) & 0xff;
503 arr[num++] = (port_a >> 8) & 0xff;
504 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200505 /* NAA-5, Target port group identifier */
506 arr[num++] = 0x61; /* proto=sas, binary */
507 arr[num++] = 0x95; /* piv=1, target port group id */
508 arr[num++] = 0x0;
509 arr[num++] = 0x4;
510 arr[num++] = 0;
511 arr[num++] = 0;
512 arr[num++] = (port_group_id >> 8) & 0xff;
513 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400514 /* NAA-5, Target device identifier */
515 arr[num++] = 0x61; /* proto=sas, binary */
516 arr[num++] = 0xa3; /* piv=1, target device, naa */
517 arr[num++] = 0x0;
518 arr[num++] = 0x8;
519 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
520 arr[num++] = 0x22;
521 arr[num++] = 0x22;
522 arr[num++] = 0x20;
523 arr[num++] = (target_dev_id >> 24);
524 arr[num++] = (target_dev_id >> 16) & 0xff;
525 arr[num++] = (target_dev_id >> 8) & 0xff;
526 arr[num++] = target_dev_id & 0xff;
527 /* SCSI name string: Target device identifier */
528 arr[num++] = 0x63; /* proto=sas, UTF-8 */
529 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
530 arr[num++] = 0x0;
531 arr[num++] = 24;
532 memcpy(arr + num, "naa.52222220", 12);
533 num += 12;
534 snprintf(b, sizeof(b), "%08X", target_dev_id);
535 memcpy(arr + num, b, 8);
536 num += 8;
537 memset(arr + num, 0, 4);
538 num += 4;
539 return num;
540}
541
542
543static unsigned char vpd84_data[] = {
544/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
545 0x22,0x22,0x22,0x0,0xbb,0x1,
546 0x22,0x22,0x22,0x0,0xbb,0x2,
547};
548
549static int inquiry_evpd_84(unsigned char * arr)
550{
551 memcpy(arr, vpd84_data, sizeof(vpd84_data));
552 return sizeof(vpd84_data);
553}
554
555static int inquiry_evpd_85(unsigned char * arr)
556{
557 int num = 0;
558 const char * na1 = "https://www.kernel.org/config";
559 const char * na2 = "http://www.kernel.org/log";
560 int plen, olen;
561
562 arr[num++] = 0x1; /* lu, storage config */
563 arr[num++] = 0x0; /* reserved */
564 arr[num++] = 0x0;
565 olen = strlen(na1);
566 plen = olen + 1;
567 if (plen % 4)
568 plen = ((plen / 4) + 1) * 4;
569 arr[num++] = plen; /* length, null termianted, padded */
570 memcpy(arr + num, na1, olen);
571 memset(arr + num + olen, 0, plen - olen);
572 num += plen;
573
574 arr[num++] = 0x4; /* lu, logging */
575 arr[num++] = 0x0; /* reserved */
576 arr[num++] = 0x0;
577 olen = strlen(na2);
578 plen = olen + 1;
579 if (plen % 4)
580 plen = ((plen / 4) + 1) * 4;
581 arr[num++] = plen; /* length, null terminated, padded */
582 memcpy(arr + num, na2, olen);
583 memset(arr + num + olen, 0, plen - olen);
584 num += plen;
585
586 return num;
587}
588
589/* SCSI ports VPD page */
590static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
591{
592 int num = 0;
593 int port_a, port_b;
594
595 port_a = target_dev_id + 1;
596 port_b = port_a + 1;
597 arr[num++] = 0x0; /* reserved */
598 arr[num++] = 0x0; /* reserved */
599 arr[num++] = 0x0;
600 arr[num++] = 0x1; /* relative port 1 (primary) */
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 (A) */
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_a >> 24);
615 arr[num++] = (port_a >> 16) & 0xff;
616 arr[num++] = (port_a >> 8) & 0xff;
617 arr[num++] = port_a & 0xff;
618
619 arr[num++] = 0x0; /* reserved */
620 arr[num++] = 0x0; /* reserved */
621 arr[num++] = 0x0;
622 arr[num++] = 0x2; /* relative port 2 (secondary) */
623 memset(arr + num, 0, 6);
624 num += 6;
625 arr[num++] = 0x0;
626 arr[num++] = 12; /* length tp descriptor */
627 /* naa-5 target port identifier (B) */
628 arr[num++] = 0x61; /* proto=sas, binary */
629 arr[num++] = 0x93; /* PIV=1, target port, NAA */
630 arr[num++] = 0x0; /* reserved */
631 arr[num++] = 0x8; /* length */
632 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
633 arr[num++] = 0x22;
634 arr[num++] = 0x22;
635 arr[num++] = 0x20;
636 arr[num++] = (port_b >> 24);
637 arr[num++] = (port_b >> 16) & 0xff;
638 arr[num++] = (port_b >> 8) & 0xff;
639 arr[num++] = port_b & 0xff;
640
641 return num;
642}
643
644
645static unsigned char vpd89_data[] = {
646/* from 4th byte */ 0,0,0,0,
647'l','i','n','u','x',' ',' ',' ',
648'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
649'1','2','3','4',
6500x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6510xec,0,0,0,
6520x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6530,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6540x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6550x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6560x53,0x41,
6570x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6580x20,0x20,
6590x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6600x10,0x80,
6610,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6620x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6630x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6640,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6650x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6660x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6670,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6690,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6710x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6720,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6730xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6740,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6760,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6770,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6860,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
687};
688
689static int inquiry_evpd_89(unsigned char * arr)
690{
691 memcpy(arr, vpd89_data, sizeof(vpd89_data));
692 return sizeof(vpd89_data);
693}
694
695
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400696/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400697static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400698 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
699 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
700 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
701 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400702};
703
704static int inquiry_evpd_b0(unsigned char * arr)
705{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400706 unsigned int gran;
707
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400708 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400709
710 /* Optimal transfer length granularity */
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400711 gran = 1 << scsi_debug_physblk_exp;
712 arr[2] = (gran >> 8) & 0xff;
713 arr[3] = gran & 0xff;
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400714
715 /* Maximum Transfer Length */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400716 if (sdebug_store_sectors > 0x400) {
717 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
718 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
719 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
720 arr[7] = sdebug_store_sectors & 0xff;
721 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400722
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400723 /* Optimal Transfer Length */
724 put_unaligned_be32(scsi_debug_opt_blks, &arr[8]);
725
Martin K. Petersen44d92692009-10-15 14:45:27 -0400726 if (scsi_debug_unmap_max_desc) {
727 unsigned int blocks;
728
729 if (scsi_debug_unmap_max_blocks)
730 blocks = scsi_debug_unmap_max_blocks;
731 else
732 blocks = 0xffffffff;
733
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400734 /* Maximum Unmap LBA Count */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400735 put_unaligned_be32(blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400736
737 /* Maximum Unmap Block Descriptor Count */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400738 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
739 }
740
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400741 /* Unmap Granularity Alignment */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400742 if (scsi_debug_unmap_alignment) {
743 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
744 arr[28] |= 0x80; /* UGAVALID */
745 }
746
Martin K. Petersene308b3d2010-03-23 01:12:27 -0400747 /* Optimal Unmap Granularity */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400748 if (scsi_debug_unmap_granularity) {
749 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
750 return 0x3c; /* Mandatory page length for thin provisioning */
751 }
752
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400753 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754}
755
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400756/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600757static int inquiry_evpd_b1(unsigned char *arr)
758{
759 memset(arr, 0, 0x3c);
760 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400761 arr[1] = 1; /* non rotating medium (e.g. solid state) */
762 arr[2] = 0;
763 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600764
765 return 0x3c;
766}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
768#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400769#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
771static int resp_inquiry(struct scsi_cmnd * scp, int target,
772 struct sdebug_dev_info * devip)
773{
774 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200775 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200777 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
779 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500780 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
781 if (! arr)
782 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400783 if (devip->wlun)
784 pq_pdt = 0x1e; /* present, wlun */
785 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
786 pq_pdt = 0x7f; /* not present, no device type */
787 else
788 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 arr[0] = pq_pdt;
790 if (0x2 & cmd[1]) { /* CMDDT bit set */
791 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
792 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200793 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return check_condition_result;
795 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200796 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400797 char lu_id_str[6];
798 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200800 port_group_id = (((host_no + 1) & 0x7f) << 8) +
801 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400802 if (0 == scsi_debug_vpd_use_hostno)
803 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400804 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
805 (devip->target * 1000) + devip->lun);
806 target_dev_id = ((host_no + 1) * 2000) +
807 (devip->target * 1000) - 3;
808 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400810 arr[1] = cmd[2]; /*sanity */
811 n = 4;
812 arr[n++] = 0x0; /* this page */
813 arr[n++] = 0x80; /* unit serial number */
814 arr[n++] = 0x83; /* device identification */
815 arr[n++] = 0x84; /* software interface ident. */
816 arr[n++] = 0x85; /* management network addresses */
817 arr[n++] = 0x86; /* extended inquiry */
818 arr[n++] = 0x87; /* mode page policy */
819 arr[n++] = 0x88; /* SCSI ports */
820 arr[n++] = 0x89; /* ATA information */
821 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600822 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400823 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400825 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400827 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400829 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200830 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
831 target_dev_id, lu_id_num,
832 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400833 } else if (0x84 == cmd[2]) { /* Software interface ident. */
834 arr[1] = cmd[2]; /*sanity */
835 arr[3] = inquiry_evpd_84(&arr[4]);
836 } else if (0x85 == cmd[2]) { /* Management network addresses */
837 arr[1] = cmd[2]; /*sanity */
838 arr[3] = inquiry_evpd_85(&arr[4]);
839 } else if (0x86 == cmd[2]) { /* extended inquiry */
840 arr[1] = cmd[2]; /*sanity */
841 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500842 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
843 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
844 else if (scsi_debug_dif)
845 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
846 else
847 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400848 arr[5] = 0x7; /* head of q, ordered + simple q's */
849 } else if (0x87 == cmd[2]) { /* mode page policy */
850 arr[1] = cmd[2]; /*sanity */
851 arr[3] = 0x8; /* number of following entries */
852 arr[4] = 0x2; /* disconnect-reconnect mp */
853 arr[6] = 0x80; /* mlus, shared */
854 arr[8] = 0x18; /* protocol specific lu */
855 arr[10] = 0x82; /* mlus, per initiator port */
856 } else if (0x88 == cmd[2]) { /* SCSI Ports */
857 arr[1] = cmd[2]; /*sanity */
858 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
859 } else if (0x89 == cmd[2]) { /* ATA information */
860 arr[1] = cmd[2]; /*sanity */
861 n = inquiry_evpd_89(&arr[4]);
862 arr[2] = (n >> 8);
863 arr[3] = (n & 0xff);
864 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
865 arr[1] = cmd[2]; /*sanity */
866 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600867 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
868 arr[1] = cmd[2]; /*sanity */
869 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 } else {
871 /* Illegal request, invalid field in cdb */
872 mk_sense_buffer(devip, ILLEGAL_REQUEST,
873 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200874 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 return check_condition_result;
876 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400877 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200878 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400879 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200880 kfree(arr);
881 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
883 /* drops through here for a standard inquiry */
884 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
885 arr[2] = scsi_debug_scsi_level;
886 arr[3] = 2; /* response_data_format==2 */
887 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500888 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200889 if (0 == scsi_debug_vpd_use_hostno)
890 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400891 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400893 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 memcpy(&arr[8], inq_vendor_id, 8);
895 memcpy(&arr[16], inq_product_id, 16);
896 memcpy(&arr[32], inq_product_rev, 4);
897 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400898 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
899 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
900 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400902 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400904 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400906 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200907 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200909 kfree(arr);
910 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911}
912
913static int resp_requests(struct scsi_cmnd * scp,
914 struct sdebug_dev_info * devip)
915{
916 unsigned char * sbuff;
917 unsigned char *cmd = (unsigned char *)scp->cmnd;
918 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400919 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 int len = 18;
921
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400922 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400924 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
925 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400927 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
928 if (want_dsense) {
929 arr[0] = 0x72;
930 arr[1] = 0x0; /* NO_SENSE in sense_key */
931 arr[2] = THRESHOLD_EXCEEDED;
932 arr[3] = 0xff; /* TEST set and MRIE==6 */
933 } else {
934 arr[0] = 0x70;
935 arr[2] = 0x0; /* NO_SENSE in sense_key */
936 arr[7] = 0xa; /* 18 byte sense buffer */
937 arr[12] = THRESHOLD_EXCEEDED;
938 arr[13] = 0xff; /* TEST set and MRIE==6 */
939 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400940 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400942 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
943 /* DESC bit set and sense_buff in fixed format */
944 memset(arr, 0, sizeof(arr));
945 arr[0] = 0x72;
946 arr[1] = sbuff[2]; /* sense key */
947 arr[2] = sbuff[12]; /* asc */
948 arr[3] = sbuff[13]; /* ascq */
949 len = 8;
950 }
951 }
952 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 return fill_from_dev_buffer(scp, arr, len);
954}
955
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400956static int resp_start_stop(struct scsi_cmnd * scp,
957 struct sdebug_dev_info * devip)
958{
959 unsigned char *cmd = (unsigned char *)scp->cmnd;
960 int power_cond, errsts, start;
961
962 if ((errsts = check_readiness(scp, 1, devip)))
963 return errsts;
964 power_cond = (cmd[4] & 0xf0) >> 4;
965 if (power_cond) {
966 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
967 0);
968 return check_condition_result;
969 }
970 start = cmd[4] & 1;
971 if (start == devip->stopped)
972 devip->stopped = !start;
973 return 0;
974}
975
FUJITA Tomonori28898872008-03-30 00:59:55 +0900976static sector_t get_sdebug_capacity(void)
977{
978 if (scsi_debug_virtual_gb > 0)
FUJITA Tomonori73da9c12009-04-22 17:42:25 -0700979 return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
FUJITA Tomonori28898872008-03-30 00:59:55 +0900980 else
981 return sdebug_store_sectors;
982}
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984#define SDEBUG_READCAP_ARR_SZ 8
985static int resp_readcap(struct scsi_cmnd * scp,
986 struct sdebug_dev_info * devip)
987{
988 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400989 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 int errsts;
991
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400992 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400994 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900995 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400997 if (sdebug_capacity < 0xffffffff) {
998 capac = (unsigned int)sdebug_capacity - 1;
999 arr[0] = (capac >> 24);
1000 arr[1] = (capac >> 16) & 0xff;
1001 arr[2] = (capac >> 8) & 0xff;
1002 arr[3] = capac & 0xff;
1003 } else {
1004 arr[0] = 0xff;
1005 arr[1] = 0xff;
1006 arr[2] = 0xff;
1007 arr[3] = 0xff;
1008 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001009 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
1010 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1012}
1013
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001014#define SDEBUG_READCAP16_ARR_SZ 32
1015static int resp_readcap16(struct scsi_cmnd * scp,
1016 struct sdebug_dev_info * devip)
1017{
1018 unsigned char *cmd = (unsigned char *)scp->cmnd;
1019 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1020 unsigned long long capac;
1021 int errsts, k, alloc_len;
1022
1023 if ((errsts = check_readiness(scp, 1, devip)))
1024 return errsts;
1025 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1026 + cmd[13]);
1027 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001028 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001029 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1030 capac = sdebug_capacity - 1;
1031 for (k = 0; k < 8; ++k, capac >>= 8)
1032 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001033 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1034 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1035 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1036 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001037 arr[13] = scsi_debug_physblk_exp & 0xf;
1038 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001039
1040 if (scsi_debug_unmap_granularity)
1041 arr[14] |= 0x80; /* TPE */
1042
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001043 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001044
1045 if (scsi_debug_dif) {
1046 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1047 arr[12] |= 1; /* PROT_EN */
1048 }
1049
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001050 return fill_from_dev_buffer(scp, arr,
1051 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1052}
1053
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001054#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1055
1056static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1057 struct sdebug_dev_info * devip)
1058{
1059 unsigned char *cmd = (unsigned char *)scp->cmnd;
1060 unsigned char * arr;
1061 int host_no = devip->sdbg_host->shost->host_no;
1062 int n, ret, alen, rlen;
1063 int port_group_a, port_group_b, port_a, port_b;
1064
1065 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1066 + cmd[9]);
1067
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001068 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1069 if (! arr)
1070 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001071 /*
1072 * EVPD page 0x88 states we have two ports, one
1073 * real and a fake port with no device connected.
1074 * So we create two port groups with one port each
1075 * and set the group with port B to unavailable.
1076 */
1077 port_a = 0x1; /* relative port A */
1078 port_b = 0x2; /* relative port B */
1079 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1080 (devip->channel & 0x7f);
1081 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1082 (devip->channel & 0x7f) + 0x80;
1083
1084 /*
1085 * The asymmetric access state is cycled according to the host_id.
1086 */
1087 n = 4;
1088 if (0 == scsi_debug_vpd_use_hostno) {
1089 arr[n++] = host_no % 3; /* Asymm access state */
1090 arr[n++] = 0x0F; /* claim: all states are supported */
1091 } else {
1092 arr[n++] = 0x0; /* Active/Optimized path */
1093 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1094 }
1095 arr[n++] = (port_group_a >> 8) & 0xff;
1096 arr[n++] = port_group_a & 0xff;
1097 arr[n++] = 0; /* Reserved */
1098 arr[n++] = 0; /* Status code */
1099 arr[n++] = 0; /* Vendor unique */
1100 arr[n++] = 0x1; /* One port per group */
1101 arr[n++] = 0; /* Reserved */
1102 arr[n++] = 0; /* Reserved */
1103 arr[n++] = (port_a >> 8) & 0xff;
1104 arr[n++] = port_a & 0xff;
1105 arr[n++] = 3; /* Port unavailable */
1106 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1107 arr[n++] = (port_group_b >> 8) & 0xff;
1108 arr[n++] = port_group_b & 0xff;
1109 arr[n++] = 0; /* Reserved */
1110 arr[n++] = 0; /* Status code */
1111 arr[n++] = 0; /* Vendor unique */
1112 arr[n++] = 0x1; /* One port per group */
1113 arr[n++] = 0; /* Reserved */
1114 arr[n++] = 0; /* Reserved */
1115 arr[n++] = (port_b >> 8) & 0xff;
1116 arr[n++] = port_b & 0xff;
1117
1118 rlen = n - 4;
1119 arr[0] = (rlen >> 24) & 0xff;
1120 arr[1] = (rlen >> 16) & 0xff;
1121 arr[2] = (rlen >> 8) & 0xff;
1122 arr[3] = rlen & 0xff;
1123
1124 /*
1125 * Return the smallest value of either
1126 * - The allocated length
1127 * - The constructed command length
1128 * - The maximum array size
1129 */
1130 rlen = min(alen,n);
1131 ret = fill_from_dev_buffer(scp, arr,
1132 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1133 kfree(arr);
1134 return ret;
1135}
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137/* <<Following mode page info copied from ST318451LW>> */
1138
1139static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1140{ /* Read-Write Error Recovery page for mode_sense */
1141 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1142 5, 0, 0xff, 0xff};
1143
1144 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1145 if (1 == pcontrol)
1146 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1147 return sizeof(err_recov_pg);
1148}
1149
1150static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1151{ /* Disconnect-Reconnect page for mode_sense */
1152 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1153 0, 0, 0, 0, 0, 0, 0, 0};
1154
1155 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1156 if (1 == pcontrol)
1157 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1158 return sizeof(disconnect_pg);
1159}
1160
1161static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1162{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001163 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1164 0, 0, 0, 0, 0, 0, 0, 0,
1165 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Martin K. Petersen597136a2008-06-05 00:12:59 -04001167 memcpy(p, format_pg, sizeof(format_pg));
1168 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1169 p[11] = sdebug_sectors_per & 0xff;
1170 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1171 p[13] = scsi_debug_sector_size & 0xff;
1172 if (DEV_REMOVEABLE(target))
1173 p[20] |= 0x20; /* should agree with INQUIRY */
1174 if (1 == pcontrol)
1175 memset(p + 2, 0, sizeof(format_pg) - 2);
1176 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177}
1178
1179static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1180{ /* Caching page for mode_sense */
1181 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1182 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1183
1184 memcpy(p, caching_pg, sizeof(caching_pg));
1185 if (1 == pcontrol)
1186 memset(p + 2, 0, sizeof(caching_pg) - 2);
1187 return sizeof(caching_pg);
1188}
1189
1190static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1191{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001192 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1193 0, 0, 0, 0};
1194 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 0, 0, 0x2, 0x4b};
1196
1197 if (scsi_debug_dsense)
1198 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001199 else
1200 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001201
1202 if (scsi_debug_ato)
1203 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1206 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001207 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1208 else if (2 == pcontrol)
1209 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 return sizeof(ctrl_m_pg);
1211}
1212
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1215{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001216 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1217 0, 0, 0x0, 0x0};
1218 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1219 0, 0, 0x0, 0x0};
1220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1222 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001223 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1224 else if (2 == pcontrol)
1225 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 return sizeof(iec_m_pg);
1227}
1228
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001229static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1230{ /* SAS SSP mode page - short format for mode_sense */
1231 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1232 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1233
1234 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1235 if (1 == pcontrol)
1236 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1237 return sizeof(sas_sf_m_pg);
1238}
1239
1240
1241static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1242 int target_dev_id)
1243{ /* SAS phy control and discover mode page for mode_sense */
1244 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1245 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1246 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1247 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1248 0x2, 0, 0, 0, 0, 0, 0, 0,
1249 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1250 0, 0, 0, 0, 0, 0, 0, 0,
1251 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1252 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1253 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1254 0x3, 0, 0, 0, 0, 0, 0, 0,
1255 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1256 0, 0, 0, 0, 0, 0, 0, 0,
1257 };
1258 int port_a, port_b;
1259
1260 port_a = target_dev_id + 1;
1261 port_b = port_a + 1;
1262 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1263 p[20] = (port_a >> 24);
1264 p[21] = (port_a >> 16) & 0xff;
1265 p[22] = (port_a >> 8) & 0xff;
1266 p[23] = port_a & 0xff;
1267 p[48 + 20] = (port_b >> 24);
1268 p[48 + 21] = (port_b >> 16) & 0xff;
1269 p[48 + 22] = (port_b >> 8) & 0xff;
1270 p[48 + 23] = port_b & 0xff;
1271 if (1 == pcontrol)
1272 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1273 return sizeof(sas_pcd_m_pg);
1274}
1275
1276static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1277{ /* SAS SSP shared protocol specific port mode subpage */
1278 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1279 0, 0, 0, 0, 0, 0, 0, 0,
1280 };
1281
1282 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1283 if (1 == pcontrol)
1284 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1285 return sizeof(sas_sha_m_pg);
1286}
1287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288#define SDEBUG_MAX_MSENSE_SZ 256
1289
1290static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1291 struct sdebug_dev_info * devip)
1292{
Douglas Gilbert23183912006-09-16 20:30:47 -04001293 unsigned char dbd, llbaa;
1294 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001296 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 unsigned char * ap;
1298 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1299 unsigned char *cmd = (unsigned char *)scp->cmnd;
1300
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001301 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001303 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 pcontrol = (cmd[2] & 0xc0) >> 6;
1305 pcode = cmd[2] & 0x3f;
1306 subpcode = cmd[3];
1307 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001308 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1309 if ((0 == scsi_debug_ptype) && (0 == dbd))
1310 bd_len = llbaa ? 16 : 8;
1311 else
1312 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1314 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1315 if (0x3 == pcontrol) { /* Saving values not supported */
1316 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1317 0);
1318 return check_condition_result;
1319 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001320 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1321 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001322 /* set DPOFUA bit for disks */
1323 if (0 == scsi_debug_ptype)
1324 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1325 else
1326 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 if (msense_6) {
1328 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001329 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 offset = 4;
1331 } else {
1332 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001333 if (16 == bd_len)
1334 arr[4] = 0x1; /* set LONGLBA bit */
1335 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 offset = 8;
1337 }
1338 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001339 if ((bd_len > 0) && (!sdebug_capacity))
1340 sdebug_capacity = get_sdebug_capacity();
1341
Douglas Gilbert23183912006-09-16 20:30:47 -04001342 if (8 == bd_len) {
1343 if (sdebug_capacity > 0xfffffffe) {
1344 ap[0] = 0xff;
1345 ap[1] = 0xff;
1346 ap[2] = 0xff;
1347 ap[3] = 0xff;
1348 } else {
1349 ap[0] = (sdebug_capacity >> 24) & 0xff;
1350 ap[1] = (sdebug_capacity >> 16) & 0xff;
1351 ap[2] = (sdebug_capacity >> 8) & 0xff;
1352 ap[3] = sdebug_capacity & 0xff;
1353 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001354 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1355 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001356 offset += bd_len;
1357 ap = arr + offset;
1358 } else if (16 == bd_len) {
1359 unsigned long long capac = sdebug_capacity;
1360
1361 for (k = 0; k < 8; ++k, capac >>= 8)
1362 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001363 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1364 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1365 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1366 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001367 offset += bd_len;
1368 ap = arr + offset;
1369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001371 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1372 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1374 0);
1375 return check_condition_result;
1376 }
1377 switch (pcode) {
1378 case 0x1: /* Read-Write error recovery page, direct access */
1379 len = resp_err_recov_pg(ap, pcontrol, target);
1380 offset += len;
1381 break;
1382 case 0x2: /* Disconnect-Reconnect page, all devices */
1383 len = resp_disconnect_pg(ap, pcontrol, target);
1384 offset += len;
1385 break;
1386 case 0x3: /* Format device page, direct access */
1387 len = resp_format_pg(ap, pcontrol, target);
1388 offset += len;
1389 break;
1390 case 0x8: /* Caching page, direct access */
1391 len = resp_caching_pg(ap, pcontrol, target);
1392 offset += len;
1393 break;
1394 case 0xa: /* Control Mode page, all devices */
1395 len = resp_ctrl_m_pg(ap, pcontrol, target);
1396 offset += len;
1397 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001398 case 0x19: /* if spc==1 then sas phy, control+discover */
1399 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1400 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1401 INVALID_FIELD_IN_CDB, 0);
1402 return check_condition_result;
1403 }
1404 len = 0;
1405 if ((0x0 == subpcode) || (0xff == subpcode))
1406 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1407 if ((0x1 == subpcode) || (0xff == subpcode))
1408 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1409 target_dev_id);
1410 if ((0x2 == subpcode) || (0xff == subpcode))
1411 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1412 offset += len;
1413 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 case 0x1c: /* Informational Exceptions Mode page, all devices */
1415 len = resp_iec_m_pg(ap, pcontrol, target);
1416 offset += len;
1417 break;
1418 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001419 if ((0 == subpcode) || (0xff == subpcode)) {
1420 len = resp_err_recov_pg(ap, pcontrol, target);
1421 len += resp_disconnect_pg(ap + len, pcontrol, target);
1422 len += resp_format_pg(ap + len, pcontrol, target);
1423 len += resp_caching_pg(ap + len, pcontrol, target);
1424 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1425 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1426 if (0xff == subpcode) {
1427 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1428 target, target_dev_id);
1429 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1430 }
1431 len += resp_iec_m_pg(ap + len, pcontrol, target);
1432 } else {
1433 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1434 INVALID_FIELD_IN_CDB, 0);
1435 return check_condition_result;
1436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 offset += len;
1438 break;
1439 default:
1440 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1441 0);
1442 return check_condition_result;
1443 }
1444 if (msense_6)
1445 arr[0] = offset - 1;
1446 else {
1447 arr[0] = ((offset - 2) >> 8) & 0xff;
1448 arr[1] = (offset - 2) & 0xff;
1449 }
1450 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1451}
1452
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001453#define SDEBUG_MAX_MSELECT_SZ 512
1454
1455static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1456 struct sdebug_dev_info * devip)
1457{
1458 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1459 int param_len, res, errsts, mpage;
1460 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1461 unsigned char *cmd = (unsigned char *)scp->cmnd;
1462
1463 if ((errsts = check_readiness(scp, 1, devip)))
1464 return errsts;
1465 memset(arr, 0, sizeof(arr));
1466 pf = cmd[1] & 0x10;
1467 sp = cmd[1] & 0x1;
1468 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1469 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1470 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1471 INVALID_FIELD_IN_CDB, 0);
1472 return check_condition_result;
1473 }
1474 res = fetch_to_dev_buffer(scp, arr, param_len);
1475 if (-1 == res)
1476 return (DID_ERROR << 16);
1477 else if ((res < param_len) &&
1478 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1479 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1480 " IO sent=%d bytes\n", param_len, res);
1481 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1482 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001483 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1485 INVALID_FIELD_IN_PARAM_LIST, 0);
1486 return check_condition_result;
1487 }
1488 off = bd_len + (mselect6 ? 4 : 8);
1489 mpage = arr[off] & 0x3f;
1490 ps = !!(arr[off] & 0x80);
1491 if (ps) {
1492 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1493 INVALID_FIELD_IN_PARAM_LIST, 0);
1494 return check_condition_result;
1495 }
1496 spf = !!(arr[off] & 0x40);
1497 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1498 (arr[off + 1] + 2);
1499 if ((pg_len + off) > param_len) {
1500 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1501 PARAMETER_LIST_LENGTH_ERR, 0);
1502 return check_condition_result;
1503 }
1504 switch (mpage) {
1505 case 0xa: /* Control Mode page */
1506 if (ctrl_m_pg[1] == arr[off + 1]) {
1507 memcpy(ctrl_m_pg + 2, arr + off + 2,
1508 sizeof(ctrl_m_pg) - 2);
1509 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1510 return 0;
1511 }
1512 break;
1513 case 0x1c: /* Informational Exceptions Mode page */
1514 if (iec_m_pg[1] == arr[off + 1]) {
1515 memcpy(iec_m_pg + 2, arr + off + 2,
1516 sizeof(iec_m_pg) - 2);
1517 return 0;
1518 }
1519 break;
1520 default:
1521 break;
1522 }
1523 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1524 INVALID_FIELD_IN_PARAM_LIST, 0);
1525 return check_condition_result;
1526}
1527
1528static int resp_temp_l_pg(unsigned char * arr)
1529{
1530 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1531 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1532 };
1533
1534 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1535 return sizeof(temp_l_pg);
1536}
1537
1538static int resp_ie_l_pg(unsigned char * arr)
1539{
1540 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1541 };
1542
1543 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1544 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1545 arr[4] = THRESHOLD_EXCEEDED;
1546 arr[5] = 0xff;
1547 }
1548 return sizeof(ie_l_pg);
1549}
1550
1551#define SDEBUG_MAX_LSENSE_SZ 512
1552
1553static int resp_log_sense(struct scsi_cmnd * scp,
1554 struct sdebug_dev_info * devip)
1555{
Douglas Gilbert23183912006-09-16 20:30:47 -04001556 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001557 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1558 unsigned char *cmd = (unsigned char *)scp->cmnd;
1559
1560 if ((errsts = check_readiness(scp, 1, devip)))
1561 return errsts;
1562 memset(arr, 0, sizeof(arr));
1563 ppc = cmd[1] & 0x2;
1564 sp = cmd[1] & 0x1;
1565 if (ppc || sp) {
1566 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1567 INVALID_FIELD_IN_CDB, 0);
1568 return check_condition_result;
1569 }
1570 pcontrol = (cmd[2] & 0xc0) >> 6;
1571 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001572 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001573 alloc_len = (cmd[7] << 8) + cmd[8];
1574 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001575 if (0 == subpcode) {
1576 switch (pcode) {
1577 case 0x0: /* Supported log pages log page */
1578 n = 4;
1579 arr[n++] = 0x0; /* this page */
1580 arr[n++] = 0xd; /* Temperature */
1581 arr[n++] = 0x2f; /* Informational exceptions */
1582 arr[3] = n - 4;
1583 break;
1584 case 0xd: /* Temperature log page */
1585 arr[3] = resp_temp_l_pg(arr + 4);
1586 break;
1587 case 0x2f: /* Informational exceptions log page */
1588 arr[3] = resp_ie_l_pg(arr + 4);
1589 break;
1590 default:
1591 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1592 INVALID_FIELD_IN_CDB, 0);
1593 return check_condition_result;
1594 }
1595 } else if (0xff == subpcode) {
1596 arr[0] |= 0x40;
1597 arr[1] = subpcode;
1598 switch (pcode) {
1599 case 0x0: /* Supported log pages and subpages log page */
1600 n = 4;
1601 arr[n++] = 0x0;
1602 arr[n++] = 0x0; /* 0,0 page */
1603 arr[n++] = 0x0;
1604 arr[n++] = 0xff; /* this page */
1605 arr[n++] = 0xd;
1606 arr[n++] = 0x0; /* Temperature */
1607 arr[n++] = 0x2f;
1608 arr[n++] = 0x0; /* Informational exceptions */
1609 arr[3] = n - 4;
1610 break;
1611 case 0xd: /* Temperature subpages */
1612 n = 4;
1613 arr[n++] = 0xd;
1614 arr[n++] = 0x0; /* Temperature */
1615 arr[3] = n - 4;
1616 break;
1617 case 0x2f: /* Informational exceptions subpages */
1618 n = 4;
1619 arr[n++] = 0x2f;
1620 arr[n++] = 0x0; /* Informational exceptions */
1621 arr[3] = n - 4;
1622 break;
1623 default:
1624 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1625 INVALID_FIELD_IN_CDB, 0);
1626 return check_condition_result;
1627 }
1628 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001629 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1630 INVALID_FIELD_IN_CDB, 0);
1631 return check_condition_result;
1632 }
1633 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1634 return fill_from_dev_buffer(scp, arr,
1635 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1636}
1637
FUJITA Tomonori19789102008-03-30 00:59:56 +09001638static int check_device_access_params(struct sdebug_dev_info *devi,
1639 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001641 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001642 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 return check_condition_result;
1644 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001645 /* transfer length excessive (tie in to block limits VPD page) */
1646 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001647 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001648 return check_condition_result;
1649 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001650 return 0;
1651}
1652
1653static int do_device_access(struct scsi_cmnd *scmd,
1654 struct sdebug_dev_info *devi,
1655 unsigned long long lba, unsigned int num, int write)
1656{
1657 int ret;
1658 unsigned int block, rest = 0;
1659 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1660
1661 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1662
1663 block = do_div(lba, sdebug_store_sectors);
1664 if (block + num > sdebug_store_sectors)
1665 rest = block + num - sdebug_store_sectors;
1666
Martin K. Petersen597136a2008-06-05 00:12:59 -04001667 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1668 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001669 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001670 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001671
1672 return ret;
1673}
1674
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001675static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001676 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001677{
1678 unsigned int i, resid;
1679 struct scatterlist *psgl;
1680 struct sd_dif_tuple *sdt;
1681 sector_t sector;
1682 sector_t tmp_sec = start_sec;
1683 void *paddr;
1684
1685 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1686
1687 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1688
1689 for (i = 0 ; i < sectors ; i++) {
1690 u16 csum;
1691
1692 if (sdt[i].app_tag == 0xffff)
1693 continue;
1694
1695 sector = start_sec + i;
1696
1697 switch (scsi_debug_guard) {
1698 case 1:
1699 csum = ip_compute_csum(fake_storep +
1700 sector * scsi_debug_sector_size,
1701 scsi_debug_sector_size);
1702 break;
1703 case 0:
1704 csum = crc_t10dif(fake_storep +
1705 sector * scsi_debug_sector_size,
1706 scsi_debug_sector_size);
1707 csum = cpu_to_be16(csum);
1708 break;
1709 default:
1710 BUG();
1711 }
1712
1713 if (sdt[i].guard_tag != csum) {
1714 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1715 " rcvd 0x%04x, data 0x%04x\n", __func__,
1716 (unsigned long)sector,
1717 be16_to_cpu(sdt[i].guard_tag),
1718 be16_to_cpu(csum));
1719 dif_errors++;
1720 return 0x01;
1721 }
1722
Martin K. Petersen395cef02009-09-18 17:33:03 -04001723 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001724 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1725 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1726 __func__, (unsigned long)sector);
1727 dif_errors++;
1728 return 0x03;
1729 }
Martin K. Petersen395cef02009-09-18 17:33:03 -04001730
1731 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1732 be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1733 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1734 __func__, (unsigned long)sector);
1735 dif_errors++;
1736 return 0x03;
1737 }
1738
1739 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001740 }
1741
1742 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1743 sector = start_sec;
1744
1745 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1746 int len = min(psgl->length, resid);
1747
1748 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1749 memcpy(paddr, dif_storep + dif_offset(sector), len);
1750
1751 sector += len >> 3;
1752 if (sector >= sdebug_store_sectors) {
1753 /* Force wrap */
1754 tmp_sec = sector;
1755 sector = do_div(tmp_sec, sdebug_store_sectors);
1756 }
1757 resid -= len;
1758 kunmap_atomic(paddr, KM_IRQ0);
1759 }
1760
1761 dix_reads++;
1762
1763 return 0;
1764}
1765
FUJITA Tomonori19789102008-03-30 00:59:56 +09001766static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001767 unsigned int num, struct sdebug_dev_info *devip,
1768 u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001769{
1770 unsigned long iflags;
1771 int ret;
1772
1773 ret = check_device_access_params(devip, lba, num);
1774 if (ret)
1775 return ret;
1776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001778 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1779 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1780 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1782 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001783 /* set info field and valid bit for fixed descriptor */
1784 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1785 devip->sense_buff[0] |= 0x80; /* Valid bit */
1786 ret = OPT_MEDIUM_ERR_ADDR;
1787 devip->sense_buff[3] = (ret >> 24) & 0xff;
1788 devip->sense_buff[4] = (ret >> 16) & 0xff;
1789 devip->sense_buff[5] = (ret >> 8) & 0xff;
1790 devip->sense_buff[6] = ret & 0xff;
1791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 return check_condition_result;
1793 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001794
1795 /* DIX + T10 DIF */
1796 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001797 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001798
1799 if (prot_ret) {
1800 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1801 return illegal_condition_result;
1802 }
1803 }
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001806 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 read_unlock_irqrestore(&atomic_rw, iflags);
1808 return ret;
1809}
1810
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001811void dump_sector(unsigned char *buf, int len)
1812{
1813 int i, j;
1814
1815 printk(KERN_ERR ">>> Sector Dump <<<\n");
1816
1817 for (i = 0 ; i < len ; i += 16) {
1818 printk(KERN_ERR "%04d: ", i);
1819
1820 for (j = 0 ; j < 16 ; j++) {
1821 unsigned char c = buf[i+j];
1822 if (c >= 0x20 && c < 0x7e)
1823 printk(" %c ", buf[i+j]);
1824 else
1825 printk("%02x ", buf[i+j]);
1826 }
1827
1828 printk("\n");
1829 }
1830}
1831
1832static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001833 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001834{
1835 int i, j, ret;
1836 struct sd_dif_tuple *sdt;
1837 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1838 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1839 void *daddr, *paddr;
1840 sector_t tmp_sec = start_sec;
1841 sector_t sector;
1842 int ppage_offset;
1843 unsigned short csum;
1844
1845 sector = do_div(tmp_sec, sdebug_store_sectors);
1846
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001847 BUG_ON(scsi_sg_count(SCpnt) == 0);
1848 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1849
1850 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1851 ppage_offset = 0;
1852
1853 /* For each data page */
1854 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1855 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1856
1857 /* For each sector-sized chunk in data page */
1858 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1859
1860 /* If we're at the end of the current
1861 * protection page advance to the next one
1862 */
1863 if (ppage_offset >= psgl->length) {
1864 kunmap_atomic(paddr, KM_IRQ1);
1865 psgl = sg_next(psgl);
1866 BUG_ON(psgl == NULL);
1867 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1868 + psgl->offset;
1869 ppage_offset = 0;
1870 }
1871
1872 sdt = paddr + ppage_offset;
1873
1874 switch (scsi_debug_guard) {
1875 case 1:
1876 csum = ip_compute_csum(daddr,
1877 scsi_debug_sector_size);
1878 break;
1879 case 0:
1880 csum = cpu_to_be16(crc_t10dif(daddr,
1881 scsi_debug_sector_size));
1882 break;
1883 default:
1884 BUG();
1885 ret = 0;
1886 goto out;
1887 }
1888
1889 if (sdt->guard_tag != csum) {
1890 printk(KERN_ERR
1891 "%s: GUARD check failed on sector %lu " \
1892 "rcvd 0x%04x, calculated 0x%04x\n",
1893 __func__, (unsigned long)sector,
1894 be16_to_cpu(sdt->guard_tag),
1895 be16_to_cpu(csum));
1896 ret = 0x01;
1897 dump_sector(daddr, scsi_debug_sector_size);
1898 goto out;
1899 }
1900
Martin K. Petersen395cef02009-09-18 17:33:03 -04001901 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001902 be32_to_cpu(sdt->ref_tag)
1903 != (start_sec & 0xffffffff)) {
1904 printk(KERN_ERR
1905 "%s: REF check failed on sector %lu\n",
1906 __func__, (unsigned long)sector);
1907 ret = 0x03;
1908 dump_sector(daddr, scsi_debug_sector_size);
1909 goto out;
1910 }
1911
Martin K. Petersen395cef02009-09-18 17:33:03 -04001912 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1913 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1914 printk(KERN_ERR
1915 "%s: REF check failed on sector %lu\n",
1916 __func__, (unsigned long)sector);
1917 ret = 0x03;
1918 dump_sector(daddr, scsi_debug_sector_size);
1919 goto out;
1920 }
1921
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001922 /* Would be great to copy this in bigger
1923 * chunks. However, for the sake of
1924 * correctness we need to verify each sector
1925 * before writing it to "stable" storage
1926 */
1927 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1928
1929 sector++;
1930
1931 if (sector == sdebug_store_sectors)
1932 sector = 0; /* Force wrap */
1933
1934 start_sec++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001935 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001936 daddr += scsi_debug_sector_size;
1937 ppage_offset += sizeof(struct sd_dif_tuple);
1938 }
1939
1940 kunmap_atomic(daddr, KM_IRQ0);
1941 }
1942
1943 kunmap_atomic(paddr, KM_IRQ1);
1944
1945 dix_writes++;
1946
1947 return 0;
1948
1949out:
1950 dif_errors++;
1951 kunmap_atomic(daddr, KM_IRQ0);
1952 kunmap_atomic(paddr, KM_IRQ1);
1953 return ret;
1954}
1955
Martin K. Petersen44d92692009-10-15 14:45:27 -04001956static unsigned int map_state(sector_t lba, unsigned int *num)
1957{
1958 unsigned int granularity, alignment, mapped;
1959 sector_t block, next, end;
1960
1961 granularity = scsi_debug_unmap_granularity;
1962 alignment = granularity - scsi_debug_unmap_alignment;
1963 block = lba + alignment;
1964 do_div(block, granularity);
1965
1966 mapped = test_bit(block, map_storep);
1967
1968 if (mapped)
1969 next = find_next_zero_bit(map_storep, map_size, block);
1970 else
1971 next = find_next_bit(map_storep, map_size, block);
1972
1973 end = next * granularity - scsi_debug_unmap_alignment;
1974 *num = end - lba;
1975
1976 return mapped;
1977}
1978
1979static void map_region(sector_t lba, unsigned int len)
1980{
1981 unsigned int granularity, alignment;
1982 sector_t end = lba + len;
1983
1984 granularity = scsi_debug_unmap_granularity;
1985 alignment = granularity - scsi_debug_unmap_alignment;
1986
1987 while (lba < end) {
1988 sector_t block, rem;
1989
1990 block = lba + alignment;
1991 rem = do_div(block, granularity);
1992
1993 set_bit(block, map_storep);
1994
1995 lba += granularity - rem;
1996 }
1997}
1998
1999static void unmap_region(sector_t lba, unsigned int len)
2000{
2001 unsigned int granularity, alignment;
2002 sector_t end = lba + len;
2003
2004 granularity = scsi_debug_unmap_granularity;
2005 alignment = granularity - scsi_debug_unmap_alignment;
2006
2007 while (lba < end) {
2008 sector_t block, rem;
2009
2010 block = lba + alignment;
2011 rem = do_div(block, granularity);
2012
2013 if (rem == 0 && lba + granularity <= end)
2014 clear_bit(block, map_storep);
2015
2016 lba += granularity - rem;
2017 }
2018}
2019
FUJITA Tomonori19789102008-03-30 00:59:56 +09002020static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002021 unsigned int num, struct sdebug_dev_info *devip,
2022 u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023{
2024 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002025 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
FUJITA Tomonori19789102008-03-30 00:59:56 +09002027 ret = check_device_access_params(devip, lba, num);
2028 if (ret)
2029 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002031 /* DIX + T10 DIF */
2032 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002033 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002034
2035 if (prot_ret) {
2036 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2037 return illegal_condition_result;
2038 }
2039 }
2040
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002042 ret = do_device_access(SCpnt, devip, lba, num, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002043 if (scsi_debug_unmap_granularity)
2044 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002046 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002048 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002050 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04002051 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002052
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 return 0;
2054}
2055
Martin K. Petersen44d92692009-10-15 14:45:27 -04002056static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
2057 unsigned int num, struct sdebug_dev_info *devip,
2058 u32 ei_lba, unsigned int unmap)
2059{
2060 unsigned long iflags;
2061 unsigned long long i;
2062 int ret;
2063
2064 ret = check_device_access_params(devip, lba, num);
2065 if (ret)
2066 return ret;
2067
2068 write_lock_irqsave(&atomic_rw, iflags);
2069
2070 if (unmap && scsi_debug_unmap_granularity) {
2071 unmap_region(lba, num);
2072 goto out;
2073 }
2074
2075 /* Else fetch one logical block */
2076 ret = fetch_to_dev_buffer(scmd,
2077 fake_storep + (lba * scsi_debug_sector_size),
2078 scsi_debug_sector_size);
2079
2080 if (-1 == ret) {
2081 write_unlock_irqrestore(&atomic_rw, iflags);
2082 return (DID_ERROR << 16);
2083 } else if ((ret < (num * scsi_debug_sector_size)) &&
2084 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2085 printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
2086 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
2087
2088 /* Copy first sector to remaining blocks */
2089 for (i = 1 ; i < num ; i++)
2090 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2091 fake_storep + (lba * scsi_debug_sector_size),
2092 scsi_debug_sector_size);
2093
2094 if (scsi_debug_unmap_granularity)
2095 map_region(lba, num);
2096out:
2097 write_unlock_irqrestore(&atomic_rw, iflags);
2098
2099 return 0;
2100}
2101
2102struct unmap_block_desc {
2103 __be64 lba;
2104 __be32 blocks;
2105 __be32 __reserved;
2106};
2107
2108static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2109{
2110 unsigned char *buf;
2111 struct unmap_block_desc *desc;
2112 unsigned int i, payload_len, descriptors;
2113 int ret;
2114
2115 ret = check_readiness(scmd, 1, devip);
2116 if (ret)
2117 return ret;
2118
2119 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2120 BUG_ON(scsi_bufflen(scmd) != payload_len);
2121
2122 descriptors = (payload_len - 8) / 16;
2123
2124 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2125 if (!buf)
2126 return check_condition_result;
2127
2128 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2129
2130 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2131 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2132
2133 desc = (void *)&buf[8];
2134
2135 for (i = 0 ; i < descriptors ; i++) {
2136 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2137 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2138
2139 ret = check_device_access_params(devip, lba, num);
2140 if (ret)
2141 goto out;
2142
2143 unmap_region(lba, num);
2144 }
2145
2146 ret = 0;
2147
2148out:
2149 kfree(buf);
2150
2151 return ret;
2152}
2153
2154#define SDEBUG_GET_LBA_STATUS_LEN 32
2155
2156static int resp_get_lba_status(struct scsi_cmnd * scmd,
2157 struct sdebug_dev_info * devip)
2158{
2159 unsigned long long lba;
2160 unsigned int alloc_len, mapped, num;
2161 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2162 int ret;
2163
2164 ret = check_readiness(scmd, 1, devip);
2165 if (ret)
2166 return ret;
2167
2168 lba = get_unaligned_be64(&scmd->cmnd[2]);
2169 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2170
2171 if (alloc_len < 24)
2172 return 0;
2173
2174 ret = check_device_access_params(devip, lba, 1);
2175 if (ret)
2176 return ret;
2177
2178 mapped = map_state(lba, &num);
2179
2180 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2181 put_unaligned_be32(16, &arr[0]); /* Parameter Data Length */
2182 put_unaligned_be64(lba, &arr[8]); /* LBA */
2183 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2184 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2185
2186 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2187}
2188
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002189#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190
2191static int resp_report_luns(struct scsi_cmnd * scp,
2192 struct sdebug_dev_info * devip)
2193{
2194 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002195 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 unsigned char *cmd = (unsigned char *)scp->cmnd;
2197 int select_report = (int)cmd[2];
2198 struct scsi_lun *one_lun;
2199 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002200 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
2202 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002203 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2205 0);
2206 return check_condition_result;
2207 }
2208 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2209 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2210 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002211 if (1 == select_report)
2212 lun_cnt = 0;
2213 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2214 --lun_cnt;
2215 wlun = (select_report > 0) ? 1 : 0;
2216 num = lun_cnt + wlun;
2217 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2218 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2219 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2220 sizeof(struct scsi_lun)), num);
2221 if (n < num) {
2222 wlun = 0;
2223 lun_cnt = n;
2224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002226 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2227 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2228 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2229 i++, lun++) {
2230 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 if (upper)
2232 one_lun[i].scsi_lun[0] =
2233 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002234 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002236 if (wlun) {
2237 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2238 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2239 i++;
2240 }
2241 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 return fill_from_dev_buffer(scp, arr,
2243 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2244}
2245
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002246static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2247 unsigned int num, struct sdebug_dev_info *devip)
2248{
2249 int i, j, ret = -1;
2250 unsigned char *kaddr, *buf;
2251 unsigned int offset;
2252 struct scatterlist *sg;
2253 struct scsi_data_buffer *sdb = scsi_in(scp);
2254
2255 /* better not to use temporary buffer. */
2256 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2257 if (!buf)
2258 return ret;
2259
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002260 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002261
2262 offset = 0;
2263 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2264 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2265 if (!kaddr)
2266 goto out;
2267
2268 for (j = 0; j < sg->length; j++)
2269 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2270
2271 offset += sg->length;
2272 kunmap_atomic(kaddr, KM_USER0);
2273 }
2274 ret = 0;
2275out:
2276 kfree(buf);
2277
2278 return ret;
2279}
2280
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281/* When timer goes off this function is called. */
2282static void timer_intr_handler(unsigned long indx)
2283{
2284 struct sdebug_queued_cmd * sqcp;
2285 unsigned long iflags;
2286
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002287 if (indx >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2289 "large\n");
2290 return;
2291 }
2292 spin_lock_irqsave(&queued_arr_lock, iflags);
2293 sqcp = &queued_arr[(int)indx];
2294 if (! sqcp->in_use) {
2295 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2296 "interrupt\n");
2297 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2298 return;
2299 }
2300 sqcp->in_use = 0;
2301 if (sqcp->done_funct) {
2302 sqcp->a_cmnd->result = sqcp->scsi_result;
2303 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2304 }
2305 sqcp->done_funct = NULL;
2306 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2307}
2308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002310static struct sdebug_dev_info *
2311sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002312{
2313 struct sdebug_dev_info *devip;
2314
2315 devip = kzalloc(sizeof(*devip), flags);
2316 if (devip) {
2317 devip->sdbg_host = sdbg_host;
2318 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2319 }
2320 return devip;
2321}
2322
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2324{
2325 struct sdebug_host_info * sdbg_host;
2326 struct sdebug_dev_info * open_devip = NULL;
2327 struct sdebug_dev_info * devip =
2328 (struct sdebug_dev_info *)sdev->hostdata;
2329
2330 if (devip)
2331 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002332 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2333 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 printk(KERN_ERR "Host info NULL\n");
2335 return NULL;
2336 }
2337 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2338 if ((devip->used) && (devip->channel == sdev->channel) &&
2339 (devip->target == sdev->id) &&
2340 (devip->lun == sdev->lun))
2341 return devip;
2342 else {
2343 if ((!devip->used) && (!open_devip))
2344 open_devip = devip;
2345 }
2346 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002347 if (!open_devip) { /* try and make a new one */
2348 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2349 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002351 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 return NULL;
2353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002355
2356 open_devip->channel = sdev->channel;
2357 open_devip->target = sdev->id;
2358 open_devip->lun = sdev->lun;
2359 open_devip->sdbg_host = sdbg_host;
2360 open_devip->reset = 1;
2361 open_devip->used = 1;
2362 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2363 if (scsi_debug_dsense)
2364 open_devip->sense_buff[0] = 0x72;
2365 else {
2366 open_devip->sense_buff[0] = 0x70;
2367 open_devip->sense_buff[7] = 0xa;
2368 }
2369 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2370 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2371
2372 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373}
2374
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002375static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002377 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2378 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2379 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002380 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002381 return 0;
2382}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002384static int scsi_debug_slave_configure(struct scsi_device *sdp)
2385{
2386 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002387
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002389 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2390 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2391 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2392 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2393 devip = devInfoReg(sdp);
2394 if (NULL == devip)
2395 return 1; /* no resources, will be marked offline */
2396 sdp->hostdata = devip;
2397 if (sdp->host->cmd_per_lun)
2398 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2399 sdp->host->cmd_per_lun);
2400 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002401 if (scsi_debug_no_uld)
2402 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002403 return 0;
2404}
2405
2406static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2407{
2408 struct sdebug_dev_info *devip =
2409 (struct sdebug_dev_info *)sdp->hostdata;
2410
2411 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2412 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2413 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2414 if (devip) {
2415 /* make this slot avaliable for re-use */
2416 devip->used = 0;
2417 sdp->hostdata = NULL;
2418 }
2419}
2420
2421/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2422static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2423{
2424 unsigned long iflags;
2425 int k;
2426 struct sdebug_queued_cmd *sqcp;
2427
2428 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002429 for (k = 0; k < scsi_debug_max_queue; ++k) {
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002430 sqcp = &queued_arr[k];
2431 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2432 del_timer_sync(&sqcp->cmnd_timer);
2433 sqcp->in_use = 0;
2434 sqcp->a_cmnd = NULL;
2435 break;
2436 }
2437 }
2438 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002439 return (k < scsi_debug_max_queue) ? 1 : 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002440}
2441
2442/* Deletes (stops) timers of all queued commands */
2443static void stop_all_queued(void)
2444{
2445 unsigned long iflags;
2446 int k;
2447 struct sdebug_queued_cmd *sqcp;
2448
2449 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002450 for (k = 0; k < scsi_debug_max_queue; ++k) {
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002451 sqcp = &queued_arr[k];
2452 if (sqcp->in_use && sqcp->a_cmnd) {
2453 del_timer_sync(&sqcp->cmnd_timer);
2454 sqcp->in_use = 0;
2455 sqcp->a_cmnd = NULL;
2456 }
2457 }
2458 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459}
2460
2461static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2462{
2463 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2464 printk(KERN_INFO "scsi_debug: abort\n");
2465 ++num_aborts;
2466 stop_queued_cmnd(SCpnt);
2467 return SUCCESS;
2468}
2469
2470static int scsi_debug_biosparam(struct scsi_device *sdev,
2471 struct block_device * bdev, sector_t capacity, int *info)
2472{
2473 int res;
2474 unsigned char *buf;
2475
2476 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2477 printk(KERN_INFO "scsi_debug: biosparam\n");
2478 buf = scsi_bios_ptable(bdev);
2479 if (buf) {
2480 res = scsi_partsize(buf, capacity,
2481 &info[2], &info[0], &info[1]);
2482 kfree(buf);
2483 if (! res)
2484 return res;
2485 }
2486 info[0] = sdebug_heads;
2487 info[1] = sdebug_sectors_per;
2488 info[2] = sdebug_cylinders_per;
2489 return 0;
2490}
2491
2492static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2493{
2494 struct sdebug_dev_info * devip;
2495
2496 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2497 printk(KERN_INFO "scsi_debug: device_reset\n");
2498 ++num_dev_resets;
2499 if (SCpnt) {
2500 devip = devInfoReg(SCpnt->device);
2501 if (devip)
2502 devip->reset = 1;
2503 }
2504 return SUCCESS;
2505}
2506
2507static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2508{
2509 struct sdebug_host_info *sdbg_host;
2510 struct sdebug_dev_info * dev_info;
2511 struct scsi_device * sdp;
2512 struct Scsi_Host * hp;
2513
2514 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2515 printk(KERN_INFO "scsi_debug: bus_reset\n");
2516 ++num_bus_resets;
2517 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002518 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 if (sdbg_host) {
2520 list_for_each_entry(dev_info,
2521 &sdbg_host->dev_info_list,
2522 dev_list)
2523 dev_info->reset = 1;
2524 }
2525 }
2526 return SUCCESS;
2527}
2528
2529static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2530{
2531 struct sdebug_host_info * sdbg_host;
2532 struct sdebug_dev_info * dev_info;
2533
2534 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2535 printk(KERN_INFO "scsi_debug: host_reset\n");
2536 ++num_host_resets;
2537 spin_lock(&sdebug_host_list_lock);
2538 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2539 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2540 dev_list)
2541 dev_info->reset = 1;
2542 }
2543 spin_unlock(&sdebug_host_list_lock);
2544 stop_all_queued();
2545 return SUCCESS;
2546}
2547
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548/* Initializes timers in queued array */
2549static void __init init_all_queued(void)
2550{
2551 unsigned long iflags;
2552 int k;
2553 struct sdebug_queued_cmd * sqcp;
2554
2555 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002556 for (k = 0; k < scsi_debug_max_queue; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 sqcp = &queued_arr[k];
2558 init_timer(&sqcp->cmnd_timer);
2559 sqcp->in_use = 0;
2560 sqcp->a_cmnd = NULL;
2561 }
2562 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2563}
2564
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002565static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002566 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567{
2568 struct partition * pp;
2569 int starts[SDEBUG_MAX_PARTS + 2];
2570 int sectors_per_part, num_sectors, k;
2571 int heads_by_sects, start_sec, end_sec;
2572
2573 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002574 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 return;
2576 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2577 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2578 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2579 "partitions to %d\n", SDEBUG_MAX_PARTS);
2580 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002581 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 sectors_per_part = (num_sectors - sdebug_sectors_per)
2583 / scsi_debug_num_parts;
2584 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2585 starts[0] = sdebug_sectors_per;
2586 for (k = 1; k < scsi_debug_num_parts; ++k)
2587 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2588 * heads_by_sects;
2589 starts[scsi_debug_num_parts] = num_sectors;
2590 starts[scsi_debug_num_parts + 1] = 0;
2591
2592 ramp[510] = 0x55; /* magic partition markings */
2593 ramp[511] = 0xAA;
2594 pp = (struct partition *)(ramp + 0x1be);
2595 for (k = 0; starts[k + 1]; ++k, ++pp) {
2596 start_sec = starts[k];
2597 end_sec = starts[k + 1] - 1;
2598 pp->boot_ind = 0;
2599
2600 pp->cyl = start_sec / heads_by_sects;
2601 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2602 / sdebug_sectors_per;
2603 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2604
2605 pp->end_cyl = end_sec / heads_by_sects;
2606 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2607 / sdebug_sectors_per;
2608 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2609
2610 pp->start_sect = start_sec;
2611 pp->nr_sects = end_sec - start_sec + 1;
2612 pp->sys_ind = 0x83; /* plain Linux partition */
2613 }
2614}
2615
2616static int schedule_resp(struct scsi_cmnd * cmnd,
2617 struct sdebug_dev_info * devip,
2618 done_funct_t done, int scsi_result, int delta_jiff)
2619{
2620 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2621 if (scsi_result) {
2622 struct scsi_device * sdp = cmnd->device;
2623
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002624 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2625 "non-zero result=0x%x\n", sdp->host->host_no,
2626 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 }
2628 }
2629 if (cmnd && devip) {
2630 /* simulate autosense by this driver */
2631 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2632 memcpy(cmnd->sense_buffer, devip->sense_buff,
2633 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2634 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2635 }
2636 if (delta_jiff <= 0) {
2637 if (cmnd)
2638 cmnd->result = scsi_result;
2639 if (done)
2640 done(cmnd);
2641 return 0;
2642 } else {
2643 unsigned long iflags;
2644 int k;
2645 struct sdebug_queued_cmd * sqcp = NULL;
2646
2647 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002648 for (k = 0; k < scsi_debug_max_queue; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 sqcp = &queued_arr[k];
2650 if (! sqcp->in_use)
2651 break;
2652 }
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002653 if (k >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2655 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2656 return 1; /* report busy to mid level */
2657 }
2658 sqcp->in_use = 1;
2659 sqcp->a_cmnd = cmnd;
2660 sqcp->scsi_result = scsi_result;
2661 sqcp->done_funct = done;
2662 sqcp->cmnd_timer.function = timer_intr_handler;
2663 sqcp->cmnd_timer.data = k;
2664 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2665 add_timer(&sqcp->cmnd_timer);
2666 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2667 if (cmnd)
2668 cmnd->result = 0;
2669 return 0;
2670 }
2671}
Douglas Gilbert23183912006-09-16 20:30:47 -04002672/* Note: The following macros create attribute files in the
2673 /sys/module/scsi_debug/parameters directory. Unfortunately this
2674 driver is unaware of a change and cannot trigger auxiliary actions
2675 as it can when the corresponding attribute in the
2676 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2677 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002678module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2679module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2680module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2681module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2682module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002683module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002684module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002685module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002686module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002687module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002688module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2689module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2690module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2691module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2692module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2693module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002694module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2695 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002696module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002697module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2698module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2699module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2700module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002701module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04002702module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002703module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002704module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
2705module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2706module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
2707module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
2709MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2710MODULE_DESCRIPTION("SCSI debug adapter driver");
2711MODULE_LICENSE("GPL");
2712MODULE_VERSION(SCSI_DEBUG_VERSION);
2713
2714MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2715MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002716MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2717MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002718MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002719MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002720MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002721MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002722MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002723MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002725MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002726MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2728MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002729MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002730MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002731MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
2732MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Martin K. Petersene308b3d2010-03-23 01:12:27 -04002733MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002734MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002735MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2736MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2737MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2738MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Martin K. Petersen44d92692009-10-15 14:45:27 -04002739MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)");
2740MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)");
2741MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)");
2742MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
2744static char sdebug_info[256];
2745
2746static const char * scsi_debug_info(struct Scsi_Host * shp)
2747{
2748 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2749 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2750 scsi_debug_version_date, scsi_debug_dev_size_mb,
2751 scsi_debug_opts);
2752 return sdebug_info;
2753}
2754
2755/* scsi_debug_proc_info
2756 * Used if the driver currently has no own support for /proc/scsi
2757 */
2758static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2759 int length, int inout)
2760{
2761 int len, pos, begin;
2762 int orig_length;
2763
2764 orig_length = length;
2765
2766 if (inout == 1) {
2767 char arr[16];
2768 int minLen = length > 15 ? 15 : length;
2769
2770 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2771 return -EACCES;
2772 memcpy(arr, buffer, minLen);
2773 arr[minLen] = '\0';
2774 if (1 != sscanf(arr, "%d", &pos))
2775 return -EINVAL;
2776 scsi_debug_opts = pos;
2777 if (scsi_debug_every_nth != 0)
2778 scsi_debug_cmnd_count = 0;
2779 return length;
2780 }
2781 begin = 0;
2782 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2783 "%s [%s]\n"
2784 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2785 "every_nth=%d(curr:%d)\n"
2786 "delay=%d, max_luns=%d, scsi_level=%d\n"
2787 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2788 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002789 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2791 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2792 scsi_debug_cmnd_count, scsi_debug_delay,
2793 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002794 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2795 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002796 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 if (pos < offset) {
2798 len = 0;
2799 begin = pos;
2800 }
2801 *start = buffer + (offset - begin); /* Start of wanted data */
2802 len -= (offset - begin);
2803 if (len > length)
2804 len = length;
2805 return len;
2806}
2807
2808static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2809{
2810 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2811}
2812
2813static ssize_t sdebug_delay_store(struct device_driver * ddp,
2814 const char * buf, size_t count)
2815{
2816 int delay;
2817 char work[20];
2818
2819 if (1 == sscanf(buf, "%10s", work)) {
2820 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2821 scsi_debug_delay = delay;
2822 return count;
2823 }
2824 }
2825 return -EINVAL;
2826}
2827DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2828 sdebug_delay_store);
2829
2830static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2831{
2832 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2833}
2834
2835static ssize_t sdebug_opts_store(struct device_driver * ddp,
2836 const char * buf, size_t count)
2837{
2838 int opts;
2839 char work[20];
2840
2841 if (1 == sscanf(buf, "%10s", work)) {
2842 if (0 == strnicmp(work,"0x", 2)) {
2843 if (1 == sscanf(&work[2], "%x", &opts))
2844 goto opts_done;
2845 } else {
2846 if (1 == sscanf(work, "%d", &opts))
2847 goto opts_done;
2848 }
2849 }
2850 return -EINVAL;
2851opts_done:
2852 scsi_debug_opts = opts;
2853 scsi_debug_cmnd_count = 0;
2854 return count;
2855}
2856DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2857 sdebug_opts_store);
2858
2859static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2860{
2861 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2862}
2863static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2864 const char * buf, size_t count)
2865{
2866 int n;
2867
2868 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2869 scsi_debug_ptype = n;
2870 return count;
2871 }
2872 return -EINVAL;
2873}
2874DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2875
2876static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2877{
2878 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2879}
2880static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2881 const char * buf, size_t count)
2882{
2883 int n;
2884
2885 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2886 scsi_debug_dsense = n;
2887 return count;
2888 }
2889 return -EINVAL;
2890}
2891DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2892 sdebug_dsense_store);
2893
Douglas Gilbert23183912006-09-16 20:30:47 -04002894static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2895{
2896 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2897}
2898static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2899 const char * buf, size_t count)
2900{
2901 int n;
2902
2903 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2904 scsi_debug_fake_rw = n;
2905 return count;
2906 }
2907 return -EINVAL;
2908}
2909DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2910 sdebug_fake_rw_store);
2911
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002912static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2913{
2914 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2915}
2916static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2917 const char * buf, size_t count)
2918{
2919 int n;
2920
2921 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2922 scsi_debug_no_lun_0 = n;
2923 return count;
2924 }
2925 return -EINVAL;
2926}
2927DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2928 sdebug_no_lun_0_store);
2929
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2931{
2932 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2933}
2934static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2935 const char * buf, size_t count)
2936{
2937 int n;
2938
2939 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2940 scsi_debug_num_tgts = n;
2941 sdebug_max_tgts_luns();
2942 return count;
2943 }
2944 return -EINVAL;
2945}
2946DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2947 sdebug_num_tgts_store);
2948
2949static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2950{
2951 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2952}
2953DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2954
2955static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2956{
2957 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2958}
2959DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2960
2961static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2962{
2963 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2964}
2965static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2966 const char * buf, size_t count)
2967{
2968 int nth;
2969
2970 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2971 scsi_debug_every_nth = nth;
2972 scsi_debug_cmnd_count = 0;
2973 return count;
2974 }
2975 return -EINVAL;
2976}
2977DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2978 sdebug_every_nth_store);
2979
2980static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2981{
2982 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2983}
2984static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2985 const char * buf, size_t count)
2986{
2987 int n;
2988
2989 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2990 scsi_debug_max_luns = n;
2991 sdebug_max_tgts_luns();
2992 return count;
2993 }
2994 return -EINVAL;
2995}
2996DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2997 sdebug_max_luns_store);
2998
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002999static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
3000{
3001 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
3002}
3003static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
3004 const char * buf, size_t count)
3005{
3006 int n;
3007
3008 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
3009 (n <= SCSI_DEBUG_CANQUEUE)) {
3010 scsi_debug_max_queue = n;
3011 return count;
3012 }
3013 return -EINVAL;
3014}
3015DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
3016 sdebug_max_queue_store);
3017
3018static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
3019{
3020 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
3021}
3022DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
3023
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
3025{
3026 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
3027}
3028DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
3029
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003030static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
3031{
3032 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3033}
3034static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
3035 const char * buf, size_t count)
3036{
3037 int n;
3038
3039 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3040 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003041
3042 sdebug_capacity = get_sdebug_capacity();
3043
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003044 return count;
3045 }
3046 return -EINVAL;
3047}
3048DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
3049 sdebug_virtual_gb_store);
3050
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
3052{
3053 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
3054}
3055
3056static ssize_t sdebug_add_host_store(struct device_driver * ddp,
3057 const char * buf, size_t count)
3058{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003059 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003061 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 if (delta_hosts > 0) {
3064 do {
3065 sdebug_add_adapter();
3066 } while (--delta_hosts);
3067 } else if (delta_hosts < 0) {
3068 do {
3069 sdebug_remove_adapter();
3070 } while (++delta_hosts);
3071 }
3072 return count;
3073}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003074DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 sdebug_add_host_store);
3076
Douglas Gilbert23183912006-09-16 20:30:47 -04003077static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
3078 char * buf)
3079{
3080 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3081}
3082static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
3083 const char * buf, size_t count)
3084{
3085 int n;
3086
3087 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3088 scsi_debug_vpd_use_hostno = n;
3089 return count;
3090 }
3091 return -EINVAL;
3092}
3093DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
3094 sdebug_vpd_use_hostno_store);
3095
Martin K. Petersen597136a2008-06-05 00:12:59 -04003096static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3097{
3098 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3099}
3100DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3101
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003102static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3103{
3104 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3105}
3106DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3107
3108static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3109{
3110 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3111}
3112DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3113
3114static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3115{
3116 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3117}
3118DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3119
3120static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3121{
3122 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3123}
3124DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3125
Martin K. Petersen44d92692009-10-15 14:45:27 -04003126static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
3127{
3128 ssize_t count;
3129
3130 if (scsi_debug_unmap_granularity == 0)
3131 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3132 sdebug_store_sectors);
3133
3134 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3135
3136 buf[count++] = '\n';
3137 buf[count++] = 0;
3138
3139 return count;
3140}
3141DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
3142
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003143
Douglas Gilbert23183912006-09-16 20:30:47 -04003144/* Note: The following function creates attribute files in the
3145 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3146 files (over those found in the /sys/module/scsi_debug/parameters
3147 directory) is that auxiliary actions can be triggered when an attribute
3148 is changed. For example see: sdebug_add_host_store() above.
3149 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003150static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003152 int ret;
3153
3154 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3155 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
3156 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3157 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3158 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04003159 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003160 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003161 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
Douglas Gilbert23183912006-09-16 20:30:47 -04003162 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003163 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003164 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003165 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003166 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3167 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
3168 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04003169 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
3170 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003171 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003172 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3173 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3174 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3175 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003176 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003177 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178}
3179
3180static void do_remove_driverfs_files(void)
3181{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003182 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003183 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3184 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3185 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3186 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003187 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04003188 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3189 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
3191 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
3192 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003194 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003195 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
Douglas Gilbert23183912006-09-16 20:30:47 -04003196 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003197 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003199 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
3201 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3202 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3203 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
3204 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3205}
3206
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003207static void pseudo_0_release(struct device *dev)
3208{
3209 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3210 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
3211}
3212
3213static struct device pseudo_primary = {
Kay Sievers71610f52008-12-03 22:41:36 +01003214 .init_name = "pseudo_0",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003215 .release = pseudo_0_release,
3216};
3217
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218static int __init scsi_debug_init(void)
3219{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003220 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 int host_to_add;
3222 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003223 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
Martin K. Petersen597136a2008-06-05 00:12:59 -04003225 switch (scsi_debug_sector_size) {
3226 case 512:
3227 case 1024:
3228 case 2048:
3229 case 4096:
3230 break;
3231 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003232 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04003233 scsi_debug_sector_size);
3234 return -EINVAL;
3235 }
3236
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003237 switch (scsi_debug_dif) {
3238
3239 case SD_DIF_TYPE0_PROTECTION:
3240 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003241 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003242 case SD_DIF_TYPE3_PROTECTION:
3243 break;
3244
3245 default:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003246 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003247 return -EINVAL;
3248 }
3249
3250 if (scsi_debug_guard > 1) {
3251 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3252 return -EINVAL;
3253 }
3254
3255 if (scsi_debug_ato > 1) {
3256 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3257 return -EINVAL;
3258 }
3259
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003260 if (scsi_debug_physblk_exp > 15) {
3261 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3262 scsi_debug_physblk_exp);
3263 return -EINVAL;
3264 }
3265
3266 if (scsi_debug_lowest_aligned > 0x3fff) {
3267 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3268 scsi_debug_lowest_aligned);
3269 return -EINVAL;
3270 }
3271
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272 if (scsi_debug_dev_size_mb < 1)
3273 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003274 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003275 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003276 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277
3278 /* play around with geometry, don't waste too much on track 0 */
3279 sdebug_heads = 8;
3280 sdebug_sectors_per = 32;
3281 if (scsi_debug_dev_size_mb >= 16)
3282 sdebug_heads = 32;
3283 else if (scsi_debug_dev_size_mb >= 256)
3284 sdebug_heads = 64;
3285 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3286 (sdebug_sectors_per * sdebug_heads);
3287 if (sdebug_cylinders_per >= 1024) {
3288 /* other LLDs do this; implies >= 1GB ram disk ... */
3289 sdebug_heads = 255;
3290 sdebug_sectors_per = 63;
3291 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3292 (sdebug_sectors_per * sdebug_heads);
3293 }
3294
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 fake_storep = vmalloc(sz);
3296 if (NULL == fake_storep) {
3297 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
3298 return -ENOMEM;
3299 }
3300 memset(fake_storep, 0, sz);
3301 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003302 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003304 if (scsi_debug_dif) {
3305 int dif_size;
3306
3307 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3308 dif_storep = vmalloc(dif_size);
3309
3310 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3311 dif_size, dif_storep);
3312
3313 if (dif_storep == NULL) {
3314 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3315 ret = -ENOMEM;
3316 goto free_vm;
3317 }
3318
3319 memset(dif_storep, 0xff, dif_size);
3320 }
3321
Martin K. Petersen44d92692009-10-15 14:45:27 -04003322 if (scsi_debug_unmap_granularity) {
3323 unsigned int map_bytes;
3324
3325 if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
3326 printk(KERN_ERR
3327 "%s: ERR: unmap_granularity < unmap_alignment\n",
3328 __func__);
3329 return -EINVAL;
3330 }
3331
3332 map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
3333 map_bytes = map_size >> 3;
3334 map_storep = vmalloc(map_bytes);
3335
3336 printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
3337 map_size);
3338
3339 if (map_storep == NULL) {
3340 printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
3341 ret = -ENOMEM;
3342 goto free_vm;
3343 }
3344
3345 memset(map_storep, 0x0, map_bytes);
3346
3347 /* Map first 1KB for partition table */
3348 if (scsi_debug_num_parts)
3349 map_region(0, 2);
3350 }
3351
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003352 ret = device_register(&pseudo_primary);
3353 if (ret < 0) {
3354 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
3355 ret);
3356 goto free_vm;
3357 }
3358 ret = bus_register(&pseudo_lld_bus);
3359 if (ret < 0) {
3360 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
3361 ret);
3362 goto dev_unreg;
3363 }
3364 ret = driver_register(&sdebug_driverfs_driver);
3365 if (ret < 0) {
3366 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
3367 ret);
3368 goto bus_unreg;
3369 }
3370 ret = do_create_driverfs_files();
3371 if (ret < 0) {
3372 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
3373 ret);
3374 goto del_files;
3375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003377 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 host_to_add = scsi_debug_add_host;
3380 scsi_debug_add_host = 0;
3381
3382 for (k = 0; k < host_to_add; k++) {
3383 if (sdebug_add_adapter()) {
3384 printk(KERN_ERR "scsi_debug_init: "
3385 "sdebug_add_adapter failed k=%d\n", k);
3386 break;
3387 }
3388 }
3389
3390 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3391 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
3392 scsi_debug_add_host);
3393 }
3394 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003395
3396del_files:
3397 do_remove_driverfs_files();
3398 driver_unregister(&sdebug_driverfs_driver);
3399bus_unreg:
3400 bus_unregister(&pseudo_lld_bus);
3401dev_unreg:
3402 device_unregister(&pseudo_primary);
3403free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003404 if (map_storep)
3405 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003406 if (dif_storep)
3407 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003408 vfree(fake_storep);
3409
3410 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411}
3412
3413static void __exit scsi_debug_exit(void)
3414{
3415 int k = scsi_debug_add_host;
3416
3417 stop_all_queued();
3418 for (; k; k--)
3419 sdebug_remove_adapter();
3420 do_remove_driverfs_files();
3421 driver_unregister(&sdebug_driverfs_driver);
3422 bus_unregister(&pseudo_lld_bus);
3423 device_unregister(&pseudo_primary);
3424
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003425 if (dif_storep)
3426 vfree(dif_storep);
3427
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 vfree(fake_storep);
3429}
3430
3431device_initcall(scsi_debug_init);
3432module_exit(scsi_debug_exit);
3433
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434static void sdebug_release_adapter(struct device * dev)
3435{
3436 struct sdebug_host_info *sdbg_host;
3437
3438 sdbg_host = to_sdebug_host(dev);
3439 kfree(sdbg_host);
3440}
3441
3442static int sdebug_add_adapter(void)
3443{
3444 int k, devs_per_host;
3445 int error = 0;
3446 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003447 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003449 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 if (NULL == sdbg_host) {
3451 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003452 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 return -ENOMEM;
3454 }
3455
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3457
3458 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3459 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003460 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3461 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003463 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 error = -ENOMEM;
3465 goto clean;
3466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 }
3468
3469 spin_lock(&sdebug_host_list_lock);
3470 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3471 spin_unlock(&sdebug_host_list_lock);
3472
3473 sdbg_host->dev.bus = &pseudo_lld_bus;
3474 sdbg_host->dev.parent = &pseudo_primary;
3475 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003476 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
3478 error = device_register(&sdbg_host->dev);
3479
3480 if (error)
3481 goto clean;
3482
3483 ++scsi_debug_add_host;
3484 return error;
3485
3486clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003487 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3488 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 list_del(&sdbg_devinfo->dev_list);
3490 kfree(sdbg_devinfo);
3491 }
3492
3493 kfree(sdbg_host);
3494 return error;
3495}
3496
3497static void sdebug_remove_adapter(void)
3498{
3499 struct sdebug_host_info * sdbg_host = NULL;
3500
3501 spin_lock(&sdebug_host_list_lock);
3502 if (!list_empty(&sdebug_host_list)) {
3503 sdbg_host = list_entry(sdebug_host_list.prev,
3504 struct sdebug_host_info, host_list);
3505 list_del(&sdbg_host->host_list);
3506 }
3507 spin_unlock(&sdebug_host_list_lock);
3508
3509 if (!sdbg_host)
3510 return;
3511
3512 device_unregister(&sdbg_host->dev);
3513 --scsi_debug_add_host;
3514}
3515
FUJITA Tomonori639db472008-03-20 11:09:19 +09003516static
3517int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
3518{
3519 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3520 int len, k;
3521 unsigned int num;
3522 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003523 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003524 int errsts = 0;
3525 int target = SCpnt->device->id;
3526 struct sdebug_dev_info *devip = NULL;
3527 int inj_recovered = 0;
3528 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003529 int inj_dif = 0;
3530 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003531 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003532 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003533
3534 scsi_set_resid(SCpnt, 0);
3535 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3536 printk(KERN_INFO "scsi_debug: cmd ");
3537 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3538 printk("%02x ", (int)cmd[k]);
3539 printk("\n");
3540 }
3541
3542 if (target == SCpnt->device->host->hostt->this_id) {
3543 printk(KERN_INFO "scsi_debug: initiator's id used as "
3544 "target!\n");
3545 return schedule_resp(SCpnt, NULL, done,
3546 DID_NO_CONNECT << 16, 0);
3547 }
3548
3549 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3550 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3551 return schedule_resp(SCpnt, NULL, done,
3552 DID_NO_CONNECT << 16, 0);
3553 devip = devInfoReg(SCpnt->device);
3554 if (NULL == devip)
3555 return schedule_resp(SCpnt, NULL, done,
3556 DID_NO_CONNECT << 16, 0);
3557
3558 if ((scsi_debug_every_nth != 0) &&
3559 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3560 scsi_debug_cmnd_count = 0;
3561 if (scsi_debug_every_nth < -1)
3562 scsi_debug_every_nth = -1;
3563 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3564 return 0; /* ignore command causing timeout */
3565 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3566 inj_recovered = 1; /* to reads and writes below */
3567 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3568 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003569 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3570 inj_dif = 1; /* to reads and writes below */
3571 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3572 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003573 }
3574
3575 if (devip->wlun) {
3576 switch (*cmd) {
3577 case INQUIRY:
3578 case REQUEST_SENSE:
3579 case TEST_UNIT_READY:
3580 case REPORT_LUNS:
3581 break; /* only allowable wlun commands */
3582 default:
3583 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3584 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3585 "not supported for wlun\n", *cmd);
3586 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3587 INVALID_OPCODE, 0);
3588 errsts = check_condition_result;
3589 return schedule_resp(SCpnt, devip, done, errsts,
3590 0);
3591 }
3592 }
3593
3594 switch (*cmd) {
3595 case INQUIRY: /* mandatory, ignore unit attention */
3596 delay_override = 1;
3597 errsts = resp_inquiry(SCpnt, target, devip);
3598 break;
3599 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3600 delay_override = 1;
3601 errsts = resp_requests(SCpnt, devip);
3602 break;
3603 case REZERO_UNIT: /* actually this is REWIND for SSC */
3604 case START_STOP:
3605 errsts = resp_start_stop(SCpnt, devip);
3606 break;
3607 case ALLOW_MEDIUM_REMOVAL:
3608 errsts = check_readiness(SCpnt, 1, devip);
3609 if (errsts)
3610 break;
3611 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3612 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3613 cmd[4] ? "inhibited" : "enabled");
3614 break;
3615 case SEND_DIAGNOSTIC: /* mandatory */
3616 errsts = check_readiness(SCpnt, 1, devip);
3617 break;
3618 case TEST_UNIT_READY: /* mandatory */
3619 delay_override = 1;
3620 errsts = check_readiness(SCpnt, 0, devip);
3621 break;
3622 case RESERVE:
3623 errsts = check_readiness(SCpnt, 1, devip);
3624 break;
3625 case RESERVE_10:
3626 errsts = check_readiness(SCpnt, 1, devip);
3627 break;
3628 case RELEASE:
3629 errsts = check_readiness(SCpnt, 1, devip);
3630 break;
3631 case RELEASE_10:
3632 errsts = check_readiness(SCpnt, 1, devip);
3633 break;
3634 case READ_CAPACITY:
3635 errsts = resp_readcap(SCpnt, devip);
3636 break;
3637 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003638 if (cmd[1] == SAI_READ_CAPACITY_16)
3639 errsts = resp_readcap16(SCpnt, devip);
3640 else if (cmd[1] == SAI_GET_LBA_STATUS) {
3641
3642 if (scsi_debug_unmap_max_desc == 0) {
3643 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3644 INVALID_COMMAND_OPCODE, 0);
3645 errsts = check_condition_result;
3646 } else
3647 errsts = resp_get_lba_status(SCpnt, devip);
3648 } else {
FUJITA Tomonori639db472008-03-20 11:09:19 +09003649 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3650 INVALID_OPCODE, 0);
3651 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003652 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09003653 break;
3654 case MAINTENANCE_IN:
3655 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3656 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3657 INVALID_OPCODE, 0);
3658 errsts = check_condition_result;
3659 break;
3660 }
3661 errsts = resp_report_tgtpgs(SCpnt, devip);
3662 break;
3663 case READ_16:
3664 case READ_12:
3665 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003666 /* READ{10,12,16} and DIF Type 2 are natural enemies */
3667 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3668 cmd[1] & 0xe0) {
3669 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3670 INVALID_COMMAND_OPCODE, 0);
3671 errsts = check_condition_result;
3672 break;
3673 }
3674
3675 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3676 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3677 (cmd[1] & 0xe0) == 0)
3678 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3679
3680 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003681 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003682read:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003683 errsts = check_readiness(SCpnt, 0, devip);
3684 if (errsts)
3685 break;
3686 if (scsi_debug_fake_rw)
3687 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003688 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3689 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003690 if (inj_recovered && (0 == errsts)) {
3691 mk_sense_buffer(devip, RECOVERED_ERROR,
3692 THRESHOLD_EXCEEDED, 0);
3693 errsts = check_condition_result;
3694 } else if (inj_transport && (0 == errsts)) {
3695 mk_sense_buffer(devip, ABORTED_COMMAND,
3696 TRANSPORT_PROBLEM, ACK_NAK_TO);
3697 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003698 } else if (inj_dif && (0 == errsts)) {
3699 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3700 errsts = illegal_condition_result;
3701 } else if (inj_dix && (0 == errsts)) {
3702 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3703 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003704 }
3705 break;
3706 case REPORT_LUNS: /* mandatory, ignore unit attention */
3707 delay_override = 1;
3708 errsts = resp_report_luns(SCpnt, devip);
3709 break;
3710 case VERIFY: /* 10 byte SBC-2 command */
3711 errsts = check_readiness(SCpnt, 0, devip);
3712 break;
3713 case WRITE_16:
3714 case WRITE_12:
3715 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003716 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3717 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3718 cmd[1] & 0xe0) {
3719 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3720 INVALID_COMMAND_OPCODE, 0);
3721 errsts = check_condition_result;
3722 break;
3723 }
3724
3725 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3726 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3727 (cmd[1] & 0xe0) == 0)
3728 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3729
3730 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003731 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003732write:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003733 errsts = check_readiness(SCpnt, 0, devip);
3734 if (errsts)
3735 break;
3736 if (scsi_debug_fake_rw)
3737 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003738 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3739 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003740 if (inj_recovered && (0 == errsts)) {
3741 mk_sense_buffer(devip, RECOVERED_ERROR,
3742 THRESHOLD_EXCEEDED, 0);
3743 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003744 } else if (inj_dif && (0 == errsts)) {
3745 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3746 errsts = illegal_condition_result;
3747 } else if (inj_dix && (0 == errsts)) {
3748 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3749 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003750 }
3751 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003752 case WRITE_SAME_16:
3753 if (cmd[1] & 0x8)
3754 unmap = 1;
3755 /* fall through */
3756 case WRITE_SAME:
3757 errsts = check_readiness(SCpnt, 0, devip);
3758 if (errsts)
3759 break;
3760 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3761 errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
3762 break;
3763 case UNMAP:
3764 errsts = check_readiness(SCpnt, 0, devip);
3765 if (errsts)
3766 break;
3767
3768 if (scsi_debug_unmap_max_desc == 0) {
3769 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3770 INVALID_COMMAND_OPCODE, 0);
3771 errsts = check_condition_result;
3772 } else
3773 errsts = resp_unmap(SCpnt, devip);
3774 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003775 case MODE_SENSE:
3776 case MODE_SENSE_10:
3777 errsts = resp_mode_sense(SCpnt, target, devip);
3778 break;
3779 case MODE_SELECT:
3780 errsts = resp_mode_select(SCpnt, 1, devip);
3781 break;
3782 case MODE_SELECT_10:
3783 errsts = resp_mode_select(SCpnt, 0, devip);
3784 break;
3785 case LOG_SENSE:
3786 errsts = resp_log_sense(SCpnt, devip);
3787 break;
3788 case SYNCHRONIZE_CACHE:
3789 delay_override = 1;
3790 errsts = check_readiness(SCpnt, 0, devip);
3791 break;
3792 case WRITE_BUFFER:
3793 errsts = check_readiness(SCpnt, 1, devip);
3794 break;
3795 case XDWRITEREAD_10:
3796 if (!scsi_bidi_cmnd(SCpnt)) {
3797 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3798 INVALID_FIELD_IN_CDB, 0);
3799 errsts = check_condition_result;
3800 break;
3801 }
3802
3803 errsts = check_readiness(SCpnt, 0, devip);
3804 if (errsts)
3805 break;
3806 if (scsi_debug_fake_rw)
3807 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003808 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3809 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003810 if (errsts)
3811 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003812 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003813 if (errsts)
3814 break;
3815 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3816 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003817 case VARIABLE_LENGTH_CMD:
3818 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3819
3820 if ((cmd[10] & 0xe0) == 0)
3821 printk(KERN_ERR
3822 "Unprotected RD/WR to DIF device\n");
3823
3824 if (cmd[9] == READ_32) {
3825 BUG_ON(SCpnt->cmd_len < 32);
3826 goto read;
3827 }
3828
3829 if (cmd[9] == WRITE_32) {
3830 BUG_ON(SCpnt->cmd_len < 32);
3831 goto write;
3832 }
3833 }
3834
3835 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3836 INVALID_FIELD_IN_CDB, 0);
3837 errsts = check_condition_result;
3838 break;
3839
FUJITA Tomonori639db472008-03-20 11:09:19 +09003840 default:
3841 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3842 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3843 "supported\n", *cmd);
3844 errsts = check_readiness(SCpnt, 1, devip);
3845 if (errsts)
3846 break; /* Unit attention takes precedence */
3847 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3848 errsts = check_condition_result;
3849 break;
3850 }
3851 return schedule_resp(SCpnt, devip, done, errsts,
3852 (delay_override ? 0 : scsi_debug_delay));
3853}
3854
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003855static struct scsi_host_template sdebug_driver_template = {
3856 .proc_info = scsi_debug_proc_info,
3857 .proc_name = sdebug_proc_name,
3858 .name = "SCSI DEBUG",
3859 .info = scsi_debug_info,
3860 .slave_alloc = scsi_debug_slave_alloc,
3861 .slave_configure = scsi_debug_slave_configure,
3862 .slave_destroy = scsi_debug_slave_destroy,
3863 .ioctl = scsi_debug_ioctl,
3864 .queuecommand = scsi_debug_queuecommand,
3865 .eh_abort_handler = scsi_debug_abort,
3866 .eh_bus_reset_handler = scsi_debug_bus_reset,
3867 .eh_device_reset_handler = scsi_debug_device_reset,
3868 .eh_host_reset_handler = scsi_debug_host_reset,
3869 .bios_param = scsi_debug_biosparam,
3870 .can_queue = SCSI_DEBUG_CANQUEUE,
3871 .this_id = 7,
3872 .sg_tablesize = 256,
3873 .cmd_per_lun = 16,
3874 .max_sectors = 0xffff,
3875 .use_clustering = DISABLE_CLUSTERING,
3876 .module = THIS_MODULE,
3877};
3878
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879static int sdebug_driver_probe(struct device * dev)
3880{
3881 int error = 0;
3882 struct sdebug_host_info *sdbg_host;
3883 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003884 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885
3886 sdbg_host = to_sdebug_host(dev);
3887
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003888 sdebug_driver_template.can_queue = scsi_debug_max_queue;
3889 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3890 if (NULL == hpnt) {
3891 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
3892 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895
3896 sdbg_host->shost = hpnt;
3897 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3898 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3899 hpnt->max_id = scsi_debug_num_tgts + 1;
3900 else
3901 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003902 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003904 host_prot = 0;
3905
3906 switch (scsi_debug_dif) {
3907
3908 case SD_DIF_TYPE1_PROTECTION:
3909 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3910 if (scsi_debug_dix)
3911 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3912 break;
3913
3914 case SD_DIF_TYPE2_PROTECTION:
3915 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3916 if (scsi_debug_dix)
3917 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3918 break;
3919
3920 case SD_DIF_TYPE3_PROTECTION:
3921 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3922 if (scsi_debug_dix)
3923 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3924 break;
3925
3926 default:
3927 if (scsi_debug_dix)
3928 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3929 break;
3930 }
3931
3932 scsi_host_set_prot(hpnt, host_prot);
3933
3934 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3935 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3936 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3937 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3938 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3939 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3940 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3941 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3942
3943 if (scsi_debug_guard == 1)
3944 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3945 else
3946 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3947
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 error = scsi_add_host(hpnt, &sdbg_host->dev);
3949 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003950 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 error = -ENODEV;
3952 scsi_host_put(hpnt);
3953 } else
3954 scsi_scan_host(hpnt);
3955
3956
3957 return error;
3958}
3959
3960static int sdebug_driver_remove(struct device * dev)
3961{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003963 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964
3965 sdbg_host = to_sdebug_host(dev);
3966
3967 if (!sdbg_host) {
3968 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003969 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 return -ENODEV;
3971 }
3972
3973 scsi_remove_host(sdbg_host->shost);
3974
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003975 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3976 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 list_del(&sdbg_devinfo->dev_list);
3978 kfree(sdbg_devinfo);
3979 }
3980
3981 scsi_host_put(sdbg_host->shost);
3982 return 0;
3983}
3984
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003985static int pseudo_lld_bus_match(struct device *dev,
3986 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003988 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003990
3991static struct bus_type pseudo_lld_bus = {
3992 .name = "pseudo",
3993 .match = pseudo_lld_bus_match,
3994 .probe = sdebug_driver_probe,
3995 .remove = sdebug_driver_remove,
3996};