blob: a783cd33a3e47d2e8c4c91b2c1197364d777ab47 [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. Petersen44d92692009-10-15 14:45:27 -0400111#define DEF_UNMAP_MAX_BLOCKS 0
112#define DEF_UNMAP_MAX_DESC 0
113#define DEF_UNMAP_GRANULARITY 0
114#define DEF_UNMAP_ALIGNMENT 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116/* bit mask values for scsi_debug_opts */
117#define SCSI_DEBUG_OPT_NOISE 1
118#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
119#define SCSI_DEBUG_OPT_TIMEOUT 4
120#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500121#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500122#define SCSI_DEBUG_OPT_DIF_ERR 32
123#define SCSI_DEBUG_OPT_DIX_ERR 64
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124/* When "every_nth" > 0 then modulo "every_nth" commands:
125 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
126 * - a RECOVERED_ERROR is simulated on successful read and write
127 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500128 * - a TRANSPORT_ERROR is simulated on successful read and write
129 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 *
131 * When "every_nth" < 0 then after "- every_nth" commands:
132 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
133 * - a RECOVERED_ERROR is simulated on successful read and write
134 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500135 * - a TRANSPORT_ERROR is simulated on successful read and write
136 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 * This will continue until some other action occurs (e.g. the user
138 * writing a new value (other than -1 or 1) to every_nth via sysfs).
139 */
140
141/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
142 * sector on read commands: */
143#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
144
145/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
146 * or "peripheral device" addressing (value 0) */
147#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400148#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400150/* Can queue up to this number of commands. Typically commands that
151 * that have a non-zero delay are queued. */
152#define SCSI_DEBUG_CANQUEUE 255
153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int scsi_debug_add_host = DEF_NUM_HOST;
155static int scsi_debug_delay = DEF_DELAY;
156static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
157static int scsi_debug_every_nth = DEF_EVERY_NTH;
158static int scsi_debug_max_luns = DEF_MAX_LUNS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400159static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160static int scsi_debug_num_parts = DEF_NUM_PARTS;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -0400161static int scsi_debug_no_uld = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
163static int scsi_debug_opts = DEF_OPTS;
164static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
165static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
166static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400167static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
168static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400169static int scsi_debug_fake_rw = DEF_FAKE_RW;
170static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400171static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500172static int scsi_debug_dix = DEF_DIX;
173static int scsi_debug_dif = DEF_DIF;
174static int scsi_debug_guard = DEF_GUARD;
175static int scsi_debug_ato = DEF_ATO;
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400176static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
177static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400178static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
179static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
180static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
181static int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183static int scsi_debug_cmnd_count = 0;
184
185#define DEV_READONLY(TGT) (0)
186#define DEV_REMOVEABLE(TGT) (0)
187
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400188static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189static sector_t sdebug_capacity; /* in sectors */
190
191/* old BIOS stuff, kernel may get rid of them but some mode sense pages
192 may still need them */
193static int sdebug_heads; /* heads per disk */
194static int sdebug_cylinders_per; /* cylinders per surface */
195static int sdebug_sectors_per; /* sectors per cylinder */
196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197#define SDEBUG_MAX_PARTS 4
198
199#define SDEBUG_SENSE_LEN 32
200
Martin K. Petersen395cef02009-09-18 17:33:03 -0400201#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203struct sdebug_dev_info {
204 struct list_head dev_list;
205 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
206 unsigned int channel;
207 unsigned int target;
208 unsigned int lun;
209 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400210 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400212 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 char used;
214};
215
216struct sdebug_host_info {
217 struct list_head host_list;
218 struct Scsi_Host *shost;
219 struct device dev;
220 struct list_head dev_info_list;
221};
222
223#define to_sdebug_host(d) \
224 container_of(d, struct sdebug_host_info, dev)
225
226static LIST_HEAD(sdebug_host_list);
227static DEFINE_SPINLOCK(sdebug_host_list_lock);
228
229typedef void (* done_funct_t) (struct scsi_cmnd *);
230
231struct sdebug_queued_cmd {
232 int in_use;
233 struct timer_list cmnd_timer;
234 done_funct_t done_funct;
235 struct scsi_cmnd * a_cmnd;
236 int scsi_result;
237};
238static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240static unsigned char * fake_storep; /* ramdisk storage */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500241static unsigned char *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400242static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Martin K. Petersen44d92692009-10-15 14:45:27 -0400244static unsigned long map_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245static int num_aborts = 0;
246static int num_dev_resets = 0;
247static int num_bus_resets = 0;
248static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500249static int dix_writes;
250static int dix_reads;
251static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253static DEFINE_SPINLOCK(queued_arr_lock);
254static DEFINE_RWLOCK(atomic_rw);
255
256static char sdebug_proc_name[] = "scsi_debug";
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258static struct bus_type pseudo_lld_bus;
259
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500260static inline sector_t dif_offset(sector_t sector)
261{
262 return sector << 3;
263}
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265static struct device_driver sdebug_driverfs_driver = {
266 .name = sdebug_proc_name,
267 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268};
269
270static const int check_condition_result =
271 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
272
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500273static const int illegal_condition_result =
274 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
275
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400276static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
277 0, 0, 0x2, 0x4b};
278static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
279 0, 0, 0x0, 0x0};
280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281static int sdebug_add_adapter(void);
282static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900284static void sdebug_max_tgts_luns(void)
285{
286 struct sdebug_host_info *sdbg_host;
287 struct Scsi_Host *hpnt;
288
289 spin_lock(&sdebug_host_list_lock);
290 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
291 hpnt = sdbg_host->shost;
292 if ((hpnt->this_id >= 0) &&
293 (scsi_debug_num_tgts > hpnt->this_id))
294 hpnt->max_id = scsi_debug_num_tgts + 1;
295 else
296 hpnt->max_id = scsi_debug_num_tgts;
297 /* scsi_debug_max_luns; */
298 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
299 }
300 spin_unlock(&sdebug_host_list_lock);
301}
302
303static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
304 int asc, int asq)
305{
306 unsigned char *sbuff;
307
308 sbuff = devip->sense_buff;
309 memset(sbuff, 0, SDEBUG_SENSE_LEN);
310
311 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
312
313 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
314 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
315 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
316}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900318static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400319 unsigned long long *lba, unsigned int *num,
320 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900321{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400322 *ei_lba = 0;
323
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900324 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400325 case VARIABLE_LENGTH_CMD:
326 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
327 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
328 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
329 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
330
331 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
332 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
333
334 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
335 (u32)cmd[28] << 24;
336 break;
337
Martin K. Petersen44d92692009-10-15 14:45:27 -0400338 case WRITE_SAME_16:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900339 case WRITE_16:
340 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900341 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
342 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
343 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
344 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
345
346 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
347 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900348 break;
349 case WRITE_12:
350 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900351 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
352 (u32)cmd[2] << 24;
353
354 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
355 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900356 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400357 case WRITE_SAME:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900358 case WRITE_10:
359 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900360 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900361 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
362 (u32)cmd[2] << 24;
363
364 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900365 break;
366 case WRITE_6:
367 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900368 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
369 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900370 *num = (0 == cmd[4]) ? 256 : cmd[4];
371 break;
372 default:
373 break;
374 }
375}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
378{
379 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
380 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
381 }
382 return -EINVAL;
383 /* return -ENOTTY; // correct return but upsets fdisk */
384}
385
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400386static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
387 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
389 if (devip->reset) {
390 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
391 printk(KERN_INFO "scsi_debug: Reporting Unit "
392 "attention: power on reset\n");
393 devip->reset = 0;
394 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
395 return check_condition_result;
396 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400397 if ((0 == reset_only) && devip->stopped) {
398 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
399 printk(KERN_INFO "scsi_debug: Reporting Not "
400 "ready: initializing command required\n");
401 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
402 0x2);
403 return check_condition_result;
404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 return 0;
406}
407
408/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900409static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 int arr_len)
411{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900412 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900413 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900415 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900417 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900419
420 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
421 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900422 if (sdb->resid)
423 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900425 sdb->resid = scsi_bufflen(scp) - act_len;
426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 return 0;
428}
429
430/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900431static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
432 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900434 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900436 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900438
439 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440}
441
442
443static const char * inq_vendor_id = "Linux ";
444static const char * inq_product_id = "scsi_debug ";
445static const char * inq_product_rev = "0004";
446
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200447static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
448 int target_dev_id, int dev_id_num,
449 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400450 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400452 int num, port_a;
453 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400455 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 /* T10 vendor identifier field format (faked) */
457 arr[0] = 0x2; /* ASCII */
458 arr[1] = 0x1;
459 arr[2] = 0x0;
460 memcpy(&arr[4], inq_vendor_id, 8);
461 memcpy(&arr[12], inq_product_id, 16);
462 memcpy(&arr[28], dev_id_str, dev_id_str_len);
463 num = 8 + 16 + dev_id_str_len;
464 arr[3] = num;
465 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400466 if (dev_id_num >= 0) {
467 /* NAA-5, Logical unit identifier (binary) */
468 arr[num++] = 0x1; /* binary (not necessarily sas) */
469 arr[num++] = 0x3; /* PIV=0, lu, naa */
470 arr[num++] = 0x0;
471 arr[num++] = 0x8;
472 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
473 arr[num++] = 0x33;
474 arr[num++] = 0x33;
475 arr[num++] = 0x30;
476 arr[num++] = (dev_id_num >> 24);
477 arr[num++] = (dev_id_num >> 16) & 0xff;
478 arr[num++] = (dev_id_num >> 8) & 0xff;
479 arr[num++] = dev_id_num & 0xff;
480 /* Target relative port number */
481 arr[num++] = 0x61; /* proto=sas, binary */
482 arr[num++] = 0x94; /* PIV=1, target port, rel port */
483 arr[num++] = 0x0; /* reserved */
484 arr[num++] = 0x4; /* length */
485 arr[num++] = 0x0; /* reserved */
486 arr[num++] = 0x0; /* reserved */
487 arr[num++] = 0x0;
488 arr[num++] = 0x1; /* relative port A */
489 }
490 /* NAA-5, Target port identifier */
491 arr[num++] = 0x61; /* proto=sas, binary */
492 arr[num++] = 0x93; /* piv=1, target port, naa */
493 arr[num++] = 0x0;
494 arr[num++] = 0x8;
495 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
496 arr[num++] = 0x22;
497 arr[num++] = 0x22;
498 arr[num++] = 0x20;
499 arr[num++] = (port_a >> 24);
500 arr[num++] = (port_a >> 16) & 0xff;
501 arr[num++] = (port_a >> 8) & 0xff;
502 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200503 /* NAA-5, Target port group identifier */
504 arr[num++] = 0x61; /* proto=sas, binary */
505 arr[num++] = 0x95; /* piv=1, target port group id */
506 arr[num++] = 0x0;
507 arr[num++] = 0x4;
508 arr[num++] = 0;
509 arr[num++] = 0;
510 arr[num++] = (port_group_id >> 8) & 0xff;
511 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400512 /* NAA-5, Target device identifier */
513 arr[num++] = 0x61; /* proto=sas, binary */
514 arr[num++] = 0xa3; /* piv=1, target device, naa */
515 arr[num++] = 0x0;
516 arr[num++] = 0x8;
517 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
518 arr[num++] = 0x22;
519 arr[num++] = 0x22;
520 arr[num++] = 0x20;
521 arr[num++] = (target_dev_id >> 24);
522 arr[num++] = (target_dev_id >> 16) & 0xff;
523 arr[num++] = (target_dev_id >> 8) & 0xff;
524 arr[num++] = target_dev_id & 0xff;
525 /* SCSI name string: Target device identifier */
526 arr[num++] = 0x63; /* proto=sas, UTF-8 */
527 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
528 arr[num++] = 0x0;
529 arr[num++] = 24;
530 memcpy(arr + num, "naa.52222220", 12);
531 num += 12;
532 snprintf(b, sizeof(b), "%08X", target_dev_id);
533 memcpy(arr + num, b, 8);
534 num += 8;
535 memset(arr + num, 0, 4);
536 num += 4;
537 return num;
538}
539
540
541static unsigned char vpd84_data[] = {
542/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
543 0x22,0x22,0x22,0x0,0xbb,0x1,
544 0x22,0x22,0x22,0x0,0xbb,0x2,
545};
546
547static int inquiry_evpd_84(unsigned char * arr)
548{
549 memcpy(arr, vpd84_data, sizeof(vpd84_data));
550 return sizeof(vpd84_data);
551}
552
553static int inquiry_evpd_85(unsigned char * arr)
554{
555 int num = 0;
556 const char * na1 = "https://www.kernel.org/config";
557 const char * na2 = "http://www.kernel.org/log";
558 int plen, olen;
559
560 arr[num++] = 0x1; /* lu, storage config */
561 arr[num++] = 0x0; /* reserved */
562 arr[num++] = 0x0;
563 olen = strlen(na1);
564 plen = olen + 1;
565 if (plen % 4)
566 plen = ((plen / 4) + 1) * 4;
567 arr[num++] = plen; /* length, null termianted, padded */
568 memcpy(arr + num, na1, olen);
569 memset(arr + num + olen, 0, plen - olen);
570 num += plen;
571
572 arr[num++] = 0x4; /* lu, logging */
573 arr[num++] = 0x0; /* reserved */
574 arr[num++] = 0x0;
575 olen = strlen(na2);
576 plen = olen + 1;
577 if (plen % 4)
578 plen = ((plen / 4) + 1) * 4;
579 arr[num++] = plen; /* length, null terminated, padded */
580 memcpy(arr + num, na2, olen);
581 memset(arr + num + olen, 0, plen - olen);
582 num += plen;
583
584 return num;
585}
586
587/* SCSI ports VPD page */
588static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
589{
590 int num = 0;
591 int port_a, port_b;
592
593 port_a = target_dev_id + 1;
594 port_b = port_a + 1;
595 arr[num++] = 0x0; /* reserved */
596 arr[num++] = 0x0; /* reserved */
597 arr[num++] = 0x0;
598 arr[num++] = 0x1; /* relative port 1 (primary) */
599 memset(arr + num, 0, 6);
600 num += 6;
601 arr[num++] = 0x0;
602 arr[num++] = 12; /* length tp descriptor */
603 /* naa-5 target port identifier (A) */
604 arr[num++] = 0x61; /* proto=sas, binary */
605 arr[num++] = 0x93; /* PIV=1, target port, NAA */
606 arr[num++] = 0x0; /* reserved */
607 arr[num++] = 0x8; /* length */
608 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
609 arr[num++] = 0x22;
610 arr[num++] = 0x22;
611 arr[num++] = 0x20;
612 arr[num++] = (port_a >> 24);
613 arr[num++] = (port_a >> 16) & 0xff;
614 arr[num++] = (port_a >> 8) & 0xff;
615 arr[num++] = port_a & 0xff;
616
617 arr[num++] = 0x0; /* reserved */
618 arr[num++] = 0x0; /* reserved */
619 arr[num++] = 0x0;
620 arr[num++] = 0x2; /* relative port 2 (secondary) */
621 memset(arr + num, 0, 6);
622 num += 6;
623 arr[num++] = 0x0;
624 arr[num++] = 12; /* length tp descriptor */
625 /* naa-5 target port identifier (B) */
626 arr[num++] = 0x61; /* proto=sas, binary */
627 arr[num++] = 0x93; /* PIV=1, target port, NAA */
628 arr[num++] = 0x0; /* reserved */
629 arr[num++] = 0x8; /* length */
630 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
631 arr[num++] = 0x22;
632 arr[num++] = 0x22;
633 arr[num++] = 0x20;
634 arr[num++] = (port_b >> 24);
635 arr[num++] = (port_b >> 16) & 0xff;
636 arr[num++] = (port_b >> 8) & 0xff;
637 arr[num++] = port_b & 0xff;
638
639 return num;
640}
641
642
643static unsigned char vpd89_data[] = {
644/* from 4th byte */ 0,0,0,0,
645'l','i','n','u','x',' ',' ',' ',
646'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
647'1','2','3','4',
6480x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6490xec,0,0,0,
6500x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6510,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6520x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6530x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6540x53,0x41,
6550x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6560x20,0x20,
6570x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6580x10,0x80,
6590,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6600x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6610x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6620,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6630x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6640x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6650,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6660,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6690x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6700,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6710xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6720,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6730,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
685};
686
687static int inquiry_evpd_89(unsigned char * arr)
688{
689 memcpy(arr, vpd89_data, sizeof(vpd89_data));
690 return sizeof(vpd89_data);
691}
692
693
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400694/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400695static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400696 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
697 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
698 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
699 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400700};
701
702static int inquiry_evpd_b0(unsigned char * arr)
703{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400704 unsigned int gran;
705
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400706 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400707 gran = 1 << scsi_debug_physblk_exp;
708 arr[2] = (gran >> 8) & 0xff;
709 arr[3] = gran & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400710 if (sdebug_store_sectors > 0x400) {
711 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
712 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
713 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
714 arr[7] = sdebug_store_sectors & 0xff;
715 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400716
717 if (scsi_debug_unmap_max_desc) {
718 unsigned int blocks;
719
720 if (scsi_debug_unmap_max_blocks)
721 blocks = scsi_debug_unmap_max_blocks;
722 else
723 blocks = 0xffffffff;
724
725 put_unaligned_be32(blocks, &arr[16]);
726 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
727 }
728
729 if (scsi_debug_unmap_alignment) {
730 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
731 arr[28] |= 0x80; /* UGAVALID */
732 }
733
734 if (scsi_debug_unmap_granularity) {
735 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
736 return 0x3c; /* Mandatory page length for thin provisioning */
737 }
738
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400739 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740}
741
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400742/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600743static int inquiry_evpd_b1(unsigned char *arr)
744{
745 memset(arr, 0, 0x3c);
746 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400747 arr[1] = 1; /* non rotating medium (e.g. solid state) */
748 arr[2] = 0;
749 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600750
751 return 0x3c;
752}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
754#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400755#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
757static int resp_inquiry(struct scsi_cmnd * scp, int target,
758 struct sdebug_dev_info * devip)
759{
760 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200761 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200763 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500766 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
767 if (! arr)
768 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400769 if (devip->wlun)
770 pq_pdt = 0x1e; /* present, wlun */
771 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
772 pq_pdt = 0x7f; /* not present, no device type */
773 else
774 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 arr[0] = pq_pdt;
776 if (0x2 & cmd[1]) { /* CMDDT bit set */
777 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
778 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200779 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return check_condition_result;
781 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200782 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400783 char lu_id_str[6];
784 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200786 port_group_id = (((host_no + 1) & 0x7f) << 8) +
787 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400788 if (0 == scsi_debug_vpd_use_hostno)
789 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400790 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
791 (devip->target * 1000) + devip->lun);
792 target_dev_id = ((host_no + 1) * 2000) +
793 (devip->target * 1000) - 3;
794 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400796 arr[1] = cmd[2]; /*sanity */
797 n = 4;
798 arr[n++] = 0x0; /* this page */
799 arr[n++] = 0x80; /* unit serial number */
800 arr[n++] = 0x83; /* device identification */
801 arr[n++] = 0x84; /* software interface ident. */
802 arr[n++] = 0x85; /* management network addresses */
803 arr[n++] = 0x86; /* extended inquiry */
804 arr[n++] = 0x87; /* mode page policy */
805 arr[n++] = 0x88; /* SCSI ports */
806 arr[n++] = 0x89; /* ATA information */
807 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600808 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400809 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400811 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400813 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400815 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200816 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
817 target_dev_id, lu_id_num,
818 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400819 } else if (0x84 == cmd[2]) { /* Software interface ident. */
820 arr[1] = cmd[2]; /*sanity */
821 arr[3] = inquiry_evpd_84(&arr[4]);
822 } else if (0x85 == cmd[2]) { /* Management network addresses */
823 arr[1] = cmd[2]; /*sanity */
824 arr[3] = inquiry_evpd_85(&arr[4]);
825 } else if (0x86 == cmd[2]) { /* extended inquiry */
826 arr[1] = cmd[2]; /*sanity */
827 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500828 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
829 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
830 else if (scsi_debug_dif)
831 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
832 else
833 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400834 arr[5] = 0x7; /* head of q, ordered + simple q's */
835 } else if (0x87 == cmd[2]) { /* mode page policy */
836 arr[1] = cmd[2]; /*sanity */
837 arr[3] = 0x8; /* number of following entries */
838 arr[4] = 0x2; /* disconnect-reconnect mp */
839 arr[6] = 0x80; /* mlus, shared */
840 arr[8] = 0x18; /* protocol specific lu */
841 arr[10] = 0x82; /* mlus, per initiator port */
842 } else if (0x88 == cmd[2]) { /* SCSI Ports */
843 arr[1] = cmd[2]; /*sanity */
844 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
845 } else if (0x89 == cmd[2]) { /* ATA information */
846 arr[1] = cmd[2]; /*sanity */
847 n = inquiry_evpd_89(&arr[4]);
848 arr[2] = (n >> 8);
849 arr[3] = (n & 0xff);
850 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
851 arr[1] = cmd[2]; /*sanity */
852 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600853 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
854 arr[1] = cmd[2]; /*sanity */
855 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 } else {
857 /* Illegal request, invalid field in cdb */
858 mk_sense_buffer(devip, ILLEGAL_REQUEST,
859 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200860 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 return check_condition_result;
862 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400863 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200864 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400865 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200866 kfree(arr);
867 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 }
869 /* drops through here for a standard inquiry */
870 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
871 arr[2] = scsi_debug_scsi_level;
872 arr[3] = 2; /* response_data_format==2 */
873 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500874 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200875 if (0 == scsi_debug_vpd_use_hostno)
876 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400877 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400879 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 memcpy(&arr[8], inq_vendor_id, 8);
881 memcpy(&arr[16], inq_product_id, 16);
882 memcpy(&arr[32], inq_product_rev, 4);
883 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400884 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
885 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
886 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400888 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400890 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400892 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200893 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200895 kfree(arr);
896 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897}
898
899static int resp_requests(struct scsi_cmnd * scp,
900 struct sdebug_dev_info * devip)
901{
902 unsigned char * sbuff;
903 unsigned char *cmd = (unsigned char *)scp->cmnd;
904 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400905 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 int len = 18;
907
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400908 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400910 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
911 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400913 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
914 if (want_dsense) {
915 arr[0] = 0x72;
916 arr[1] = 0x0; /* NO_SENSE in sense_key */
917 arr[2] = THRESHOLD_EXCEEDED;
918 arr[3] = 0xff; /* TEST set and MRIE==6 */
919 } else {
920 arr[0] = 0x70;
921 arr[2] = 0x0; /* NO_SENSE in sense_key */
922 arr[7] = 0xa; /* 18 byte sense buffer */
923 arr[12] = THRESHOLD_EXCEEDED;
924 arr[13] = 0xff; /* TEST set and MRIE==6 */
925 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400926 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400928 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
929 /* DESC bit set and sense_buff in fixed format */
930 memset(arr, 0, sizeof(arr));
931 arr[0] = 0x72;
932 arr[1] = sbuff[2]; /* sense key */
933 arr[2] = sbuff[12]; /* asc */
934 arr[3] = sbuff[13]; /* ascq */
935 len = 8;
936 }
937 }
938 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 return fill_from_dev_buffer(scp, arr, len);
940}
941
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400942static int resp_start_stop(struct scsi_cmnd * scp,
943 struct sdebug_dev_info * devip)
944{
945 unsigned char *cmd = (unsigned char *)scp->cmnd;
946 int power_cond, errsts, start;
947
948 if ((errsts = check_readiness(scp, 1, devip)))
949 return errsts;
950 power_cond = (cmd[4] & 0xf0) >> 4;
951 if (power_cond) {
952 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
953 0);
954 return check_condition_result;
955 }
956 start = cmd[4] & 1;
957 if (start == devip->stopped)
958 devip->stopped = !start;
959 return 0;
960}
961
FUJITA Tomonori28898872008-03-30 00:59:55 +0900962static sector_t get_sdebug_capacity(void)
963{
964 if (scsi_debug_virtual_gb > 0)
FUJITA Tomonori73da9c12009-04-22 17:42:25 -0700965 return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
FUJITA Tomonori28898872008-03-30 00:59:55 +0900966 else
967 return sdebug_store_sectors;
968}
969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970#define SDEBUG_READCAP_ARR_SZ 8
971static int resp_readcap(struct scsi_cmnd * scp,
972 struct sdebug_dev_info * devip)
973{
974 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400975 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 int errsts;
977
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400978 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400980 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900981 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400983 if (sdebug_capacity < 0xffffffff) {
984 capac = (unsigned int)sdebug_capacity - 1;
985 arr[0] = (capac >> 24);
986 arr[1] = (capac >> 16) & 0xff;
987 arr[2] = (capac >> 8) & 0xff;
988 arr[3] = capac & 0xff;
989 } else {
990 arr[0] = 0xff;
991 arr[1] = 0xff;
992 arr[2] = 0xff;
993 arr[3] = 0xff;
994 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400995 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
996 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
998}
999
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001000#define SDEBUG_READCAP16_ARR_SZ 32
1001static int resp_readcap16(struct scsi_cmnd * scp,
1002 struct sdebug_dev_info * devip)
1003{
1004 unsigned char *cmd = (unsigned char *)scp->cmnd;
1005 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1006 unsigned long long capac;
1007 int errsts, k, alloc_len;
1008
1009 if ((errsts = check_readiness(scp, 1, devip)))
1010 return errsts;
1011 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1012 + cmd[13]);
1013 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001014 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001015 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1016 capac = sdebug_capacity - 1;
1017 for (k = 0; k < 8; ++k, capac >>= 8)
1018 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001019 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1020 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1021 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1022 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001023 arr[13] = scsi_debug_physblk_exp & 0xf;
1024 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001025
1026 if (scsi_debug_unmap_granularity)
1027 arr[14] |= 0x80; /* TPE */
1028
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001029 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001030
1031 if (scsi_debug_dif) {
1032 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1033 arr[12] |= 1; /* PROT_EN */
1034 }
1035
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001036 return fill_from_dev_buffer(scp, arr,
1037 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1038}
1039
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001040#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1041
1042static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1043 struct sdebug_dev_info * devip)
1044{
1045 unsigned char *cmd = (unsigned char *)scp->cmnd;
1046 unsigned char * arr;
1047 int host_no = devip->sdbg_host->shost->host_no;
1048 int n, ret, alen, rlen;
1049 int port_group_a, port_group_b, port_a, port_b;
1050
1051 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1052 + cmd[9]);
1053
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001054 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1055 if (! arr)
1056 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001057 /*
1058 * EVPD page 0x88 states we have two ports, one
1059 * real and a fake port with no device connected.
1060 * So we create two port groups with one port each
1061 * and set the group with port B to unavailable.
1062 */
1063 port_a = 0x1; /* relative port A */
1064 port_b = 0x2; /* relative port B */
1065 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1066 (devip->channel & 0x7f);
1067 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1068 (devip->channel & 0x7f) + 0x80;
1069
1070 /*
1071 * The asymmetric access state is cycled according to the host_id.
1072 */
1073 n = 4;
1074 if (0 == scsi_debug_vpd_use_hostno) {
1075 arr[n++] = host_no % 3; /* Asymm access state */
1076 arr[n++] = 0x0F; /* claim: all states are supported */
1077 } else {
1078 arr[n++] = 0x0; /* Active/Optimized path */
1079 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1080 }
1081 arr[n++] = (port_group_a >> 8) & 0xff;
1082 arr[n++] = port_group_a & 0xff;
1083 arr[n++] = 0; /* Reserved */
1084 arr[n++] = 0; /* Status code */
1085 arr[n++] = 0; /* Vendor unique */
1086 arr[n++] = 0x1; /* One port per group */
1087 arr[n++] = 0; /* Reserved */
1088 arr[n++] = 0; /* Reserved */
1089 arr[n++] = (port_a >> 8) & 0xff;
1090 arr[n++] = port_a & 0xff;
1091 arr[n++] = 3; /* Port unavailable */
1092 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1093 arr[n++] = (port_group_b >> 8) & 0xff;
1094 arr[n++] = port_group_b & 0xff;
1095 arr[n++] = 0; /* Reserved */
1096 arr[n++] = 0; /* Status code */
1097 arr[n++] = 0; /* Vendor unique */
1098 arr[n++] = 0x1; /* One port per group */
1099 arr[n++] = 0; /* Reserved */
1100 arr[n++] = 0; /* Reserved */
1101 arr[n++] = (port_b >> 8) & 0xff;
1102 arr[n++] = port_b & 0xff;
1103
1104 rlen = n - 4;
1105 arr[0] = (rlen >> 24) & 0xff;
1106 arr[1] = (rlen >> 16) & 0xff;
1107 arr[2] = (rlen >> 8) & 0xff;
1108 arr[3] = rlen & 0xff;
1109
1110 /*
1111 * Return the smallest value of either
1112 * - The allocated length
1113 * - The constructed command length
1114 * - The maximum array size
1115 */
1116 rlen = min(alen,n);
1117 ret = fill_from_dev_buffer(scp, arr,
1118 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1119 kfree(arr);
1120 return ret;
1121}
1122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123/* <<Following mode page info copied from ST318451LW>> */
1124
1125static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1126{ /* Read-Write Error Recovery page for mode_sense */
1127 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1128 5, 0, 0xff, 0xff};
1129
1130 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1131 if (1 == pcontrol)
1132 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1133 return sizeof(err_recov_pg);
1134}
1135
1136static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1137{ /* Disconnect-Reconnect page for mode_sense */
1138 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1139 0, 0, 0, 0, 0, 0, 0, 0};
1140
1141 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1142 if (1 == pcontrol)
1143 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1144 return sizeof(disconnect_pg);
1145}
1146
1147static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1148{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001149 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1150 0, 0, 0, 0, 0, 0, 0, 0,
1151 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Martin K. Petersen597136a2008-06-05 00:12:59 -04001153 memcpy(p, format_pg, sizeof(format_pg));
1154 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1155 p[11] = sdebug_sectors_per & 0xff;
1156 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1157 p[13] = scsi_debug_sector_size & 0xff;
1158 if (DEV_REMOVEABLE(target))
1159 p[20] |= 0x20; /* should agree with INQUIRY */
1160 if (1 == pcontrol)
1161 memset(p + 2, 0, sizeof(format_pg) - 2);
1162 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163}
1164
1165static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1166{ /* Caching page for mode_sense */
1167 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1168 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1169
1170 memcpy(p, caching_pg, sizeof(caching_pg));
1171 if (1 == pcontrol)
1172 memset(p + 2, 0, sizeof(caching_pg) - 2);
1173 return sizeof(caching_pg);
1174}
1175
1176static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1177{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001178 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1179 0, 0, 0, 0};
1180 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 0, 0, 0x2, 0x4b};
1182
1183 if (scsi_debug_dsense)
1184 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001185 else
1186 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001187
1188 if (scsi_debug_ato)
1189 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1190
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1192 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001193 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1194 else if (2 == pcontrol)
1195 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 return sizeof(ctrl_m_pg);
1197}
1198
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1201{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001202 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1203 0, 0, 0x0, 0x0};
1204 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1205 0, 0, 0x0, 0x0};
1206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1208 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001209 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1210 else if (2 == pcontrol)
1211 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 return sizeof(iec_m_pg);
1213}
1214
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001215static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1216{ /* SAS SSP mode page - short format for mode_sense */
1217 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1218 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1219
1220 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1221 if (1 == pcontrol)
1222 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1223 return sizeof(sas_sf_m_pg);
1224}
1225
1226
1227static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1228 int target_dev_id)
1229{ /* SAS phy control and discover mode page for mode_sense */
1230 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1231 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1232 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1233 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1234 0x2, 0, 0, 0, 0, 0, 0, 0,
1235 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1236 0, 0, 0, 0, 0, 0, 0, 0,
1237 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1238 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1239 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1240 0x3, 0, 0, 0, 0, 0, 0, 0,
1241 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1242 0, 0, 0, 0, 0, 0, 0, 0,
1243 };
1244 int port_a, port_b;
1245
1246 port_a = target_dev_id + 1;
1247 port_b = port_a + 1;
1248 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1249 p[20] = (port_a >> 24);
1250 p[21] = (port_a >> 16) & 0xff;
1251 p[22] = (port_a >> 8) & 0xff;
1252 p[23] = port_a & 0xff;
1253 p[48 + 20] = (port_b >> 24);
1254 p[48 + 21] = (port_b >> 16) & 0xff;
1255 p[48 + 22] = (port_b >> 8) & 0xff;
1256 p[48 + 23] = port_b & 0xff;
1257 if (1 == pcontrol)
1258 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1259 return sizeof(sas_pcd_m_pg);
1260}
1261
1262static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1263{ /* SAS SSP shared protocol specific port mode subpage */
1264 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1265 0, 0, 0, 0, 0, 0, 0, 0,
1266 };
1267
1268 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1269 if (1 == pcontrol)
1270 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1271 return sizeof(sas_sha_m_pg);
1272}
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274#define SDEBUG_MAX_MSENSE_SZ 256
1275
1276static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1277 struct sdebug_dev_info * devip)
1278{
Douglas Gilbert23183912006-09-16 20:30:47 -04001279 unsigned char dbd, llbaa;
1280 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001282 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 unsigned char * ap;
1284 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1285 unsigned char *cmd = (unsigned char *)scp->cmnd;
1286
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001287 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001289 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 pcontrol = (cmd[2] & 0xc0) >> 6;
1291 pcode = cmd[2] & 0x3f;
1292 subpcode = cmd[3];
1293 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001294 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1295 if ((0 == scsi_debug_ptype) && (0 == dbd))
1296 bd_len = llbaa ? 16 : 8;
1297 else
1298 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1300 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1301 if (0x3 == pcontrol) { /* Saving values not supported */
1302 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1303 0);
1304 return check_condition_result;
1305 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001306 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1307 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001308 /* set DPOFUA bit for disks */
1309 if (0 == scsi_debug_ptype)
1310 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1311 else
1312 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 if (msense_6) {
1314 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001315 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 offset = 4;
1317 } else {
1318 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001319 if (16 == bd_len)
1320 arr[4] = 0x1; /* set LONGLBA bit */
1321 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 offset = 8;
1323 }
1324 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001325 if ((bd_len > 0) && (!sdebug_capacity))
1326 sdebug_capacity = get_sdebug_capacity();
1327
Douglas Gilbert23183912006-09-16 20:30:47 -04001328 if (8 == bd_len) {
1329 if (sdebug_capacity > 0xfffffffe) {
1330 ap[0] = 0xff;
1331 ap[1] = 0xff;
1332 ap[2] = 0xff;
1333 ap[3] = 0xff;
1334 } else {
1335 ap[0] = (sdebug_capacity >> 24) & 0xff;
1336 ap[1] = (sdebug_capacity >> 16) & 0xff;
1337 ap[2] = (sdebug_capacity >> 8) & 0xff;
1338 ap[3] = sdebug_capacity & 0xff;
1339 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001340 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1341 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001342 offset += bd_len;
1343 ap = arr + offset;
1344 } else if (16 == bd_len) {
1345 unsigned long long capac = sdebug_capacity;
1346
1347 for (k = 0; k < 8; ++k, capac >>= 8)
1348 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001349 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1350 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1351 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1352 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001353 offset += bd_len;
1354 ap = arr + offset;
1355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001357 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1358 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1360 0);
1361 return check_condition_result;
1362 }
1363 switch (pcode) {
1364 case 0x1: /* Read-Write error recovery page, direct access */
1365 len = resp_err_recov_pg(ap, pcontrol, target);
1366 offset += len;
1367 break;
1368 case 0x2: /* Disconnect-Reconnect page, all devices */
1369 len = resp_disconnect_pg(ap, pcontrol, target);
1370 offset += len;
1371 break;
1372 case 0x3: /* Format device page, direct access */
1373 len = resp_format_pg(ap, pcontrol, target);
1374 offset += len;
1375 break;
1376 case 0x8: /* Caching page, direct access */
1377 len = resp_caching_pg(ap, pcontrol, target);
1378 offset += len;
1379 break;
1380 case 0xa: /* Control Mode page, all devices */
1381 len = resp_ctrl_m_pg(ap, pcontrol, target);
1382 offset += len;
1383 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001384 case 0x19: /* if spc==1 then sas phy, control+discover */
1385 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1386 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1387 INVALID_FIELD_IN_CDB, 0);
1388 return check_condition_result;
1389 }
1390 len = 0;
1391 if ((0x0 == subpcode) || (0xff == subpcode))
1392 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1393 if ((0x1 == subpcode) || (0xff == subpcode))
1394 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1395 target_dev_id);
1396 if ((0x2 == subpcode) || (0xff == subpcode))
1397 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1398 offset += len;
1399 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 case 0x1c: /* Informational Exceptions Mode page, all devices */
1401 len = resp_iec_m_pg(ap, pcontrol, target);
1402 offset += len;
1403 break;
1404 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001405 if ((0 == subpcode) || (0xff == subpcode)) {
1406 len = resp_err_recov_pg(ap, pcontrol, target);
1407 len += resp_disconnect_pg(ap + len, pcontrol, target);
1408 len += resp_format_pg(ap + len, pcontrol, target);
1409 len += resp_caching_pg(ap + len, pcontrol, target);
1410 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1411 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1412 if (0xff == subpcode) {
1413 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1414 target, target_dev_id);
1415 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1416 }
1417 len += resp_iec_m_pg(ap + len, pcontrol, target);
1418 } else {
1419 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1420 INVALID_FIELD_IN_CDB, 0);
1421 return check_condition_result;
1422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 offset += len;
1424 break;
1425 default:
1426 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1427 0);
1428 return check_condition_result;
1429 }
1430 if (msense_6)
1431 arr[0] = offset - 1;
1432 else {
1433 arr[0] = ((offset - 2) >> 8) & 0xff;
1434 arr[1] = (offset - 2) & 0xff;
1435 }
1436 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1437}
1438
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001439#define SDEBUG_MAX_MSELECT_SZ 512
1440
1441static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1442 struct sdebug_dev_info * devip)
1443{
1444 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1445 int param_len, res, errsts, mpage;
1446 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1447 unsigned char *cmd = (unsigned char *)scp->cmnd;
1448
1449 if ((errsts = check_readiness(scp, 1, devip)))
1450 return errsts;
1451 memset(arr, 0, sizeof(arr));
1452 pf = cmd[1] & 0x10;
1453 sp = cmd[1] & 0x1;
1454 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1455 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1456 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1457 INVALID_FIELD_IN_CDB, 0);
1458 return check_condition_result;
1459 }
1460 res = fetch_to_dev_buffer(scp, arr, param_len);
1461 if (-1 == res)
1462 return (DID_ERROR << 16);
1463 else if ((res < param_len) &&
1464 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1465 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1466 " IO sent=%d bytes\n", param_len, res);
1467 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1468 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001469 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001470 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1471 INVALID_FIELD_IN_PARAM_LIST, 0);
1472 return check_condition_result;
1473 }
1474 off = bd_len + (mselect6 ? 4 : 8);
1475 mpage = arr[off] & 0x3f;
1476 ps = !!(arr[off] & 0x80);
1477 if (ps) {
1478 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1479 INVALID_FIELD_IN_PARAM_LIST, 0);
1480 return check_condition_result;
1481 }
1482 spf = !!(arr[off] & 0x40);
1483 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1484 (arr[off + 1] + 2);
1485 if ((pg_len + off) > param_len) {
1486 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1487 PARAMETER_LIST_LENGTH_ERR, 0);
1488 return check_condition_result;
1489 }
1490 switch (mpage) {
1491 case 0xa: /* Control Mode page */
1492 if (ctrl_m_pg[1] == arr[off + 1]) {
1493 memcpy(ctrl_m_pg + 2, arr + off + 2,
1494 sizeof(ctrl_m_pg) - 2);
1495 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1496 return 0;
1497 }
1498 break;
1499 case 0x1c: /* Informational Exceptions Mode page */
1500 if (iec_m_pg[1] == arr[off + 1]) {
1501 memcpy(iec_m_pg + 2, arr + off + 2,
1502 sizeof(iec_m_pg) - 2);
1503 return 0;
1504 }
1505 break;
1506 default:
1507 break;
1508 }
1509 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1510 INVALID_FIELD_IN_PARAM_LIST, 0);
1511 return check_condition_result;
1512}
1513
1514static int resp_temp_l_pg(unsigned char * arr)
1515{
1516 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1517 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1518 };
1519
1520 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1521 return sizeof(temp_l_pg);
1522}
1523
1524static int resp_ie_l_pg(unsigned char * arr)
1525{
1526 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1527 };
1528
1529 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1530 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1531 arr[4] = THRESHOLD_EXCEEDED;
1532 arr[5] = 0xff;
1533 }
1534 return sizeof(ie_l_pg);
1535}
1536
1537#define SDEBUG_MAX_LSENSE_SZ 512
1538
1539static int resp_log_sense(struct scsi_cmnd * scp,
1540 struct sdebug_dev_info * devip)
1541{
Douglas Gilbert23183912006-09-16 20:30:47 -04001542 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001543 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1544 unsigned char *cmd = (unsigned char *)scp->cmnd;
1545
1546 if ((errsts = check_readiness(scp, 1, devip)))
1547 return errsts;
1548 memset(arr, 0, sizeof(arr));
1549 ppc = cmd[1] & 0x2;
1550 sp = cmd[1] & 0x1;
1551 if (ppc || sp) {
1552 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1553 INVALID_FIELD_IN_CDB, 0);
1554 return check_condition_result;
1555 }
1556 pcontrol = (cmd[2] & 0xc0) >> 6;
1557 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001558 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001559 alloc_len = (cmd[7] << 8) + cmd[8];
1560 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001561 if (0 == subpcode) {
1562 switch (pcode) {
1563 case 0x0: /* Supported log pages log page */
1564 n = 4;
1565 arr[n++] = 0x0; /* this page */
1566 arr[n++] = 0xd; /* Temperature */
1567 arr[n++] = 0x2f; /* Informational exceptions */
1568 arr[3] = n - 4;
1569 break;
1570 case 0xd: /* Temperature log page */
1571 arr[3] = resp_temp_l_pg(arr + 4);
1572 break;
1573 case 0x2f: /* Informational exceptions log page */
1574 arr[3] = resp_ie_l_pg(arr + 4);
1575 break;
1576 default:
1577 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1578 INVALID_FIELD_IN_CDB, 0);
1579 return check_condition_result;
1580 }
1581 } else if (0xff == subpcode) {
1582 arr[0] |= 0x40;
1583 arr[1] = subpcode;
1584 switch (pcode) {
1585 case 0x0: /* Supported log pages and subpages log page */
1586 n = 4;
1587 arr[n++] = 0x0;
1588 arr[n++] = 0x0; /* 0,0 page */
1589 arr[n++] = 0x0;
1590 arr[n++] = 0xff; /* this page */
1591 arr[n++] = 0xd;
1592 arr[n++] = 0x0; /* Temperature */
1593 arr[n++] = 0x2f;
1594 arr[n++] = 0x0; /* Informational exceptions */
1595 arr[3] = n - 4;
1596 break;
1597 case 0xd: /* Temperature subpages */
1598 n = 4;
1599 arr[n++] = 0xd;
1600 arr[n++] = 0x0; /* Temperature */
1601 arr[3] = n - 4;
1602 break;
1603 case 0x2f: /* Informational exceptions subpages */
1604 n = 4;
1605 arr[n++] = 0x2f;
1606 arr[n++] = 0x0; /* Informational exceptions */
1607 arr[3] = n - 4;
1608 break;
1609 default:
1610 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1611 INVALID_FIELD_IN_CDB, 0);
1612 return check_condition_result;
1613 }
1614 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001615 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1616 INVALID_FIELD_IN_CDB, 0);
1617 return check_condition_result;
1618 }
1619 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1620 return fill_from_dev_buffer(scp, arr,
1621 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1622}
1623
FUJITA Tomonori19789102008-03-30 00:59:56 +09001624static int check_device_access_params(struct sdebug_dev_info *devi,
1625 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001628 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 return check_condition_result;
1630 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001631 /* transfer length excessive (tie in to block limits VPD page) */
1632 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001633 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001634 return check_condition_result;
1635 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001636 return 0;
1637}
1638
1639static int do_device_access(struct scsi_cmnd *scmd,
1640 struct sdebug_dev_info *devi,
1641 unsigned long long lba, unsigned int num, int write)
1642{
1643 int ret;
1644 unsigned int block, rest = 0;
1645 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1646
1647 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1648
1649 block = do_div(lba, sdebug_store_sectors);
1650 if (block + num > sdebug_store_sectors)
1651 rest = block + num - sdebug_store_sectors;
1652
Martin K. Petersen597136a2008-06-05 00:12:59 -04001653 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1654 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001655 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001656 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001657
1658 return ret;
1659}
1660
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001661static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001662 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001663{
1664 unsigned int i, resid;
1665 struct scatterlist *psgl;
1666 struct sd_dif_tuple *sdt;
1667 sector_t sector;
1668 sector_t tmp_sec = start_sec;
1669 void *paddr;
1670
1671 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1672
1673 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1674
1675 for (i = 0 ; i < sectors ; i++) {
1676 u16 csum;
1677
1678 if (sdt[i].app_tag == 0xffff)
1679 continue;
1680
1681 sector = start_sec + i;
1682
1683 switch (scsi_debug_guard) {
1684 case 1:
1685 csum = ip_compute_csum(fake_storep +
1686 sector * scsi_debug_sector_size,
1687 scsi_debug_sector_size);
1688 break;
1689 case 0:
1690 csum = crc_t10dif(fake_storep +
1691 sector * scsi_debug_sector_size,
1692 scsi_debug_sector_size);
1693 csum = cpu_to_be16(csum);
1694 break;
1695 default:
1696 BUG();
1697 }
1698
1699 if (sdt[i].guard_tag != csum) {
1700 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1701 " rcvd 0x%04x, data 0x%04x\n", __func__,
1702 (unsigned long)sector,
1703 be16_to_cpu(sdt[i].guard_tag),
1704 be16_to_cpu(csum));
1705 dif_errors++;
1706 return 0x01;
1707 }
1708
Martin K. Petersen395cef02009-09-18 17:33:03 -04001709 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001710 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1711 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1712 __func__, (unsigned long)sector);
1713 dif_errors++;
1714 return 0x03;
1715 }
Martin K. Petersen395cef02009-09-18 17:33:03 -04001716
1717 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1718 be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1719 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1720 __func__, (unsigned long)sector);
1721 dif_errors++;
1722 return 0x03;
1723 }
1724
1725 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001726 }
1727
1728 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1729 sector = start_sec;
1730
1731 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1732 int len = min(psgl->length, resid);
1733
1734 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1735 memcpy(paddr, dif_storep + dif_offset(sector), len);
1736
1737 sector += len >> 3;
1738 if (sector >= sdebug_store_sectors) {
1739 /* Force wrap */
1740 tmp_sec = sector;
1741 sector = do_div(tmp_sec, sdebug_store_sectors);
1742 }
1743 resid -= len;
1744 kunmap_atomic(paddr, KM_IRQ0);
1745 }
1746
1747 dix_reads++;
1748
1749 return 0;
1750}
1751
FUJITA Tomonori19789102008-03-30 00:59:56 +09001752static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001753 unsigned int num, struct sdebug_dev_info *devip,
1754 u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001755{
1756 unsigned long iflags;
1757 int ret;
1758
1759 ret = check_device_access_params(devip, lba, num);
1760 if (ret)
1761 return ret;
1762
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001764 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1765 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1766 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1768 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001769 /* set info field and valid bit for fixed descriptor */
1770 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1771 devip->sense_buff[0] |= 0x80; /* Valid bit */
1772 ret = OPT_MEDIUM_ERR_ADDR;
1773 devip->sense_buff[3] = (ret >> 24) & 0xff;
1774 devip->sense_buff[4] = (ret >> 16) & 0xff;
1775 devip->sense_buff[5] = (ret >> 8) & 0xff;
1776 devip->sense_buff[6] = ret & 0xff;
1777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 return check_condition_result;
1779 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001780
1781 /* DIX + T10 DIF */
1782 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001783 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001784
1785 if (prot_ret) {
1786 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1787 return illegal_condition_result;
1788 }
1789 }
1790
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001792 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 read_unlock_irqrestore(&atomic_rw, iflags);
1794 return ret;
1795}
1796
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001797void dump_sector(unsigned char *buf, int len)
1798{
1799 int i, j;
1800
1801 printk(KERN_ERR ">>> Sector Dump <<<\n");
1802
1803 for (i = 0 ; i < len ; i += 16) {
1804 printk(KERN_ERR "%04d: ", i);
1805
1806 for (j = 0 ; j < 16 ; j++) {
1807 unsigned char c = buf[i+j];
1808 if (c >= 0x20 && c < 0x7e)
1809 printk(" %c ", buf[i+j]);
1810 else
1811 printk("%02x ", buf[i+j]);
1812 }
1813
1814 printk("\n");
1815 }
1816}
1817
1818static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001819 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001820{
1821 int i, j, ret;
1822 struct sd_dif_tuple *sdt;
1823 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1824 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1825 void *daddr, *paddr;
1826 sector_t tmp_sec = start_sec;
1827 sector_t sector;
1828 int ppage_offset;
1829 unsigned short csum;
1830
1831 sector = do_div(tmp_sec, sdebug_store_sectors);
1832
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001833 BUG_ON(scsi_sg_count(SCpnt) == 0);
1834 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1835
1836 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1837 ppage_offset = 0;
1838
1839 /* For each data page */
1840 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1841 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1842
1843 /* For each sector-sized chunk in data page */
1844 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1845
1846 /* If we're at the end of the current
1847 * protection page advance to the next one
1848 */
1849 if (ppage_offset >= psgl->length) {
1850 kunmap_atomic(paddr, KM_IRQ1);
1851 psgl = sg_next(psgl);
1852 BUG_ON(psgl == NULL);
1853 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1854 + psgl->offset;
1855 ppage_offset = 0;
1856 }
1857
1858 sdt = paddr + ppage_offset;
1859
1860 switch (scsi_debug_guard) {
1861 case 1:
1862 csum = ip_compute_csum(daddr,
1863 scsi_debug_sector_size);
1864 break;
1865 case 0:
1866 csum = cpu_to_be16(crc_t10dif(daddr,
1867 scsi_debug_sector_size));
1868 break;
1869 default:
1870 BUG();
1871 ret = 0;
1872 goto out;
1873 }
1874
1875 if (sdt->guard_tag != csum) {
1876 printk(KERN_ERR
1877 "%s: GUARD check failed on sector %lu " \
1878 "rcvd 0x%04x, calculated 0x%04x\n",
1879 __func__, (unsigned long)sector,
1880 be16_to_cpu(sdt->guard_tag),
1881 be16_to_cpu(csum));
1882 ret = 0x01;
1883 dump_sector(daddr, scsi_debug_sector_size);
1884 goto out;
1885 }
1886
Martin K. Petersen395cef02009-09-18 17:33:03 -04001887 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001888 be32_to_cpu(sdt->ref_tag)
1889 != (start_sec & 0xffffffff)) {
1890 printk(KERN_ERR
1891 "%s: REF check failed on sector %lu\n",
1892 __func__, (unsigned long)sector);
1893 ret = 0x03;
1894 dump_sector(daddr, scsi_debug_sector_size);
1895 goto out;
1896 }
1897
Martin K. Petersen395cef02009-09-18 17:33:03 -04001898 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1899 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1900 printk(KERN_ERR
1901 "%s: REF check failed on sector %lu\n",
1902 __func__, (unsigned long)sector);
1903 ret = 0x03;
1904 dump_sector(daddr, scsi_debug_sector_size);
1905 goto out;
1906 }
1907
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001908 /* Would be great to copy this in bigger
1909 * chunks. However, for the sake of
1910 * correctness we need to verify each sector
1911 * before writing it to "stable" storage
1912 */
1913 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1914
1915 sector++;
1916
1917 if (sector == sdebug_store_sectors)
1918 sector = 0; /* Force wrap */
1919
1920 start_sec++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001921 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001922 daddr += scsi_debug_sector_size;
1923 ppage_offset += sizeof(struct sd_dif_tuple);
1924 }
1925
1926 kunmap_atomic(daddr, KM_IRQ0);
1927 }
1928
1929 kunmap_atomic(paddr, KM_IRQ1);
1930
1931 dix_writes++;
1932
1933 return 0;
1934
1935out:
1936 dif_errors++;
1937 kunmap_atomic(daddr, KM_IRQ0);
1938 kunmap_atomic(paddr, KM_IRQ1);
1939 return ret;
1940}
1941
Martin K. Petersen44d92692009-10-15 14:45:27 -04001942static unsigned int map_state(sector_t lba, unsigned int *num)
1943{
1944 unsigned int granularity, alignment, mapped;
1945 sector_t block, next, end;
1946
1947 granularity = scsi_debug_unmap_granularity;
1948 alignment = granularity - scsi_debug_unmap_alignment;
1949 block = lba + alignment;
1950 do_div(block, granularity);
1951
1952 mapped = test_bit(block, map_storep);
1953
1954 if (mapped)
1955 next = find_next_zero_bit(map_storep, map_size, block);
1956 else
1957 next = find_next_bit(map_storep, map_size, block);
1958
1959 end = next * granularity - scsi_debug_unmap_alignment;
1960 *num = end - lba;
1961
1962 return mapped;
1963}
1964
1965static void map_region(sector_t lba, unsigned int len)
1966{
1967 unsigned int granularity, alignment;
1968 sector_t end = lba + len;
1969
1970 granularity = scsi_debug_unmap_granularity;
1971 alignment = granularity - scsi_debug_unmap_alignment;
1972
1973 while (lba < end) {
1974 sector_t block, rem;
1975
1976 block = lba + alignment;
1977 rem = do_div(block, granularity);
1978
1979 set_bit(block, map_storep);
1980
1981 lba += granularity - rem;
1982 }
1983}
1984
1985static void unmap_region(sector_t lba, unsigned int len)
1986{
1987 unsigned int granularity, alignment;
1988 sector_t end = lba + len;
1989
1990 granularity = scsi_debug_unmap_granularity;
1991 alignment = granularity - scsi_debug_unmap_alignment;
1992
1993 while (lba < end) {
1994 sector_t block, rem;
1995
1996 block = lba + alignment;
1997 rem = do_div(block, granularity);
1998
1999 if (rem == 0 && lba + granularity <= end)
2000 clear_bit(block, map_storep);
2001
2002 lba += granularity - rem;
2003 }
2004}
2005
FUJITA Tomonori19789102008-03-30 00:59:56 +09002006static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002007 unsigned int num, struct sdebug_dev_info *devip,
2008 u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009{
2010 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002011 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
FUJITA Tomonori19789102008-03-30 00:59:56 +09002013 ret = check_device_access_params(devip, lba, num);
2014 if (ret)
2015 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002017 /* DIX + T10 DIF */
2018 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002019 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002020
2021 if (prot_ret) {
2022 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2023 return illegal_condition_result;
2024 }
2025 }
2026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002028 ret = do_device_access(SCpnt, devip, lba, num, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002029 if (scsi_debug_unmap_granularity)
2030 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002032 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002034 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002036 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04002037 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002038
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 return 0;
2040}
2041
Martin K. Petersen44d92692009-10-15 14:45:27 -04002042static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
2043 unsigned int num, struct sdebug_dev_info *devip,
2044 u32 ei_lba, unsigned int unmap)
2045{
2046 unsigned long iflags;
2047 unsigned long long i;
2048 int ret;
2049
2050 ret = check_device_access_params(devip, lba, num);
2051 if (ret)
2052 return ret;
2053
2054 write_lock_irqsave(&atomic_rw, iflags);
2055
2056 if (unmap && scsi_debug_unmap_granularity) {
2057 unmap_region(lba, num);
2058 goto out;
2059 }
2060
2061 /* Else fetch one logical block */
2062 ret = fetch_to_dev_buffer(scmd,
2063 fake_storep + (lba * scsi_debug_sector_size),
2064 scsi_debug_sector_size);
2065
2066 if (-1 == ret) {
2067 write_unlock_irqrestore(&atomic_rw, iflags);
2068 return (DID_ERROR << 16);
2069 } else if ((ret < (num * scsi_debug_sector_size)) &&
2070 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2071 printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
2072 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
2073
2074 /* Copy first sector to remaining blocks */
2075 for (i = 1 ; i < num ; i++)
2076 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2077 fake_storep + (lba * scsi_debug_sector_size),
2078 scsi_debug_sector_size);
2079
2080 if (scsi_debug_unmap_granularity)
2081 map_region(lba, num);
2082out:
2083 write_unlock_irqrestore(&atomic_rw, iflags);
2084
2085 return 0;
2086}
2087
2088struct unmap_block_desc {
2089 __be64 lba;
2090 __be32 blocks;
2091 __be32 __reserved;
2092};
2093
2094static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2095{
2096 unsigned char *buf;
2097 struct unmap_block_desc *desc;
2098 unsigned int i, payload_len, descriptors;
2099 int ret;
2100
2101 ret = check_readiness(scmd, 1, devip);
2102 if (ret)
2103 return ret;
2104
2105 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2106 BUG_ON(scsi_bufflen(scmd) != payload_len);
2107
2108 descriptors = (payload_len - 8) / 16;
2109
2110 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2111 if (!buf)
2112 return check_condition_result;
2113
2114 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2115
2116 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2117 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2118
2119 desc = (void *)&buf[8];
2120
2121 for (i = 0 ; i < descriptors ; i++) {
2122 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2123 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2124
2125 ret = check_device_access_params(devip, lba, num);
2126 if (ret)
2127 goto out;
2128
2129 unmap_region(lba, num);
2130 }
2131
2132 ret = 0;
2133
2134out:
2135 kfree(buf);
2136
2137 return ret;
2138}
2139
2140#define SDEBUG_GET_LBA_STATUS_LEN 32
2141
2142static int resp_get_lba_status(struct scsi_cmnd * scmd,
2143 struct sdebug_dev_info * devip)
2144{
2145 unsigned long long lba;
2146 unsigned int alloc_len, mapped, num;
2147 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2148 int ret;
2149
2150 ret = check_readiness(scmd, 1, devip);
2151 if (ret)
2152 return ret;
2153
2154 lba = get_unaligned_be64(&scmd->cmnd[2]);
2155 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2156
2157 if (alloc_len < 24)
2158 return 0;
2159
2160 ret = check_device_access_params(devip, lba, 1);
2161 if (ret)
2162 return ret;
2163
2164 mapped = map_state(lba, &num);
2165
2166 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2167 put_unaligned_be32(16, &arr[0]); /* Parameter Data Length */
2168 put_unaligned_be64(lba, &arr[8]); /* LBA */
2169 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2170 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2171
2172 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2173}
2174
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002175#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
2177static int resp_report_luns(struct scsi_cmnd * scp,
2178 struct sdebug_dev_info * devip)
2179{
2180 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002181 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 unsigned char *cmd = (unsigned char *)scp->cmnd;
2183 int select_report = (int)cmd[2];
2184 struct scsi_lun *one_lun;
2185 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002186 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
2188 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002189 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2191 0);
2192 return check_condition_result;
2193 }
2194 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2195 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2196 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002197 if (1 == select_report)
2198 lun_cnt = 0;
2199 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2200 --lun_cnt;
2201 wlun = (select_report > 0) ? 1 : 0;
2202 num = lun_cnt + wlun;
2203 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2204 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2205 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2206 sizeof(struct scsi_lun)), num);
2207 if (n < num) {
2208 wlun = 0;
2209 lun_cnt = n;
2210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002212 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2213 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2214 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2215 i++, lun++) {
2216 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 if (upper)
2218 one_lun[i].scsi_lun[0] =
2219 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002220 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002222 if (wlun) {
2223 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2224 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2225 i++;
2226 }
2227 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 return fill_from_dev_buffer(scp, arr,
2229 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2230}
2231
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002232static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2233 unsigned int num, struct sdebug_dev_info *devip)
2234{
2235 int i, j, ret = -1;
2236 unsigned char *kaddr, *buf;
2237 unsigned int offset;
2238 struct scatterlist *sg;
2239 struct scsi_data_buffer *sdb = scsi_in(scp);
2240
2241 /* better not to use temporary buffer. */
2242 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2243 if (!buf)
2244 return ret;
2245
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002246 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002247
2248 offset = 0;
2249 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2250 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2251 if (!kaddr)
2252 goto out;
2253
2254 for (j = 0; j < sg->length; j++)
2255 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2256
2257 offset += sg->length;
2258 kunmap_atomic(kaddr, KM_USER0);
2259 }
2260 ret = 0;
2261out:
2262 kfree(buf);
2263
2264 return ret;
2265}
2266
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267/* When timer goes off this function is called. */
2268static void timer_intr_handler(unsigned long indx)
2269{
2270 struct sdebug_queued_cmd * sqcp;
2271 unsigned long iflags;
2272
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002273 if (indx >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2275 "large\n");
2276 return;
2277 }
2278 spin_lock_irqsave(&queued_arr_lock, iflags);
2279 sqcp = &queued_arr[(int)indx];
2280 if (! sqcp->in_use) {
2281 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2282 "interrupt\n");
2283 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2284 return;
2285 }
2286 sqcp->in_use = 0;
2287 if (sqcp->done_funct) {
2288 sqcp->a_cmnd->result = sqcp->scsi_result;
2289 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2290 }
2291 sqcp->done_funct = NULL;
2292 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2293}
2294
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002296static struct sdebug_dev_info *
2297sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002298{
2299 struct sdebug_dev_info *devip;
2300
2301 devip = kzalloc(sizeof(*devip), flags);
2302 if (devip) {
2303 devip->sdbg_host = sdbg_host;
2304 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2305 }
2306 return devip;
2307}
2308
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2310{
2311 struct sdebug_host_info * sdbg_host;
2312 struct sdebug_dev_info * open_devip = NULL;
2313 struct sdebug_dev_info * devip =
2314 (struct sdebug_dev_info *)sdev->hostdata;
2315
2316 if (devip)
2317 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002318 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2319 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 printk(KERN_ERR "Host info NULL\n");
2321 return NULL;
2322 }
2323 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2324 if ((devip->used) && (devip->channel == sdev->channel) &&
2325 (devip->target == sdev->id) &&
2326 (devip->lun == sdev->lun))
2327 return devip;
2328 else {
2329 if ((!devip->used) && (!open_devip))
2330 open_devip = devip;
2331 }
2332 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002333 if (!open_devip) { /* try and make a new one */
2334 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2335 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002337 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 return NULL;
2339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002341
2342 open_devip->channel = sdev->channel;
2343 open_devip->target = sdev->id;
2344 open_devip->lun = sdev->lun;
2345 open_devip->sdbg_host = sdbg_host;
2346 open_devip->reset = 1;
2347 open_devip->used = 1;
2348 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2349 if (scsi_debug_dsense)
2350 open_devip->sense_buff[0] = 0x72;
2351 else {
2352 open_devip->sense_buff[0] = 0x70;
2353 open_devip->sense_buff[7] = 0xa;
2354 }
2355 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2356 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2357
2358 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359}
2360
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002361static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002363 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2364 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2365 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002366 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002367 return 0;
2368}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002370static int scsi_debug_slave_configure(struct scsi_device *sdp)
2371{
2372 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002373
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002375 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2376 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2377 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2378 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2379 devip = devInfoReg(sdp);
2380 if (NULL == devip)
2381 return 1; /* no resources, will be marked offline */
2382 sdp->hostdata = devip;
2383 if (sdp->host->cmd_per_lun)
2384 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2385 sdp->host->cmd_per_lun);
2386 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002387 if (scsi_debug_no_uld)
2388 sdp->no_uld_attach = 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002389 return 0;
2390}
2391
2392static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2393{
2394 struct sdebug_dev_info *devip =
2395 (struct sdebug_dev_info *)sdp->hostdata;
2396
2397 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2398 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2399 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2400 if (devip) {
2401 /* make this slot avaliable for re-use */
2402 devip->used = 0;
2403 sdp->hostdata = NULL;
2404 }
2405}
2406
2407/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2408static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2409{
2410 unsigned long iflags;
2411 int k;
2412 struct sdebug_queued_cmd *sqcp;
2413
2414 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002415 for (k = 0; k < scsi_debug_max_queue; ++k) {
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002416 sqcp = &queued_arr[k];
2417 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2418 del_timer_sync(&sqcp->cmnd_timer);
2419 sqcp->in_use = 0;
2420 sqcp->a_cmnd = NULL;
2421 break;
2422 }
2423 }
2424 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002425 return (k < scsi_debug_max_queue) ? 1 : 0;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002426}
2427
2428/* Deletes (stops) timers of all queued commands */
2429static void stop_all_queued(void)
2430{
2431 unsigned long iflags;
2432 int k;
2433 struct sdebug_queued_cmd *sqcp;
2434
2435 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002436 for (k = 0; k < scsi_debug_max_queue; ++k) {
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002437 sqcp = &queued_arr[k];
2438 if (sqcp->in_use && sqcp->a_cmnd) {
2439 del_timer_sync(&sqcp->cmnd_timer);
2440 sqcp->in_use = 0;
2441 sqcp->a_cmnd = NULL;
2442 }
2443 }
2444 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445}
2446
2447static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2448{
2449 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2450 printk(KERN_INFO "scsi_debug: abort\n");
2451 ++num_aborts;
2452 stop_queued_cmnd(SCpnt);
2453 return SUCCESS;
2454}
2455
2456static int scsi_debug_biosparam(struct scsi_device *sdev,
2457 struct block_device * bdev, sector_t capacity, int *info)
2458{
2459 int res;
2460 unsigned char *buf;
2461
2462 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2463 printk(KERN_INFO "scsi_debug: biosparam\n");
2464 buf = scsi_bios_ptable(bdev);
2465 if (buf) {
2466 res = scsi_partsize(buf, capacity,
2467 &info[2], &info[0], &info[1]);
2468 kfree(buf);
2469 if (! res)
2470 return res;
2471 }
2472 info[0] = sdebug_heads;
2473 info[1] = sdebug_sectors_per;
2474 info[2] = sdebug_cylinders_per;
2475 return 0;
2476}
2477
2478static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2479{
2480 struct sdebug_dev_info * devip;
2481
2482 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2483 printk(KERN_INFO "scsi_debug: device_reset\n");
2484 ++num_dev_resets;
2485 if (SCpnt) {
2486 devip = devInfoReg(SCpnt->device);
2487 if (devip)
2488 devip->reset = 1;
2489 }
2490 return SUCCESS;
2491}
2492
2493static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2494{
2495 struct sdebug_host_info *sdbg_host;
2496 struct sdebug_dev_info * dev_info;
2497 struct scsi_device * sdp;
2498 struct Scsi_Host * hp;
2499
2500 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2501 printk(KERN_INFO "scsi_debug: bus_reset\n");
2502 ++num_bus_resets;
2503 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002504 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 if (sdbg_host) {
2506 list_for_each_entry(dev_info,
2507 &sdbg_host->dev_info_list,
2508 dev_list)
2509 dev_info->reset = 1;
2510 }
2511 }
2512 return SUCCESS;
2513}
2514
2515static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2516{
2517 struct sdebug_host_info * sdbg_host;
2518 struct sdebug_dev_info * dev_info;
2519
2520 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2521 printk(KERN_INFO "scsi_debug: host_reset\n");
2522 ++num_host_resets;
2523 spin_lock(&sdebug_host_list_lock);
2524 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2525 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2526 dev_list)
2527 dev_info->reset = 1;
2528 }
2529 spin_unlock(&sdebug_host_list_lock);
2530 stop_all_queued();
2531 return SUCCESS;
2532}
2533
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534/* Initializes timers in queued array */
2535static void __init init_all_queued(void)
2536{
2537 unsigned long iflags;
2538 int k;
2539 struct sdebug_queued_cmd * sqcp;
2540
2541 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002542 for (k = 0; k < scsi_debug_max_queue; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 sqcp = &queued_arr[k];
2544 init_timer(&sqcp->cmnd_timer);
2545 sqcp->in_use = 0;
2546 sqcp->a_cmnd = NULL;
2547 }
2548 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2549}
2550
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002551static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002552 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553{
2554 struct partition * pp;
2555 int starts[SDEBUG_MAX_PARTS + 2];
2556 int sectors_per_part, num_sectors, k;
2557 int heads_by_sects, start_sec, end_sec;
2558
2559 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002560 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 return;
2562 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2563 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2564 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2565 "partitions to %d\n", SDEBUG_MAX_PARTS);
2566 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002567 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 sectors_per_part = (num_sectors - sdebug_sectors_per)
2569 / scsi_debug_num_parts;
2570 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2571 starts[0] = sdebug_sectors_per;
2572 for (k = 1; k < scsi_debug_num_parts; ++k)
2573 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2574 * heads_by_sects;
2575 starts[scsi_debug_num_parts] = num_sectors;
2576 starts[scsi_debug_num_parts + 1] = 0;
2577
2578 ramp[510] = 0x55; /* magic partition markings */
2579 ramp[511] = 0xAA;
2580 pp = (struct partition *)(ramp + 0x1be);
2581 for (k = 0; starts[k + 1]; ++k, ++pp) {
2582 start_sec = starts[k];
2583 end_sec = starts[k + 1] - 1;
2584 pp->boot_ind = 0;
2585
2586 pp->cyl = start_sec / heads_by_sects;
2587 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2588 / sdebug_sectors_per;
2589 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2590
2591 pp->end_cyl = end_sec / heads_by_sects;
2592 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2593 / sdebug_sectors_per;
2594 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2595
2596 pp->start_sect = start_sec;
2597 pp->nr_sects = end_sec - start_sec + 1;
2598 pp->sys_ind = 0x83; /* plain Linux partition */
2599 }
2600}
2601
2602static int schedule_resp(struct scsi_cmnd * cmnd,
2603 struct sdebug_dev_info * devip,
2604 done_funct_t done, int scsi_result, int delta_jiff)
2605{
2606 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2607 if (scsi_result) {
2608 struct scsi_device * sdp = cmnd->device;
2609
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002610 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2611 "non-zero result=0x%x\n", sdp->host->host_no,
2612 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 }
2614 }
2615 if (cmnd && devip) {
2616 /* simulate autosense by this driver */
2617 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2618 memcpy(cmnd->sense_buffer, devip->sense_buff,
2619 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2620 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2621 }
2622 if (delta_jiff <= 0) {
2623 if (cmnd)
2624 cmnd->result = scsi_result;
2625 if (done)
2626 done(cmnd);
2627 return 0;
2628 } else {
2629 unsigned long iflags;
2630 int k;
2631 struct sdebug_queued_cmd * sqcp = NULL;
2632
2633 spin_lock_irqsave(&queued_arr_lock, iflags);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002634 for (k = 0; k < scsi_debug_max_queue; ++k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 sqcp = &queued_arr[k];
2636 if (! sqcp->in_use)
2637 break;
2638 }
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002639 if (k >= scsi_debug_max_queue) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2641 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2642 return 1; /* report busy to mid level */
2643 }
2644 sqcp->in_use = 1;
2645 sqcp->a_cmnd = cmnd;
2646 sqcp->scsi_result = scsi_result;
2647 sqcp->done_funct = done;
2648 sqcp->cmnd_timer.function = timer_intr_handler;
2649 sqcp->cmnd_timer.data = k;
2650 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2651 add_timer(&sqcp->cmnd_timer);
2652 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2653 if (cmnd)
2654 cmnd->result = 0;
2655 return 0;
2656 }
2657}
Douglas Gilbert23183912006-09-16 20:30:47 -04002658/* Note: The following macros create attribute files in the
2659 /sys/module/scsi_debug/parameters directory. Unfortunately this
2660 driver is unaware of a change and cannot trigger auxiliary actions
2661 as it can when the corresponding attribute in the
2662 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2663 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002664module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2665module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2666module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2667module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2668module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002669module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002670module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002671module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002672module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002673module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002674module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2675module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2676module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2677module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2678module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2679module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002680module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2681 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002682module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002683module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2684module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2685module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2686module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002687module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2688module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002689module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
2690module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2691module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
2692module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693
2694MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2695MODULE_DESCRIPTION("SCSI debug adapter driver");
2696MODULE_LICENSE("GPL");
2697MODULE_VERSION(SCSI_DEBUG_VERSION);
2698
2699MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2700MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002701MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2702MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002703MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002704MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002705MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002706MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002707MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002708MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002710MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002711MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2713MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002714MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002715MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002716MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
2717MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
2718MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002719MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2720MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2721MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2722MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Martin K. Petersen44d92692009-10-15 14:45:27 -04002723MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)");
2724MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)");
2725MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)");
2726MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
2728static char sdebug_info[256];
2729
2730static const char * scsi_debug_info(struct Scsi_Host * shp)
2731{
2732 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2733 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2734 scsi_debug_version_date, scsi_debug_dev_size_mb,
2735 scsi_debug_opts);
2736 return sdebug_info;
2737}
2738
2739/* scsi_debug_proc_info
2740 * Used if the driver currently has no own support for /proc/scsi
2741 */
2742static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2743 int length, int inout)
2744{
2745 int len, pos, begin;
2746 int orig_length;
2747
2748 orig_length = length;
2749
2750 if (inout == 1) {
2751 char arr[16];
2752 int minLen = length > 15 ? 15 : length;
2753
2754 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2755 return -EACCES;
2756 memcpy(arr, buffer, minLen);
2757 arr[minLen] = '\0';
2758 if (1 != sscanf(arr, "%d", &pos))
2759 return -EINVAL;
2760 scsi_debug_opts = pos;
2761 if (scsi_debug_every_nth != 0)
2762 scsi_debug_cmnd_count = 0;
2763 return length;
2764 }
2765 begin = 0;
2766 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2767 "%s [%s]\n"
2768 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2769 "every_nth=%d(curr:%d)\n"
2770 "delay=%d, max_luns=%d, scsi_level=%d\n"
2771 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2772 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002773 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2775 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2776 scsi_debug_cmnd_count, scsi_debug_delay,
2777 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002778 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2779 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002780 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 if (pos < offset) {
2782 len = 0;
2783 begin = pos;
2784 }
2785 *start = buffer + (offset - begin); /* Start of wanted data */
2786 len -= (offset - begin);
2787 if (len > length)
2788 len = length;
2789 return len;
2790}
2791
2792static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2793{
2794 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2795}
2796
2797static ssize_t sdebug_delay_store(struct device_driver * ddp,
2798 const char * buf, size_t count)
2799{
2800 int delay;
2801 char work[20];
2802
2803 if (1 == sscanf(buf, "%10s", work)) {
2804 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2805 scsi_debug_delay = delay;
2806 return count;
2807 }
2808 }
2809 return -EINVAL;
2810}
2811DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2812 sdebug_delay_store);
2813
2814static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2815{
2816 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2817}
2818
2819static ssize_t sdebug_opts_store(struct device_driver * ddp,
2820 const char * buf, size_t count)
2821{
2822 int opts;
2823 char work[20];
2824
2825 if (1 == sscanf(buf, "%10s", work)) {
2826 if (0 == strnicmp(work,"0x", 2)) {
2827 if (1 == sscanf(&work[2], "%x", &opts))
2828 goto opts_done;
2829 } else {
2830 if (1 == sscanf(work, "%d", &opts))
2831 goto opts_done;
2832 }
2833 }
2834 return -EINVAL;
2835opts_done:
2836 scsi_debug_opts = opts;
2837 scsi_debug_cmnd_count = 0;
2838 return count;
2839}
2840DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2841 sdebug_opts_store);
2842
2843static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2844{
2845 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2846}
2847static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2848 const char * buf, size_t count)
2849{
2850 int n;
2851
2852 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2853 scsi_debug_ptype = n;
2854 return count;
2855 }
2856 return -EINVAL;
2857}
2858DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2859
2860static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2861{
2862 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2863}
2864static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2865 const char * buf, size_t count)
2866{
2867 int n;
2868
2869 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2870 scsi_debug_dsense = n;
2871 return count;
2872 }
2873 return -EINVAL;
2874}
2875DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2876 sdebug_dsense_store);
2877
Douglas Gilbert23183912006-09-16 20:30:47 -04002878static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2879{
2880 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2881}
2882static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2883 const char * buf, size_t count)
2884{
2885 int n;
2886
2887 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2888 scsi_debug_fake_rw = n;
2889 return count;
2890 }
2891 return -EINVAL;
2892}
2893DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2894 sdebug_fake_rw_store);
2895
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002896static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2897{
2898 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2899}
2900static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2901 const char * buf, size_t count)
2902{
2903 int n;
2904
2905 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2906 scsi_debug_no_lun_0 = n;
2907 return count;
2908 }
2909 return -EINVAL;
2910}
2911DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2912 sdebug_no_lun_0_store);
2913
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2915{
2916 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2917}
2918static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2919 const char * buf, size_t count)
2920{
2921 int n;
2922
2923 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2924 scsi_debug_num_tgts = n;
2925 sdebug_max_tgts_luns();
2926 return count;
2927 }
2928 return -EINVAL;
2929}
2930DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2931 sdebug_num_tgts_store);
2932
2933static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2934{
2935 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2936}
2937DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2938
2939static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2940{
2941 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2942}
2943DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2944
2945static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2946{
2947 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2948}
2949static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2950 const char * buf, size_t count)
2951{
2952 int nth;
2953
2954 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2955 scsi_debug_every_nth = nth;
2956 scsi_debug_cmnd_count = 0;
2957 return count;
2958 }
2959 return -EINVAL;
2960}
2961DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2962 sdebug_every_nth_store);
2963
2964static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2965{
2966 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2967}
2968static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2969 const char * buf, size_t count)
2970{
2971 int n;
2972
2973 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2974 scsi_debug_max_luns = n;
2975 sdebug_max_tgts_luns();
2976 return count;
2977 }
2978 return -EINVAL;
2979}
2980DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2981 sdebug_max_luns_store);
2982
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04002983static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf)
2984{
2985 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);
2986}
2987static ssize_t sdebug_max_queue_store(struct device_driver * ddp,
2988 const char * buf, size_t count)
2989{
2990 int n;
2991
2992 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
2993 (n <= SCSI_DEBUG_CANQUEUE)) {
2994 scsi_debug_max_queue = n;
2995 return count;
2996 }
2997 return -EINVAL;
2998}
2999DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show,
3000 sdebug_max_queue_store);
3001
3002static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf)
3003{
3004 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);
3005}
3006DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL);
3007
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
3009{
3010 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
3011}
3012DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
3013
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003014static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
3015{
3016 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
3017}
3018static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
3019 const char * buf, size_t count)
3020{
3021 int n;
3022
3023 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3024 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003025
3026 sdebug_capacity = get_sdebug_capacity();
3027
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003028 return count;
3029 }
3030 return -EINVAL;
3031}
3032DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
3033 sdebug_virtual_gb_store);
3034
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
3036{
3037 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
3038}
3039
3040static ssize_t sdebug_add_host_store(struct device_driver * ddp,
3041 const char * buf, size_t count)
3042{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003043 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003045 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 if (delta_hosts > 0) {
3048 do {
3049 sdebug_add_adapter();
3050 } while (--delta_hosts);
3051 } else if (delta_hosts < 0) {
3052 do {
3053 sdebug_remove_adapter();
3054 } while (++delta_hosts);
3055 }
3056 return count;
3057}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003058DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 sdebug_add_host_store);
3060
Douglas Gilbert23183912006-09-16 20:30:47 -04003061static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
3062 char * buf)
3063{
3064 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3065}
3066static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
3067 const char * buf, size_t count)
3068{
3069 int n;
3070
3071 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3072 scsi_debug_vpd_use_hostno = n;
3073 return count;
3074 }
3075 return -EINVAL;
3076}
3077DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
3078 sdebug_vpd_use_hostno_store);
3079
Martin K. Petersen597136a2008-06-05 00:12:59 -04003080static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3081{
3082 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3083}
3084DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3085
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003086static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3087{
3088 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3089}
3090DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3091
3092static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3093{
3094 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3095}
3096DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3097
3098static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3099{
3100 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3101}
3102DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3103
3104static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3105{
3106 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3107}
3108DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3109
Martin K. Petersen44d92692009-10-15 14:45:27 -04003110static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
3111{
3112 ssize_t count;
3113
3114 if (scsi_debug_unmap_granularity == 0)
3115 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3116 sdebug_store_sectors);
3117
3118 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3119
3120 buf[count++] = '\n';
3121 buf[count++] = 0;
3122
3123 return count;
3124}
3125DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
3126
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003127
Douglas Gilbert23183912006-09-16 20:30:47 -04003128/* Note: The following function creates attribute files in the
3129 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3130 files (over those found in the /sys/module/scsi_debug/parameters
3131 directory) is that auxiliary actions can be triggered when an attribute
3132 is changed. For example see: sdebug_add_host_store() above.
3133 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003134static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003136 int ret;
3137
3138 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3139 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
3140 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3141 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3142 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04003143 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003144 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003145 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
Douglas Gilbert23183912006-09-16 20:30:47 -04003146 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003147 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003148 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003149 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003150 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3151 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
3152 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04003153 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
3154 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003155 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003156 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3157 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3158 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3159 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003160 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003161 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162}
3163
3164static void do_remove_driverfs_files(void)
3165{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003166 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003167 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3168 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3169 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3170 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003171 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04003172 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3173 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
3175 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
3176 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003178 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003179 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld);
Douglas Gilbert23183912006-09-16 20:30:47 -04003180 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003181 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003183 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
3185 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3186 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3187 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
3188 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3189}
3190
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003191static void pseudo_0_release(struct device *dev)
3192{
3193 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3194 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
3195}
3196
3197static struct device pseudo_primary = {
Kay Sievers71610f52008-12-03 22:41:36 +01003198 .init_name = "pseudo_0",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003199 .release = pseudo_0_release,
3200};
3201
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202static int __init scsi_debug_init(void)
3203{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003204 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 int host_to_add;
3206 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003207 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208
Martin K. Petersen597136a2008-06-05 00:12:59 -04003209 switch (scsi_debug_sector_size) {
3210 case 512:
3211 case 1024:
3212 case 2048:
3213 case 4096:
3214 break;
3215 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003216 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04003217 scsi_debug_sector_size);
3218 return -EINVAL;
3219 }
3220
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003221 switch (scsi_debug_dif) {
3222
3223 case SD_DIF_TYPE0_PROTECTION:
3224 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003225 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003226 case SD_DIF_TYPE3_PROTECTION:
3227 break;
3228
3229 default:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003230 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003231 return -EINVAL;
3232 }
3233
3234 if (scsi_debug_guard > 1) {
3235 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3236 return -EINVAL;
3237 }
3238
3239 if (scsi_debug_ato > 1) {
3240 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3241 return -EINVAL;
3242 }
3243
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003244 if (scsi_debug_physblk_exp > 15) {
3245 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3246 scsi_debug_physblk_exp);
3247 return -EINVAL;
3248 }
3249
3250 if (scsi_debug_lowest_aligned > 0x3fff) {
3251 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3252 scsi_debug_lowest_aligned);
3253 return -EINVAL;
3254 }
3255
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 if (scsi_debug_dev_size_mb < 1)
3257 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003258 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003259 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003260 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261
3262 /* play around with geometry, don't waste too much on track 0 */
3263 sdebug_heads = 8;
3264 sdebug_sectors_per = 32;
3265 if (scsi_debug_dev_size_mb >= 16)
3266 sdebug_heads = 32;
3267 else if (scsi_debug_dev_size_mb >= 256)
3268 sdebug_heads = 64;
3269 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3270 (sdebug_sectors_per * sdebug_heads);
3271 if (sdebug_cylinders_per >= 1024) {
3272 /* other LLDs do this; implies >= 1GB ram disk ... */
3273 sdebug_heads = 255;
3274 sdebug_sectors_per = 63;
3275 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3276 (sdebug_sectors_per * sdebug_heads);
3277 }
3278
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 fake_storep = vmalloc(sz);
3280 if (NULL == fake_storep) {
3281 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
3282 return -ENOMEM;
3283 }
3284 memset(fake_storep, 0, sz);
3285 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003286 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003288 if (scsi_debug_dif) {
3289 int dif_size;
3290
3291 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3292 dif_storep = vmalloc(dif_size);
3293
3294 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3295 dif_size, dif_storep);
3296
3297 if (dif_storep == NULL) {
3298 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3299 ret = -ENOMEM;
3300 goto free_vm;
3301 }
3302
3303 memset(dif_storep, 0xff, dif_size);
3304 }
3305
Martin K. Petersen44d92692009-10-15 14:45:27 -04003306 if (scsi_debug_unmap_granularity) {
3307 unsigned int map_bytes;
3308
3309 if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
3310 printk(KERN_ERR
3311 "%s: ERR: unmap_granularity < unmap_alignment\n",
3312 __func__);
3313 return -EINVAL;
3314 }
3315
3316 map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
3317 map_bytes = map_size >> 3;
3318 map_storep = vmalloc(map_bytes);
3319
3320 printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
3321 map_size);
3322
3323 if (map_storep == NULL) {
3324 printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
3325 ret = -ENOMEM;
3326 goto free_vm;
3327 }
3328
3329 memset(map_storep, 0x0, map_bytes);
3330
3331 /* Map first 1KB for partition table */
3332 if (scsi_debug_num_parts)
3333 map_region(0, 2);
3334 }
3335
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003336 ret = device_register(&pseudo_primary);
3337 if (ret < 0) {
3338 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
3339 ret);
3340 goto free_vm;
3341 }
3342 ret = bus_register(&pseudo_lld_bus);
3343 if (ret < 0) {
3344 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
3345 ret);
3346 goto dev_unreg;
3347 }
3348 ret = driver_register(&sdebug_driverfs_driver);
3349 if (ret < 0) {
3350 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
3351 ret);
3352 goto bus_unreg;
3353 }
3354 ret = do_create_driverfs_files();
3355 if (ret < 0) {
3356 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
3357 ret);
3358 goto del_files;
3359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003361 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 host_to_add = scsi_debug_add_host;
3364 scsi_debug_add_host = 0;
3365
3366 for (k = 0; k < host_to_add; k++) {
3367 if (sdebug_add_adapter()) {
3368 printk(KERN_ERR "scsi_debug_init: "
3369 "sdebug_add_adapter failed k=%d\n", k);
3370 break;
3371 }
3372 }
3373
3374 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3375 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
3376 scsi_debug_add_host);
3377 }
3378 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003379
3380del_files:
3381 do_remove_driverfs_files();
3382 driver_unregister(&sdebug_driverfs_driver);
3383bus_unreg:
3384 bus_unregister(&pseudo_lld_bus);
3385dev_unreg:
3386 device_unregister(&pseudo_primary);
3387free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003388 if (map_storep)
3389 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003390 if (dif_storep)
3391 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003392 vfree(fake_storep);
3393
3394 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395}
3396
3397static void __exit scsi_debug_exit(void)
3398{
3399 int k = scsi_debug_add_host;
3400
3401 stop_all_queued();
3402 for (; k; k--)
3403 sdebug_remove_adapter();
3404 do_remove_driverfs_files();
3405 driver_unregister(&sdebug_driverfs_driver);
3406 bus_unregister(&pseudo_lld_bus);
3407 device_unregister(&pseudo_primary);
3408
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003409 if (dif_storep)
3410 vfree(dif_storep);
3411
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 vfree(fake_storep);
3413}
3414
3415device_initcall(scsi_debug_init);
3416module_exit(scsi_debug_exit);
3417
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418static void sdebug_release_adapter(struct device * dev)
3419{
3420 struct sdebug_host_info *sdbg_host;
3421
3422 sdbg_host = to_sdebug_host(dev);
3423 kfree(sdbg_host);
3424}
3425
3426static int sdebug_add_adapter(void)
3427{
3428 int k, devs_per_host;
3429 int error = 0;
3430 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003431 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003433 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 if (NULL == sdbg_host) {
3435 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003436 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 return -ENOMEM;
3438 }
3439
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3441
3442 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3443 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003444 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3445 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003447 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 error = -ENOMEM;
3449 goto clean;
3450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 }
3452
3453 spin_lock(&sdebug_host_list_lock);
3454 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3455 spin_unlock(&sdebug_host_list_lock);
3456
3457 sdbg_host->dev.bus = &pseudo_lld_bus;
3458 sdbg_host->dev.parent = &pseudo_primary;
3459 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003460 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461
3462 error = device_register(&sdbg_host->dev);
3463
3464 if (error)
3465 goto clean;
3466
3467 ++scsi_debug_add_host;
3468 return error;
3469
3470clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003471 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3472 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 list_del(&sdbg_devinfo->dev_list);
3474 kfree(sdbg_devinfo);
3475 }
3476
3477 kfree(sdbg_host);
3478 return error;
3479}
3480
3481static void sdebug_remove_adapter(void)
3482{
3483 struct sdebug_host_info * sdbg_host = NULL;
3484
3485 spin_lock(&sdebug_host_list_lock);
3486 if (!list_empty(&sdebug_host_list)) {
3487 sdbg_host = list_entry(sdebug_host_list.prev,
3488 struct sdebug_host_info, host_list);
3489 list_del(&sdbg_host->host_list);
3490 }
3491 spin_unlock(&sdebug_host_list_lock);
3492
3493 if (!sdbg_host)
3494 return;
3495
3496 device_unregister(&sdbg_host->dev);
3497 --scsi_debug_add_host;
3498}
3499
FUJITA Tomonori639db472008-03-20 11:09:19 +09003500static
3501int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
3502{
3503 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3504 int len, k;
3505 unsigned int num;
3506 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003507 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003508 int errsts = 0;
3509 int target = SCpnt->device->id;
3510 struct sdebug_dev_info *devip = NULL;
3511 int inj_recovered = 0;
3512 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003513 int inj_dif = 0;
3514 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003515 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003516 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003517
3518 scsi_set_resid(SCpnt, 0);
3519 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3520 printk(KERN_INFO "scsi_debug: cmd ");
3521 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3522 printk("%02x ", (int)cmd[k]);
3523 printk("\n");
3524 }
3525
3526 if (target == SCpnt->device->host->hostt->this_id) {
3527 printk(KERN_INFO "scsi_debug: initiator's id used as "
3528 "target!\n");
3529 return schedule_resp(SCpnt, NULL, done,
3530 DID_NO_CONNECT << 16, 0);
3531 }
3532
3533 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3534 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3535 return schedule_resp(SCpnt, NULL, done,
3536 DID_NO_CONNECT << 16, 0);
3537 devip = devInfoReg(SCpnt->device);
3538 if (NULL == devip)
3539 return schedule_resp(SCpnt, NULL, done,
3540 DID_NO_CONNECT << 16, 0);
3541
3542 if ((scsi_debug_every_nth != 0) &&
3543 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3544 scsi_debug_cmnd_count = 0;
3545 if (scsi_debug_every_nth < -1)
3546 scsi_debug_every_nth = -1;
3547 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3548 return 0; /* ignore command causing timeout */
3549 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3550 inj_recovered = 1; /* to reads and writes below */
3551 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3552 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003553 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3554 inj_dif = 1; /* to reads and writes below */
3555 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3556 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003557 }
3558
3559 if (devip->wlun) {
3560 switch (*cmd) {
3561 case INQUIRY:
3562 case REQUEST_SENSE:
3563 case TEST_UNIT_READY:
3564 case REPORT_LUNS:
3565 break; /* only allowable wlun commands */
3566 default:
3567 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3568 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3569 "not supported for wlun\n", *cmd);
3570 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3571 INVALID_OPCODE, 0);
3572 errsts = check_condition_result;
3573 return schedule_resp(SCpnt, devip, done, errsts,
3574 0);
3575 }
3576 }
3577
3578 switch (*cmd) {
3579 case INQUIRY: /* mandatory, ignore unit attention */
3580 delay_override = 1;
3581 errsts = resp_inquiry(SCpnt, target, devip);
3582 break;
3583 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3584 delay_override = 1;
3585 errsts = resp_requests(SCpnt, devip);
3586 break;
3587 case REZERO_UNIT: /* actually this is REWIND for SSC */
3588 case START_STOP:
3589 errsts = resp_start_stop(SCpnt, devip);
3590 break;
3591 case ALLOW_MEDIUM_REMOVAL:
3592 errsts = check_readiness(SCpnt, 1, devip);
3593 if (errsts)
3594 break;
3595 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3596 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3597 cmd[4] ? "inhibited" : "enabled");
3598 break;
3599 case SEND_DIAGNOSTIC: /* mandatory */
3600 errsts = check_readiness(SCpnt, 1, devip);
3601 break;
3602 case TEST_UNIT_READY: /* mandatory */
3603 delay_override = 1;
3604 errsts = check_readiness(SCpnt, 0, devip);
3605 break;
3606 case RESERVE:
3607 errsts = check_readiness(SCpnt, 1, devip);
3608 break;
3609 case RESERVE_10:
3610 errsts = check_readiness(SCpnt, 1, devip);
3611 break;
3612 case RELEASE:
3613 errsts = check_readiness(SCpnt, 1, devip);
3614 break;
3615 case RELEASE_10:
3616 errsts = check_readiness(SCpnt, 1, devip);
3617 break;
3618 case READ_CAPACITY:
3619 errsts = resp_readcap(SCpnt, devip);
3620 break;
3621 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003622 if (cmd[1] == SAI_READ_CAPACITY_16)
3623 errsts = resp_readcap16(SCpnt, devip);
3624 else if (cmd[1] == SAI_GET_LBA_STATUS) {
3625
3626 if (scsi_debug_unmap_max_desc == 0) {
3627 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3628 INVALID_COMMAND_OPCODE, 0);
3629 errsts = check_condition_result;
3630 } else
3631 errsts = resp_get_lba_status(SCpnt, devip);
3632 } else {
FUJITA Tomonori639db472008-03-20 11:09:19 +09003633 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3634 INVALID_OPCODE, 0);
3635 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003636 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09003637 break;
3638 case MAINTENANCE_IN:
3639 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3640 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3641 INVALID_OPCODE, 0);
3642 errsts = check_condition_result;
3643 break;
3644 }
3645 errsts = resp_report_tgtpgs(SCpnt, devip);
3646 break;
3647 case READ_16:
3648 case READ_12:
3649 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003650 /* READ{10,12,16} and DIF Type 2 are natural enemies */
3651 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3652 cmd[1] & 0xe0) {
3653 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3654 INVALID_COMMAND_OPCODE, 0);
3655 errsts = check_condition_result;
3656 break;
3657 }
3658
3659 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3660 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3661 (cmd[1] & 0xe0) == 0)
3662 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3663
3664 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003665 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003666read:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003667 errsts = check_readiness(SCpnt, 0, devip);
3668 if (errsts)
3669 break;
3670 if (scsi_debug_fake_rw)
3671 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003672 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3673 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003674 if (inj_recovered && (0 == errsts)) {
3675 mk_sense_buffer(devip, RECOVERED_ERROR,
3676 THRESHOLD_EXCEEDED, 0);
3677 errsts = check_condition_result;
3678 } else if (inj_transport && (0 == errsts)) {
3679 mk_sense_buffer(devip, ABORTED_COMMAND,
3680 TRANSPORT_PROBLEM, ACK_NAK_TO);
3681 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003682 } else if (inj_dif && (0 == errsts)) {
3683 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3684 errsts = illegal_condition_result;
3685 } else if (inj_dix && (0 == errsts)) {
3686 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3687 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003688 }
3689 break;
3690 case REPORT_LUNS: /* mandatory, ignore unit attention */
3691 delay_override = 1;
3692 errsts = resp_report_luns(SCpnt, devip);
3693 break;
3694 case VERIFY: /* 10 byte SBC-2 command */
3695 errsts = check_readiness(SCpnt, 0, devip);
3696 break;
3697 case WRITE_16:
3698 case WRITE_12:
3699 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003700 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3701 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3702 cmd[1] & 0xe0) {
3703 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3704 INVALID_COMMAND_OPCODE, 0);
3705 errsts = check_condition_result;
3706 break;
3707 }
3708
3709 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3710 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3711 (cmd[1] & 0xe0) == 0)
3712 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3713
3714 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003715 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003716write:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003717 errsts = check_readiness(SCpnt, 0, devip);
3718 if (errsts)
3719 break;
3720 if (scsi_debug_fake_rw)
3721 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003722 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3723 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003724 if (inj_recovered && (0 == errsts)) {
3725 mk_sense_buffer(devip, RECOVERED_ERROR,
3726 THRESHOLD_EXCEEDED, 0);
3727 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003728 } else if (inj_dif && (0 == errsts)) {
3729 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3730 errsts = illegal_condition_result;
3731 } else if (inj_dix && (0 == errsts)) {
3732 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3733 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003734 }
3735 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003736 case WRITE_SAME_16:
3737 if (cmd[1] & 0x8)
3738 unmap = 1;
3739 /* fall through */
3740 case WRITE_SAME:
3741 errsts = check_readiness(SCpnt, 0, devip);
3742 if (errsts)
3743 break;
3744 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3745 errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
3746 break;
3747 case UNMAP:
3748 errsts = check_readiness(SCpnt, 0, devip);
3749 if (errsts)
3750 break;
3751
3752 if (scsi_debug_unmap_max_desc == 0) {
3753 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3754 INVALID_COMMAND_OPCODE, 0);
3755 errsts = check_condition_result;
3756 } else
3757 errsts = resp_unmap(SCpnt, devip);
3758 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003759 case MODE_SENSE:
3760 case MODE_SENSE_10:
3761 errsts = resp_mode_sense(SCpnt, target, devip);
3762 break;
3763 case MODE_SELECT:
3764 errsts = resp_mode_select(SCpnt, 1, devip);
3765 break;
3766 case MODE_SELECT_10:
3767 errsts = resp_mode_select(SCpnt, 0, devip);
3768 break;
3769 case LOG_SENSE:
3770 errsts = resp_log_sense(SCpnt, devip);
3771 break;
3772 case SYNCHRONIZE_CACHE:
3773 delay_override = 1;
3774 errsts = check_readiness(SCpnt, 0, devip);
3775 break;
3776 case WRITE_BUFFER:
3777 errsts = check_readiness(SCpnt, 1, devip);
3778 break;
3779 case XDWRITEREAD_10:
3780 if (!scsi_bidi_cmnd(SCpnt)) {
3781 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3782 INVALID_FIELD_IN_CDB, 0);
3783 errsts = check_condition_result;
3784 break;
3785 }
3786
3787 errsts = check_readiness(SCpnt, 0, devip);
3788 if (errsts)
3789 break;
3790 if (scsi_debug_fake_rw)
3791 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003792 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3793 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003794 if (errsts)
3795 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003796 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003797 if (errsts)
3798 break;
3799 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3800 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003801 case VARIABLE_LENGTH_CMD:
3802 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3803
3804 if ((cmd[10] & 0xe0) == 0)
3805 printk(KERN_ERR
3806 "Unprotected RD/WR to DIF device\n");
3807
3808 if (cmd[9] == READ_32) {
3809 BUG_ON(SCpnt->cmd_len < 32);
3810 goto read;
3811 }
3812
3813 if (cmd[9] == WRITE_32) {
3814 BUG_ON(SCpnt->cmd_len < 32);
3815 goto write;
3816 }
3817 }
3818
3819 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3820 INVALID_FIELD_IN_CDB, 0);
3821 errsts = check_condition_result;
3822 break;
3823
FUJITA Tomonori639db472008-03-20 11:09:19 +09003824 default:
3825 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3826 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3827 "supported\n", *cmd);
3828 errsts = check_readiness(SCpnt, 1, devip);
3829 if (errsts)
3830 break; /* Unit attention takes precedence */
3831 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3832 errsts = check_condition_result;
3833 break;
3834 }
3835 return schedule_resp(SCpnt, devip, done, errsts,
3836 (delay_override ? 0 : scsi_debug_delay));
3837}
3838
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003839static struct scsi_host_template sdebug_driver_template = {
3840 .proc_info = scsi_debug_proc_info,
3841 .proc_name = sdebug_proc_name,
3842 .name = "SCSI DEBUG",
3843 .info = scsi_debug_info,
3844 .slave_alloc = scsi_debug_slave_alloc,
3845 .slave_configure = scsi_debug_slave_configure,
3846 .slave_destroy = scsi_debug_slave_destroy,
3847 .ioctl = scsi_debug_ioctl,
3848 .queuecommand = scsi_debug_queuecommand,
3849 .eh_abort_handler = scsi_debug_abort,
3850 .eh_bus_reset_handler = scsi_debug_bus_reset,
3851 .eh_device_reset_handler = scsi_debug_device_reset,
3852 .eh_host_reset_handler = scsi_debug_host_reset,
3853 .bios_param = scsi_debug_biosparam,
3854 .can_queue = SCSI_DEBUG_CANQUEUE,
3855 .this_id = 7,
3856 .sg_tablesize = 256,
3857 .cmd_per_lun = 16,
3858 .max_sectors = 0xffff,
3859 .use_clustering = DISABLE_CLUSTERING,
3860 .module = THIS_MODULE,
3861};
3862
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863static int sdebug_driver_probe(struct device * dev)
3864{
3865 int error = 0;
3866 struct sdebug_host_info *sdbg_host;
3867 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003868 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869
3870 sdbg_host = to_sdebug_host(dev);
3871
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003872 sdebug_driver_template.can_queue = scsi_debug_max_queue;
3873 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3874 if (NULL == hpnt) {
3875 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
3876 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879
3880 sdbg_host->shost = hpnt;
3881 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3882 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3883 hpnt->max_id = scsi_debug_num_tgts + 1;
3884 else
3885 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003886 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003888 host_prot = 0;
3889
3890 switch (scsi_debug_dif) {
3891
3892 case SD_DIF_TYPE1_PROTECTION:
3893 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3894 if (scsi_debug_dix)
3895 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3896 break;
3897
3898 case SD_DIF_TYPE2_PROTECTION:
3899 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3900 if (scsi_debug_dix)
3901 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3902 break;
3903
3904 case SD_DIF_TYPE3_PROTECTION:
3905 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3906 if (scsi_debug_dix)
3907 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3908 break;
3909
3910 default:
3911 if (scsi_debug_dix)
3912 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3913 break;
3914 }
3915
3916 scsi_host_set_prot(hpnt, host_prot);
3917
3918 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3919 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3920 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3921 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3922 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3923 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3924 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3925 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3926
3927 if (scsi_debug_guard == 1)
3928 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3929 else
3930 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3931
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 error = scsi_add_host(hpnt, &sdbg_host->dev);
3933 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003934 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 error = -ENODEV;
3936 scsi_host_put(hpnt);
3937 } else
3938 scsi_scan_host(hpnt);
3939
3940
3941 return error;
3942}
3943
3944static int sdebug_driver_remove(struct device * dev)
3945{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003947 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948
3949 sdbg_host = to_sdebug_host(dev);
3950
3951 if (!sdbg_host) {
3952 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003953 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 return -ENODEV;
3955 }
3956
3957 scsi_remove_host(sdbg_host->shost);
3958
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003959 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3960 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 list_del(&sdbg_devinfo->dev_list);
3962 kfree(sdbg_devinfo);
3963 }
3964
3965 scsi_host_put(sdbg_host->shost);
3966 return 0;
3967}
3968
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003969static int pseudo_lld_bus_match(struct device *dev,
3970 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003972 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003974
3975static struct bus_type pseudo_lld_bus = {
3976 .name = "pseudo",
3977 .match = pseudo_lld_bus_match,
3978 .probe = sdebug_driver_probe,
3979 .remove = sdebug_driver_remove,
3980};