blob: 3e10c306de946b76002738fc0b214a786d6cbc7b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
15 * For documentation see http://www.torque.net/sg/sdebug26.html
16 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
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 Gilbert6f3cbf52007-01-05 00:05:25 -050061#define SCSI_DEBUG_VERSION "1.81"
62static const char * scsi_debug_version_date = "20070104";
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
150static int scsi_debug_add_host = DEF_NUM_HOST;
151static int scsi_debug_delay = DEF_DELAY;
152static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
153static int scsi_debug_every_nth = DEF_EVERY_NTH;
154static int scsi_debug_max_luns = DEF_MAX_LUNS;
155static int scsi_debug_num_parts = DEF_NUM_PARTS;
156static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
157static int scsi_debug_opts = DEF_OPTS;
158static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
159static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
160static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400161static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
162static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400163static int scsi_debug_fake_rw = DEF_FAKE_RW;
164static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400165static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500166static int scsi_debug_dix = DEF_DIX;
167static int scsi_debug_dif = DEF_DIF;
168static int scsi_debug_guard = DEF_GUARD;
169static int scsi_debug_ato = DEF_ATO;
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400170static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
171static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400172static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
173static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
174static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
175static int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177static int scsi_debug_cmnd_count = 0;
178
179#define DEV_READONLY(TGT) (0)
180#define DEV_REMOVEABLE(TGT) (0)
181
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400182static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static sector_t sdebug_capacity; /* in sectors */
184
185/* old BIOS stuff, kernel may get rid of them but some mode sense pages
186 may still need them */
187static int sdebug_heads; /* heads per disk */
188static int sdebug_cylinders_per; /* cylinders per surface */
189static int sdebug_sectors_per; /* sectors per cylinder */
190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191#define SDEBUG_MAX_PARTS 4
192
193#define SDEBUG_SENSE_LEN 32
194
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900195#define SCSI_DEBUG_CANQUEUE 255
Martin K. Petersen395cef02009-09-18 17:33:03 -0400196#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900197
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198struct sdebug_dev_info {
199 struct list_head dev_list;
200 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
201 unsigned int channel;
202 unsigned int target;
203 unsigned int lun;
204 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400205 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400207 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 char used;
209};
210
211struct sdebug_host_info {
212 struct list_head host_list;
213 struct Scsi_Host *shost;
214 struct device dev;
215 struct list_head dev_info_list;
216};
217
218#define to_sdebug_host(d) \
219 container_of(d, struct sdebug_host_info, dev)
220
221static LIST_HEAD(sdebug_host_list);
222static DEFINE_SPINLOCK(sdebug_host_list_lock);
223
224typedef void (* done_funct_t) (struct scsi_cmnd *);
225
226struct sdebug_queued_cmd {
227 int in_use;
228 struct timer_list cmnd_timer;
229 done_funct_t done_funct;
230 struct scsi_cmnd * a_cmnd;
231 int scsi_result;
232};
233static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
234
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235static unsigned char * fake_storep; /* ramdisk storage */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500236static unsigned char *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400237static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
Martin K. Petersen44d92692009-10-15 14:45:27 -0400239static unsigned long map_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240static int num_aborts = 0;
241static int num_dev_resets = 0;
242static int num_bus_resets = 0;
243static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500244static int dix_writes;
245static int dix_reads;
246static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
248static DEFINE_SPINLOCK(queued_arr_lock);
249static DEFINE_RWLOCK(atomic_rw);
250
251static char sdebug_proc_name[] = "scsi_debug";
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253static struct bus_type pseudo_lld_bus;
254
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500255static inline sector_t dif_offset(sector_t sector)
256{
257 return sector << 3;
258}
259
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260static struct device_driver sdebug_driverfs_driver = {
261 .name = sdebug_proc_name,
262 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263};
264
265static const int check_condition_result =
266 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
267
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500268static const int illegal_condition_result =
269 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
270
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400271static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
272 0, 0, 0x2, 0x4b};
273static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
274 0, 0, 0x0, 0x0};
275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276static int sdebug_add_adapter(void);
277static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900279static void sdebug_max_tgts_luns(void)
280{
281 struct sdebug_host_info *sdbg_host;
282 struct Scsi_Host *hpnt;
283
284 spin_lock(&sdebug_host_list_lock);
285 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
286 hpnt = sdbg_host->shost;
287 if ((hpnt->this_id >= 0) &&
288 (scsi_debug_num_tgts > hpnt->this_id))
289 hpnt->max_id = scsi_debug_num_tgts + 1;
290 else
291 hpnt->max_id = scsi_debug_num_tgts;
292 /* scsi_debug_max_luns; */
293 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
294 }
295 spin_unlock(&sdebug_host_list_lock);
296}
297
298static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
299 int asc, int asq)
300{
301 unsigned char *sbuff;
302
303 sbuff = devip->sense_buff;
304 memset(sbuff, 0, SDEBUG_SENSE_LEN);
305
306 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
307
308 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
309 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
310 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
311}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900313static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400314 unsigned long long *lba, unsigned int *num,
315 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900316{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400317 *ei_lba = 0;
318
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900319 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400320 case VARIABLE_LENGTH_CMD:
321 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
322 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
323 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
324 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
325
326 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
327 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
328
329 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
330 (u32)cmd[28] << 24;
331 break;
332
Martin K. Petersen44d92692009-10-15 14:45:27 -0400333 case WRITE_SAME_16:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900334 case WRITE_16:
335 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900336 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
337 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
338 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
339 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
340
341 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
342 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900343 break;
344 case WRITE_12:
345 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900346 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
347 (u32)cmd[2] << 24;
348
349 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
350 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900351 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400352 case WRITE_SAME:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900353 case WRITE_10:
354 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900355 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900356 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
357 (u32)cmd[2] << 24;
358
359 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900360 break;
361 case WRITE_6:
362 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900363 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
364 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900365 *num = (0 == cmd[4]) ? 256 : cmd[4];
366 break;
367 default:
368 break;
369 }
370}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
373{
374 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
375 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
376 }
377 return -EINVAL;
378 /* return -ENOTTY; // correct return but upsets fdisk */
379}
380
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400381static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
382 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
384 if (devip->reset) {
385 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
386 printk(KERN_INFO "scsi_debug: Reporting Unit "
387 "attention: power on reset\n");
388 devip->reset = 0;
389 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
390 return check_condition_result;
391 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400392 if ((0 == reset_only) && devip->stopped) {
393 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
394 printk(KERN_INFO "scsi_debug: Reporting Not "
395 "ready: initializing command required\n");
396 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
397 0x2);
398 return check_condition_result;
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 return 0;
401}
402
403/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900404static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 int arr_len)
406{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900407 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900408 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900410 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900412 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900414
415 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
416 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900417 if (sdb->resid)
418 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400419 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900420 sdb->resid = scsi_bufflen(scp) - act_len;
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return 0;
423}
424
425/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900426static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
427 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900429 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900431 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900433
434 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435}
436
437
438static const char * inq_vendor_id = "Linux ";
439static const char * inq_product_id = "scsi_debug ";
440static const char * inq_product_rev = "0004";
441
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200442static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
443 int target_dev_id, int dev_id_num,
444 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400445 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400447 int num, port_a;
448 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400450 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 /* T10 vendor identifier field format (faked) */
452 arr[0] = 0x2; /* ASCII */
453 arr[1] = 0x1;
454 arr[2] = 0x0;
455 memcpy(&arr[4], inq_vendor_id, 8);
456 memcpy(&arr[12], inq_product_id, 16);
457 memcpy(&arr[28], dev_id_str, dev_id_str_len);
458 num = 8 + 16 + dev_id_str_len;
459 arr[3] = num;
460 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400461 if (dev_id_num >= 0) {
462 /* NAA-5, Logical unit identifier (binary) */
463 arr[num++] = 0x1; /* binary (not necessarily sas) */
464 arr[num++] = 0x3; /* PIV=0, lu, naa */
465 arr[num++] = 0x0;
466 arr[num++] = 0x8;
467 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
468 arr[num++] = 0x33;
469 arr[num++] = 0x33;
470 arr[num++] = 0x30;
471 arr[num++] = (dev_id_num >> 24);
472 arr[num++] = (dev_id_num >> 16) & 0xff;
473 arr[num++] = (dev_id_num >> 8) & 0xff;
474 arr[num++] = dev_id_num & 0xff;
475 /* Target relative port number */
476 arr[num++] = 0x61; /* proto=sas, binary */
477 arr[num++] = 0x94; /* PIV=1, target port, rel port */
478 arr[num++] = 0x0; /* reserved */
479 arr[num++] = 0x4; /* length */
480 arr[num++] = 0x0; /* reserved */
481 arr[num++] = 0x0; /* reserved */
482 arr[num++] = 0x0;
483 arr[num++] = 0x1; /* relative port A */
484 }
485 /* NAA-5, Target port identifier */
486 arr[num++] = 0x61; /* proto=sas, binary */
487 arr[num++] = 0x93; /* piv=1, target port, naa */
488 arr[num++] = 0x0;
489 arr[num++] = 0x8;
490 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
491 arr[num++] = 0x22;
492 arr[num++] = 0x22;
493 arr[num++] = 0x20;
494 arr[num++] = (port_a >> 24);
495 arr[num++] = (port_a >> 16) & 0xff;
496 arr[num++] = (port_a >> 8) & 0xff;
497 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200498 /* NAA-5, Target port group identifier */
499 arr[num++] = 0x61; /* proto=sas, binary */
500 arr[num++] = 0x95; /* piv=1, target port group id */
501 arr[num++] = 0x0;
502 arr[num++] = 0x4;
503 arr[num++] = 0;
504 arr[num++] = 0;
505 arr[num++] = (port_group_id >> 8) & 0xff;
506 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400507 /* NAA-5, Target device identifier */
508 arr[num++] = 0x61; /* proto=sas, binary */
509 arr[num++] = 0xa3; /* piv=1, target device, naa */
510 arr[num++] = 0x0;
511 arr[num++] = 0x8;
512 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
513 arr[num++] = 0x22;
514 arr[num++] = 0x22;
515 arr[num++] = 0x20;
516 arr[num++] = (target_dev_id >> 24);
517 arr[num++] = (target_dev_id >> 16) & 0xff;
518 arr[num++] = (target_dev_id >> 8) & 0xff;
519 arr[num++] = target_dev_id & 0xff;
520 /* SCSI name string: Target device identifier */
521 arr[num++] = 0x63; /* proto=sas, UTF-8 */
522 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
523 arr[num++] = 0x0;
524 arr[num++] = 24;
525 memcpy(arr + num, "naa.52222220", 12);
526 num += 12;
527 snprintf(b, sizeof(b), "%08X", target_dev_id);
528 memcpy(arr + num, b, 8);
529 num += 8;
530 memset(arr + num, 0, 4);
531 num += 4;
532 return num;
533}
534
535
536static unsigned char vpd84_data[] = {
537/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
538 0x22,0x22,0x22,0x0,0xbb,0x1,
539 0x22,0x22,0x22,0x0,0xbb,0x2,
540};
541
542static int inquiry_evpd_84(unsigned char * arr)
543{
544 memcpy(arr, vpd84_data, sizeof(vpd84_data));
545 return sizeof(vpd84_data);
546}
547
548static int inquiry_evpd_85(unsigned char * arr)
549{
550 int num = 0;
551 const char * na1 = "https://www.kernel.org/config";
552 const char * na2 = "http://www.kernel.org/log";
553 int plen, olen;
554
555 arr[num++] = 0x1; /* lu, storage config */
556 arr[num++] = 0x0; /* reserved */
557 arr[num++] = 0x0;
558 olen = strlen(na1);
559 plen = olen + 1;
560 if (plen % 4)
561 plen = ((plen / 4) + 1) * 4;
562 arr[num++] = plen; /* length, null termianted, padded */
563 memcpy(arr + num, na1, olen);
564 memset(arr + num + olen, 0, plen - olen);
565 num += plen;
566
567 arr[num++] = 0x4; /* lu, logging */
568 arr[num++] = 0x0; /* reserved */
569 arr[num++] = 0x0;
570 olen = strlen(na2);
571 plen = olen + 1;
572 if (plen % 4)
573 plen = ((plen / 4) + 1) * 4;
574 arr[num++] = plen; /* length, null terminated, padded */
575 memcpy(arr + num, na2, olen);
576 memset(arr + num + olen, 0, plen - olen);
577 num += plen;
578
579 return num;
580}
581
582/* SCSI ports VPD page */
583static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
584{
585 int num = 0;
586 int port_a, port_b;
587
588 port_a = target_dev_id + 1;
589 port_b = port_a + 1;
590 arr[num++] = 0x0; /* reserved */
591 arr[num++] = 0x0; /* reserved */
592 arr[num++] = 0x0;
593 arr[num++] = 0x1; /* relative port 1 (primary) */
594 memset(arr + num, 0, 6);
595 num += 6;
596 arr[num++] = 0x0;
597 arr[num++] = 12; /* length tp descriptor */
598 /* naa-5 target port identifier (A) */
599 arr[num++] = 0x61; /* proto=sas, binary */
600 arr[num++] = 0x93; /* PIV=1, target port, NAA */
601 arr[num++] = 0x0; /* reserved */
602 arr[num++] = 0x8; /* length */
603 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
604 arr[num++] = 0x22;
605 arr[num++] = 0x22;
606 arr[num++] = 0x20;
607 arr[num++] = (port_a >> 24);
608 arr[num++] = (port_a >> 16) & 0xff;
609 arr[num++] = (port_a >> 8) & 0xff;
610 arr[num++] = port_a & 0xff;
611
612 arr[num++] = 0x0; /* reserved */
613 arr[num++] = 0x0; /* reserved */
614 arr[num++] = 0x0;
615 arr[num++] = 0x2; /* relative port 2 (secondary) */
616 memset(arr + num, 0, 6);
617 num += 6;
618 arr[num++] = 0x0;
619 arr[num++] = 12; /* length tp descriptor */
620 /* naa-5 target port identifier (B) */
621 arr[num++] = 0x61; /* proto=sas, binary */
622 arr[num++] = 0x93; /* PIV=1, target port, NAA */
623 arr[num++] = 0x0; /* reserved */
624 arr[num++] = 0x8; /* length */
625 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
626 arr[num++] = 0x22;
627 arr[num++] = 0x22;
628 arr[num++] = 0x20;
629 arr[num++] = (port_b >> 24);
630 arr[num++] = (port_b >> 16) & 0xff;
631 arr[num++] = (port_b >> 8) & 0xff;
632 arr[num++] = port_b & 0xff;
633
634 return num;
635}
636
637
638static unsigned char vpd89_data[] = {
639/* from 4th byte */ 0,0,0,0,
640'l','i','n','u','x',' ',' ',' ',
641'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
642'1','2','3','4',
6430x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6440xec,0,0,0,
6450x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6460,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6470x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6480x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6490x53,0x41,
6500x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6510x20,0x20,
6520x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6530x10,0x80,
6540,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6550x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6560x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6570,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6580x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6590x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6600,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6610,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6620,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6640x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6650,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6660xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6670,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6690,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
680};
681
682static int inquiry_evpd_89(unsigned char * arr)
683{
684 memcpy(arr, vpd89_data, sizeof(vpd89_data));
685 return sizeof(vpd89_data);
686}
687
688
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400689/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400690static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400691 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
692 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
693 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
694 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400695};
696
697static int inquiry_evpd_b0(unsigned char * arr)
698{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400699 unsigned int gran;
700
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400701 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400702 gran = 1 << scsi_debug_physblk_exp;
703 arr[2] = (gran >> 8) & 0xff;
704 arr[3] = gran & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400705 if (sdebug_store_sectors > 0x400) {
706 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
707 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
708 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
709 arr[7] = sdebug_store_sectors & 0xff;
710 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400711
712 if (scsi_debug_unmap_max_desc) {
713 unsigned int blocks;
714
715 if (scsi_debug_unmap_max_blocks)
716 blocks = scsi_debug_unmap_max_blocks;
717 else
718 blocks = 0xffffffff;
719
720 put_unaligned_be32(blocks, &arr[16]);
721 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
722 }
723
724 if (scsi_debug_unmap_alignment) {
725 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
726 arr[28] |= 0x80; /* UGAVALID */
727 }
728
729 if (scsi_debug_unmap_granularity) {
730 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
731 return 0x3c; /* Mandatory page length for thin provisioning */
732 }
733
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400734 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735}
736
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400737/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600738static int inquiry_evpd_b1(unsigned char *arr)
739{
740 memset(arr, 0, 0x3c);
741 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400742 arr[1] = 1; /* non rotating medium (e.g. solid state) */
743 arr[2] = 0;
744 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600745
746 return 0x3c;
747}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400750#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751
752static int resp_inquiry(struct scsi_cmnd * scp, int target,
753 struct sdebug_dev_info * devip)
754{
755 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200756 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200758 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
760 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500761 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
762 if (! arr)
763 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400764 if (devip->wlun)
765 pq_pdt = 0x1e; /* present, wlun */
766 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
767 pq_pdt = 0x7f; /* not present, no device type */
768 else
769 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 arr[0] = pq_pdt;
771 if (0x2 & cmd[1]) { /* CMDDT bit set */
772 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
773 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200774 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 return check_condition_result;
776 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200777 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400778 char lu_id_str[6];
779 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200781 port_group_id = (((host_no + 1) & 0x7f) << 8) +
782 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400783 if (0 == scsi_debug_vpd_use_hostno)
784 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400785 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
786 (devip->target * 1000) + devip->lun);
787 target_dev_id = ((host_no + 1) * 2000) +
788 (devip->target * 1000) - 3;
789 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400791 arr[1] = cmd[2]; /*sanity */
792 n = 4;
793 arr[n++] = 0x0; /* this page */
794 arr[n++] = 0x80; /* unit serial number */
795 arr[n++] = 0x83; /* device identification */
796 arr[n++] = 0x84; /* software interface ident. */
797 arr[n++] = 0x85; /* management network addresses */
798 arr[n++] = 0x86; /* extended inquiry */
799 arr[n++] = 0x87; /* mode page policy */
800 arr[n++] = 0x88; /* SCSI ports */
801 arr[n++] = 0x89; /* ATA information */
802 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600803 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400804 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400806 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400808 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400810 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200811 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
812 target_dev_id, lu_id_num,
813 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400814 } else if (0x84 == cmd[2]) { /* Software interface ident. */
815 arr[1] = cmd[2]; /*sanity */
816 arr[3] = inquiry_evpd_84(&arr[4]);
817 } else if (0x85 == cmd[2]) { /* Management network addresses */
818 arr[1] = cmd[2]; /*sanity */
819 arr[3] = inquiry_evpd_85(&arr[4]);
820 } else if (0x86 == cmd[2]) { /* extended inquiry */
821 arr[1] = cmd[2]; /*sanity */
822 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500823 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
824 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
825 else if (scsi_debug_dif)
826 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
827 else
828 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400829 arr[5] = 0x7; /* head of q, ordered + simple q's */
830 } else if (0x87 == cmd[2]) { /* mode page policy */
831 arr[1] = cmd[2]; /*sanity */
832 arr[3] = 0x8; /* number of following entries */
833 arr[4] = 0x2; /* disconnect-reconnect mp */
834 arr[6] = 0x80; /* mlus, shared */
835 arr[8] = 0x18; /* protocol specific lu */
836 arr[10] = 0x82; /* mlus, per initiator port */
837 } else if (0x88 == cmd[2]) { /* SCSI Ports */
838 arr[1] = cmd[2]; /*sanity */
839 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
840 } else if (0x89 == cmd[2]) { /* ATA information */
841 arr[1] = cmd[2]; /*sanity */
842 n = inquiry_evpd_89(&arr[4]);
843 arr[2] = (n >> 8);
844 arr[3] = (n & 0xff);
845 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
846 arr[1] = cmd[2]; /*sanity */
847 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600848 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
849 arr[1] = cmd[2]; /*sanity */
850 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 } else {
852 /* Illegal request, invalid field in cdb */
853 mk_sense_buffer(devip, ILLEGAL_REQUEST,
854 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200855 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 return check_condition_result;
857 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400858 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200859 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400860 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200861 kfree(arr);
862 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 }
864 /* drops through here for a standard inquiry */
865 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
866 arr[2] = scsi_debug_scsi_level;
867 arr[3] = 2; /* response_data_format==2 */
868 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500869 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200870 if (0 == scsi_debug_vpd_use_hostno)
871 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400872 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400874 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 memcpy(&arr[8], inq_vendor_id, 8);
876 memcpy(&arr[16], inq_product_id, 16);
877 memcpy(&arr[32], inq_product_rev, 4);
878 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400879 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
880 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
881 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400883 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400885 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400887 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200888 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200890 kfree(arr);
891 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892}
893
894static int resp_requests(struct scsi_cmnd * scp,
895 struct sdebug_dev_info * devip)
896{
897 unsigned char * sbuff;
898 unsigned char *cmd = (unsigned char *)scp->cmnd;
899 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400900 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 int len = 18;
902
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400903 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400905 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
906 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400908 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
909 if (want_dsense) {
910 arr[0] = 0x72;
911 arr[1] = 0x0; /* NO_SENSE in sense_key */
912 arr[2] = THRESHOLD_EXCEEDED;
913 arr[3] = 0xff; /* TEST set and MRIE==6 */
914 } else {
915 arr[0] = 0x70;
916 arr[2] = 0x0; /* NO_SENSE in sense_key */
917 arr[7] = 0xa; /* 18 byte sense buffer */
918 arr[12] = THRESHOLD_EXCEEDED;
919 arr[13] = 0xff; /* TEST set and MRIE==6 */
920 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400921 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400923 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
924 /* DESC bit set and sense_buff in fixed format */
925 memset(arr, 0, sizeof(arr));
926 arr[0] = 0x72;
927 arr[1] = sbuff[2]; /* sense key */
928 arr[2] = sbuff[12]; /* asc */
929 arr[3] = sbuff[13]; /* ascq */
930 len = 8;
931 }
932 }
933 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 return fill_from_dev_buffer(scp, arr, len);
935}
936
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400937static int resp_start_stop(struct scsi_cmnd * scp,
938 struct sdebug_dev_info * devip)
939{
940 unsigned char *cmd = (unsigned char *)scp->cmnd;
941 int power_cond, errsts, start;
942
943 if ((errsts = check_readiness(scp, 1, devip)))
944 return errsts;
945 power_cond = (cmd[4] & 0xf0) >> 4;
946 if (power_cond) {
947 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
948 0);
949 return check_condition_result;
950 }
951 start = cmd[4] & 1;
952 if (start == devip->stopped)
953 devip->stopped = !start;
954 return 0;
955}
956
FUJITA Tomonori28898872008-03-30 00:59:55 +0900957static sector_t get_sdebug_capacity(void)
958{
959 if (scsi_debug_virtual_gb > 0)
FUJITA Tomonori73da9c12009-04-22 17:42:25 -0700960 return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
FUJITA Tomonori28898872008-03-30 00:59:55 +0900961 else
962 return sdebug_store_sectors;
963}
964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965#define SDEBUG_READCAP_ARR_SZ 8
966static int resp_readcap(struct scsi_cmnd * scp,
967 struct sdebug_dev_info * devip)
968{
969 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400970 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 int errsts;
972
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400973 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400975 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900976 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400978 if (sdebug_capacity < 0xffffffff) {
979 capac = (unsigned int)sdebug_capacity - 1;
980 arr[0] = (capac >> 24);
981 arr[1] = (capac >> 16) & 0xff;
982 arr[2] = (capac >> 8) & 0xff;
983 arr[3] = capac & 0xff;
984 } else {
985 arr[0] = 0xff;
986 arr[1] = 0xff;
987 arr[2] = 0xff;
988 arr[3] = 0xff;
989 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400990 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
991 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
993}
994
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400995#define SDEBUG_READCAP16_ARR_SZ 32
996static int resp_readcap16(struct scsi_cmnd * scp,
997 struct sdebug_dev_info * devip)
998{
999 unsigned char *cmd = (unsigned char *)scp->cmnd;
1000 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1001 unsigned long long capac;
1002 int errsts, k, alloc_len;
1003
1004 if ((errsts = check_readiness(scp, 1, devip)))
1005 return errsts;
1006 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1007 + cmd[13]);
1008 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001009 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001010 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1011 capac = sdebug_capacity - 1;
1012 for (k = 0; k < 8; ++k, capac >>= 8)
1013 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001014 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1015 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1016 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1017 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001018 arr[13] = scsi_debug_physblk_exp & 0xf;
1019 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001020
1021 if (scsi_debug_unmap_granularity)
1022 arr[14] |= 0x80; /* TPE */
1023
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001024 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001025
1026 if (scsi_debug_dif) {
1027 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1028 arr[12] |= 1; /* PROT_EN */
1029 }
1030
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001031 return fill_from_dev_buffer(scp, arr,
1032 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1033}
1034
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001035#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1036
1037static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1038 struct sdebug_dev_info * devip)
1039{
1040 unsigned char *cmd = (unsigned char *)scp->cmnd;
1041 unsigned char * arr;
1042 int host_no = devip->sdbg_host->shost->host_no;
1043 int n, ret, alen, rlen;
1044 int port_group_a, port_group_b, port_a, port_b;
1045
1046 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1047 + cmd[9]);
1048
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001049 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1050 if (! arr)
1051 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001052 /*
1053 * EVPD page 0x88 states we have two ports, one
1054 * real and a fake port with no device connected.
1055 * So we create two port groups with one port each
1056 * and set the group with port B to unavailable.
1057 */
1058 port_a = 0x1; /* relative port A */
1059 port_b = 0x2; /* relative port B */
1060 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1061 (devip->channel & 0x7f);
1062 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1063 (devip->channel & 0x7f) + 0x80;
1064
1065 /*
1066 * The asymmetric access state is cycled according to the host_id.
1067 */
1068 n = 4;
1069 if (0 == scsi_debug_vpd_use_hostno) {
1070 arr[n++] = host_no % 3; /* Asymm access state */
1071 arr[n++] = 0x0F; /* claim: all states are supported */
1072 } else {
1073 arr[n++] = 0x0; /* Active/Optimized path */
1074 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1075 }
1076 arr[n++] = (port_group_a >> 8) & 0xff;
1077 arr[n++] = port_group_a & 0xff;
1078 arr[n++] = 0; /* Reserved */
1079 arr[n++] = 0; /* Status code */
1080 arr[n++] = 0; /* Vendor unique */
1081 arr[n++] = 0x1; /* One port per group */
1082 arr[n++] = 0; /* Reserved */
1083 arr[n++] = 0; /* Reserved */
1084 arr[n++] = (port_a >> 8) & 0xff;
1085 arr[n++] = port_a & 0xff;
1086 arr[n++] = 3; /* Port unavailable */
1087 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1088 arr[n++] = (port_group_b >> 8) & 0xff;
1089 arr[n++] = port_group_b & 0xff;
1090 arr[n++] = 0; /* Reserved */
1091 arr[n++] = 0; /* Status code */
1092 arr[n++] = 0; /* Vendor unique */
1093 arr[n++] = 0x1; /* One port per group */
1094 arr[n++] = 0; /* Reserved */
1095 arr[n++] = 0; /* Reserved */
1096 arr[n++] = (port_b >> 8) & 0xff;
1097 arr[n++] = port_b & 0xff;
1098
1099 rlen = n - 4;
1100 arr[0] = (rlen >> 24) & 0xff;
1101 arr[1] = (rlen >> 16) & 0xff;
1102 arr[2] = (rlen >> 8) & 0xff;
1103 arr[3] = rlen & 0xff;
1104
1105 /*
1106 * Return the smallest value of either
1107 * - The allocated length
1108 * - The constructed command length
1109 * - The maximum array size
1110 */
1111 rlen = min(alen,n);
1112 ret = fill_from_dev_buffer(scp, arr,
1113 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1114 kfree(arr);
1115 return ret;
1116}
1117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118/* <<Following mode page info copied from ST318451LW>> */
1119
1120static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1121{ /* Read-Write Error Recovery page for mode_sense */
1122 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1123 5, 0, 0xff, 0xff};
1124
1125 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1126 if (1 == pcontrol)
1127 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1128 return sizeof(err_recov_pg);
1129}
1130
1131static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1132{ /* Disconnect-Reconnect page for mode_sense */
1133 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1134 0, 0, 0, 0, 0, 0, 0, 0};
1135
1136 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1137 if (1 == pcontrol)
1138 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1139 return sizeof(disconnect_pg);
1140}
1141
1142static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1143{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001144 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1145 0, 0, 0, 0, 0, 0, 0, 0,
1146 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Martin K. Petersen597136a2008-06-05 00:12:59 -04001148 memcpy(p, format_pg, sizeof(format_pg));
1149 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1150 p[11] = sdebug_sectors_per & 0xff;
1151 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1152 p[13] = scsi_debug_sector_size & 0xff;
1153 if (DEV_REMOVEABLE(target))
1154 p[20] |= 0x20; /* should agree with INQUIRY */
1155 if (1 == pcontrol)
1156 memset(p + 2, 0, sizeof(format_pg) - 2);
1157 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158}
1159
1160static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1161{ /* Caching page for mode_sense */
1162 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1163 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1164
1165 memcpy(p, caching_pg, sizeof(caching_pg));
1166 if (1 == pcontrol)
1167 memset(p + 2, 0, sizeof(caching_pg) - 2);
1168 return sizeof(caching_pg);
1169}
1170
1171static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1172{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001173 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1174 0, 0, 0, 0};
1175 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 0, 0, 0x2, 0x4b};
1177
1178 if (scsi_debug_dsense)
1179 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001180 else
1181 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001182
1183 if (scsi_debug_ato)
1184 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1187 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001188 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1189 else if (2 == pcontrol)
1190 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 return sizeof(ctrl_m_pg);
1192}
1193
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1196{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001197 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1198 0, 0, 0x0, 0x0};
1199 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1200 0, 0, 0x0, 0x0};
1201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1203 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001204 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1205 else if (2 == pcontrol)
1206 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 return sizeof(iec_m_pg);
1208}
1209
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001210static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1211{ /* SAS SSP mode page - short format for mode_sense */
1212 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1213 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1214
1215 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1216 if (1 == pcontrol)
1217 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1218 return sizeof(sas_sf_m_pg);
1219}
1220
1221
1222static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1223 int target_dev_id)
1224{ /* SAS phy control and discover mode page for mode_sense */
1225 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1226 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1227 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1228 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1229 0x2, 0, 0, 0, 0, 0, 0, 0,
1230 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1231 0, 0, 0, 0, 0, 0, 0, 0,
1232 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1233 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1234 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1235 0x3, 0, 0, 0, 0, 0, 0, 0,
1236 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1237 0, 0, 0, 0, 0, 0, 0, 0,
1238 };
1239 int port_a, port_b;
1240
1241 port_a = target_dev_id + 1;
1242 port_b = port_a + 1;
1243 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1244 p[20] = (port_a >> 24);
1245 p[21] = (port_a >> 16) & 0xff;
1246 p[22] = (port_a >> 8) & 0xff;
1247 p[23] = port_a & 0xff;
1248 p[48 + 20] = (port_b >> 24);
1249 p[48 + 21] = (port_b >> 16) & 0xff;
1250 p[48 + 22] = (port_b >> 8) & 0xff;
1251 p[48 + 23] = port_b & 0xff;
1252 if (1 == pcontrol)
1253 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1254 return sizeof(sas_pcd_m_pg);
1255}
1256
1257static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1258{ /* SAS SSP shared protocol specific port mode subpage */
1259 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1260 0, 0, 0, 0, 0, 0, 0, 0,
1261 };
1262
1263 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1264 if (1 == pcontrol)
1265 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1266 return sizeof(sas_sha_m_pg);
1267}
1268
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269#define SDEBUG_MAX_MSENSE_SZ 256
1270
1271static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1272 struct sdebug_dev_info * devip)
1273{
Douglas Gilbert23183912006-09-16 20:30:47 -04001274 unsigned char dbd, llbaa;
1275 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001277 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 unsigned char * ap;
1279 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1280 unsigned char *cmd = (unsigned char *)scp->cmnd;
1281
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001282 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001284 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 pcontrol = (cmd[2] & 0xc0) >> 6;
1286 pcode = cmd[2] & 0x3f;
1287 subpcode = cmd[3];
1288 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001289 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1290 if ((0 == scsi_debug_ptype) && (0 == dbd))
1291 bd_len = llbaa ? 16 : 8;
1292 else
1293 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1295 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1296 if (0x3 == pcontrol) { /* Saving values not supported */
1297 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1298 0);
1299 return check_condition_result;
1300 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001301 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1302 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001303 /* set DPOFUA bit for disks */
1304 if (0 == scsi_debug_ptype)
1305 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1306 else
1307 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 if (msense_6) {
1309 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001310 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 offset = 4;
1312 } else {
1313 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001314 if (16 == bd_len)
1315 arr[4] = 0x1; /* set LONGLBA bit */
1316 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 offset = 8;
1318 }
1319 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001320 if ((bd_len > 0) && (!sdebug_capacity))
1321 sdebug_capacity = get_sdebug_capacity();
1322
Douglas Gilbert23183912006-09-16 20:30:47 -04001323 if (8 == bd_len) {
1324 if (sdebug_capacity > 0xfffffffe) {
1325 ap[0] = 0xff;
1326 ap[1] = 0xff;
1327 ap[2] = 0xff;
1328 ap[3] = 0xff;
1329 } else {
1330 ap[0] = (sdebug_capacity >> 24) & 0xff;
1331 ap[1] = (sdebug_capacity >> 16) & 0xff;
1332 ap[2] = (sdebug_capacity >> 8) & 0xff;
1333 ap[3] = sdebug_capacity & 0xff;
1334 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001335 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1336 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001337 offset += bd_len;
1338 ap = arr + offset;
1339 } else if (16 == bd_len) {
1340 unsigned long long capac = sdebug_capacity;
1341
1342 for (k = 0; k < 8; ++k, capac >>= 8)
1343 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001344 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1345 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1346 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1347 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001348 offset += bd_len;
1349 ap = arr + offset;
1350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001352 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1353 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1355 0);
1356 return check_condition_result;
1357 }
1358 switch (pcode) {
1359 case 0x1: /* Read-Write error recovery page, direct access */
1360 len = resp_err_recov_pg(ap, pcontrol, target);
1361 offset += len;
1362 break;
1363 case 0x2: /* Disconnect-Reconnect page, all devices */
1364 len = resp_disconnect_pg(ap, pcontrol, target);
1365 offset += len;
1366 break;
1367 case 0x3: /* Format device page, direct access */
1368 len = resp_format_pg(ap, pcontrol, target);
1369 offset += len;
1370 break;
1371 case 0x8: /* Caching page, direct access */
1372 len = resp_caching_pg(ap, pcontrol, target);
1373 offset += len;
1374 break;
1375 case 0xa: /* Control Mode page, all devices */
1376 len = resp_ctrl_m_pg(ap, pcontrol, target);
1377 offset += len;
1378 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001379 case 0x19: /* if spc==1 then sas phy, control+discover */
1380 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1381 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1382 INVALID_FIELD_IN_CDB, 0);
1383 return check_condition_result;
1384 }
1385 len = 0;
1386 if ((0x0 == subpcode) || (0xff == subpcode))
1387 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1388 if ((0x1 == subpcode) || (0xff == subpcode))
1389 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1390 target_dev_id);
1391 if ((0x2 == subpcode) || (0xff == subpcode))
1392 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1393 offset += len;
1394 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 case 0x1c: /* Informational Exceptions Mode page, all devices */
1396 len = resp_iec_m_pg(ap, pcontrol, target);
1397 offset += len;
1398 break;
1399 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001400 if ((0 == subpcode) || (0xff == subpcode)) {
1401 len = resp_err_recov_pg(ap, pcontrol, target);
1402 len += resp_disconnect_pg(ap + len, pcontrol, target);
1403 len += resp_format_pg(ap + len, pcontrol, target);
1404 len += resp_caching_pg(ap + len, pcontrol, target);
1405 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1406 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1407 if (0xff == subpcode) {
1408 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1409 target, target_dev_id);
1410 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1411 }
1412 len += resp_iec_m_pg(ap + len, pcontrol, target);
1413 } else {
1414 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1415 INVALID_FIELD_IN_CDB, 0);
1416 return check_condition_result;
1417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 offset += len;
1419 break;
1420 default:
1421 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1422 0);
1423 return check_condition_result;
1424 }
1425 if (msense_6)
1426 arr[0] = offset - 1;
1427 else {
1428 arr[0] = ((offset - 2) >> 8) & 0xff;
1429 arr[1] = (offset - 2) & 0xff;
1430 }
1431 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1432}
1433
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001434#define SDEBUG_MAX_MSELECT_SZ 512
1435
1436static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1437 struct sdebug_dev_info * devip)
1438{
1439 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1440 int param_len, res, errsts, mpage;
1441 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1442 unsigned char *cmd = (unsigned char *)scp->cmnd;
1443
1444 if ((errsts = check_readiness(scp, 1, devip)))
1445 return errsts;
1446 memset(arr, 0, sizeof(arr));
1447 pf = cmd[1] & 0x10;
1448 sp = cmd[1] & 0x1;
1449 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1450 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1451 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1452 INVALID_FIELD_IN_CDB, 0);
1453 return check_condition_result;
1454 }
1455 res = fetch_to_dev_buffer(scp, arr, param_len);
1456 if (-1 == res)
1457 return (DID_ERROR << 16);
1458 else if ((res < param_len) &&
1459 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1460 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1461 " IO sent=%d bytes\n", param_len, res);
1462 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1463 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001464 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001465 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1466 INVALID_FIELD_IN_PARAM_LIST, 0);
1467 return check_condition_result;
1468 }
1469 off = bd_len + (mselect6 ? 4 : 8);
1470 mpage = arr[off] & 0x3f;
1471 ps = !!(arr[off] & 0x80);
1472 if (ps) {
1473 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1474 INVALID_FIELD_IN_PARAM_LIST, 0);
1475 return check_condition_result;
1476 }
1477 spf = !!(arr[off] & 0x40);
1478 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1479 (arr[off + 1] + 2);
1480 if ((pg_len + off) > param_len) {
1481 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1482 PARAMETER_LIST_LENGTH_ERR, 0);
1483 return check_condition_result;
1484 }
1485 switch (mpage) {
1486 case 0xa: /* Control Mode page */
1487 if (ctrl_m_pg[1] == arr[off + 1]) {
1488 memcpy(ctrl_m_pg + 2, arr + off + 2,
1489 sizeof(ctrl_m_pg) - 2);
1490 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1491 return 0;
1492 }
1493 break;
1494 case 0x1c: /* Informational Exceptions Mode page */
1495 if (iec_m_pg[1] == arr[off + 1]) {
1496 memcpy(iec_m_pg + 2, arr + off + 2,
1497 sizeof(iec_m_pg) - 2);
1498 return 0;
1499 }
1500 break;
1501 default:
1502 break;
1503 }
1504 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1505 INVALID_FIELD_IN_PARAM_LIST, 0);
1506 return check_condition_result;
1507}
1508
1509static int resp_temp_l_pg(unsigned char * arr)
1510{
1511 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1512 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1513 };
1514
1515 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1516 return sizeof(temp_l_pg);
1517}
1518
1519static int resp_ie_l_pg(unsigned char * arr)
1520{
1521 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1522 };
1523
1524 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1525 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1526 arr[4] = THRESHOLD_EXCEEDED;
1527 arr[5] = 0xff;
1528 }
1529 return sizeof(ie_l_pg);
1530}
1531
1532#define SDEBUG_MAX_LSENSE_SZ 512
1533
1534static int resp_log_sense(struct scsi_cmnd * scp,
1535 struct sdebug_dev_info * devip)
1536{
Douglas Gilbert23183912006-09-16 20:30:47 -04001537 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001538 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1539 unsigned char *cmd = (unsigned char *)scp->cmnd;
1540
1541 if ((errsts = check_readiness(scp, 1, devip)))
1542 return errsts;
1543 memset(arr, 0, sizeof(arr));
1544 ppc = cmd[1] & 0x2;
1545 sp = cmd[1] & 0x1;
1546 if (ppc || sp) {
1547 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1548 INVALID_FIELD_IN_CDB, 0);
1549 return check_condition_result;
1550 }
1551 pcontrol = (cmd[2] & 0xc0) >> 6;
1552 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001553 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001554 alloc_len = (cmd[7] << 8) + cmd[8];
1555 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001556 if (0 == subpcode) {
1557 switch (pcode) {
1558 case 0x0: /* Supported log pages log page */
1559 n = 4;
1560 arr[n++] = 0x0; /* this page */
1561 arr[n++] = 0xd; /* Temperature */
1562 arr[n++] = 0x2f; /* Informational exceptions */
1563 arr[3] = n - 4;
1564 break;
1565 case 0xd: /* Temperature log page */
1566 arr[3] = resp_temp_l_pg(arr + 4);
1567 break;
1568 case 0x2f: /* Informational exceptions log page */
1569 arr[3] = resp_ie_l_pg(arr + 4);
1570 break;
1571 default:
1572 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1573 INVALID_FIELD_IN_CDB, 0);
1574 return check_condition_result;
1575 }
1576 } else if (0xff == subpcode) {
1577 arr[0] |= 0x40;
1578 arr[1] = subpcode;
1579 switch (pcode) {
1580 case 0x0: /* Supported log pages and subpages log page */
1581 n = 4;
1582 arr[n++] = 0x0;
1583 arr[n++] = 0x0; /* 0,0 page */
1584 arr[n++] = 0x0;
1585 arr[n++] = 0xff; /* this page */
1586 arr[n++] = 0xd;
1587 arr[n++] = 0x0; /* Temperature */
1588 arr[n++] = 0x2f;
1589 arr[n++] = 0x0; /* Informational exceptions */
1590 arr[3] = n - 4;
1591 break;
1592 case 0xd: /* Temperature subpages */
1593 n = 4;
1594 arr[n++] = 0xd;
1595 arr[n++] = 0x0; /* Temperature */
1596 arr[3] = n - 4;
1597 break;
1598 case 0x2f: /* Informational exceptions subpages */
1599 n = 4;
1600 arr[n++] = 0x2f;
1601 arr[n++] = 0x0; /* Informational exceptions */
1602 arr[3] = n - 4;
1603 break;
1604 default:
1605 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1606 INVALID_FIELD_IN_CDB, 0);
1607 return check_condition_result;
1608 }
1609 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001610 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1611 INVALID_FIELD_IN_CDB, 0);
1612 return check_condition_result;
1613 }
1614 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1615 return fill_from_dev_buffer(scp, arr,
1616 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1617}
1618
FUJITA Tomonori19789102008-03-30 00:59:56 +09001619static int check_device_access_params(struct sdebug_dev_info *devi,
1620 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001622 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001623 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 return check_condition_result;
1625 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001626 /* transfer length excessive (tie in to block limits VPD page) */
1627 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001628 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001629 return check_condition_result;
1630 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001631 return 0;
1632}
1633
1634static int do_device_access(struct scsi_cmnd *scmd,
1635 struct sdebug_dev_info *devi,
1636 unsigned long long lba, unsigned int num, int write)
1637{
1638 int ret;
1639 unsigned int block, rest = 0;
1640 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1641
1642 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1643
1644 block = do_div(lba, sdebug_store_sectors);
1645 if (block + num > sdebug_store_sectors)
1646 rest = block + num - sdebug_store_sectors;
1647
Martin K. Petersen597136a2008-06-05 00:12:59 -04001648 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1649 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001650 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001651 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001652
1653 return ret;
1654}
1655
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001656static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001657 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001658{
1659 unsigned int i, resid;
1660 struct scatterlist *psgl;
1661 struct sd_dif_tuple *sdt;
1662 sector_t sector;
1663 sector_t tmp_sec = start_sec;
1664 void *paddr;
1665
1666 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1667
1668 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1669
1670 for (i = 0 ; i < sectors ; i++) {
1671 u16 csum;
1672
1673 if (sdt[i].app_tag == 0xffff)
1674 continue;
1675
1676 sector = start_sec + i;
1677
1678 switch (scsi_debug_guard) {
1679 case 1:
1680 csum = ip_compute_csum(fake_storep +
1681 sector * scsi_debug_sector_size,
1682 scsi_debug_sector_size);
1683 break;
1684 case 0:
1685 csum = crc_t10dif(fake_storep +
1686 sector * scsi_debug_sector_size,
1687 scsi_debug_sector_size);
1688 csum = cpu_to_be16(csum);
1689 break;
1690 default:
1691 BUG();
1692 }
1693
1694 if (sdt[i].guard_tag != csum) {
1695 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1696 " rcvd 0x%04x, data 0x%04x\n", __func__,
1697 (unsigned long)sector,
1698 be16_to_cpu(sdt[i].guard_tag),
1699 be16_to_cpu(csum));
1700 dif_errors++;
1701 return 0x01;
1702 }
1703
Martin K. Petersen395cef02009-09-18 17:33:03 -04001704 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001705 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1706 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1707 __func__, (unsigned long)sector);
1708 dif_errors++;
1709 return 0x03;
1710 }
Martin K. Petersen395cef02009-09-18 17:33:03 -04001711
1712 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1713 be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1714 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1715 __func__, (unsigned long)sector);
1716 dif_errors++;
1717 return 0x03;
1718 }
1719
1720 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001721 }
1722
1723 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1724 sector = start_sec;
1725
1726 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1727 int len = min(psgl->length, resid);
1728
1729 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1730 memcpy(paddr, dif_storep + dif_offset(sector), len);
1731
1732 sector += len >> 3;
1733 if (sector >= sdebug_store_sectors) {
1734 /* Force wrap */
1735 tmp_sec = sector;
1736 sector = do_div(tmp_sec, sdebug_store_sectors);
1737 }
1738 resid -= len;
1739 kunmap_atomic(paddr, KM_IRQ0);
1740 }
1741
1742 dix_reads++;
1743
1744 return 0;
1745}
1746
FUJITA Tomonori19789102008-03-30 00:59:56 +09001747static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001748 unsigned int num, struct sdebug_dev_info *devip,
1749 u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001750{
1751 unsigned long iflags;
1752 int ret;
1753
1754 ret = check_device_access_params(devip, lba, num);
1755 if (ret)
1756 return ret;
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001759 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1760 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1761 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1763 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001764 /* set info field and valid bit for fixed descriptor */
1765 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1766 devip->sense_buff[0] |= 0x80; /* Valid bit */
1767 ret = OPT_MEDIUM_ERR_ADDR;
1768 devip->sense_buff[3] = (ret >> 24) & 0xff;
1769 devip->sense_buff[4] = (ret >> 16) & 0xff;
1770 devip->sense_buff[5] = (ret >> 8) & 0xff;
1771 devip->sense_buff[6] = ret & 0xff;
1772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 return check_condition_result;
1774 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001775
1776 /* DIX + T10 DIF */
1777 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001778 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001779
1780 if (prot_ret) {
1781 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1782 return illegal_condition_result;
1783 }
1784 }
1785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001787 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 read_unlock_irqrestore(&atomic_rw, iflags);
1789 return ret;
1790}
1791
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001792void dump_sector(unsigned char *buf, int len)
1793{
1794 int i, j;
1795
1796 printk(KERN_ERR ">>> Sector Dump <<<\n");
1797
1798 for (i = 0 ; i < len ; i += 16) {
1799 printk(KERN_ERR "%04d: ", i);
1800
1801 for (j = 0 ; j < 16 ; j++) {
1802 unsigned char c = buf[i+j];
1803 if (c >= 0x20 && c < 0x7e)
1804 printk(" %c ", buf[i+j]);
1805 else
1806 printk("%02x ", buf[i+j]);
1807 }
1808
1809 printk("\n");
1810 }
1811}
1812
1813static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001814 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001815{
1816 int i, j, ret;
1817 struct sd_dif_tuple *sdt;
1818 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1819 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1820 void *daddr, *paddr;
1821 sector_t tmp_sec = start_sec;
1822 sector_t sector;
1823 int ppage_offset;
1824 unsigned short csum;
1825
1826 sector = do_div(tmp_sec, sdebug_store_sectors);
1827
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001828 BUG_ON(scsi_sg_count(SCpnt) == 0);
1829 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1830
1831 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1832 ppage_offset = 0;
1833
1834 /* For each data page */
1835 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1836 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1837
1838 /* For each sector-sized chunk in data page */
1839 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1840
1841 /* If we're at the end of the current
1842 * protection page advance to the next one
1843 */
1844 if (ppage_offset >= psgl->length) {
1845 kunmap_atomic(paddr, KM_IRQ1);
1846 psgl = sg_next(psgl);
1847 BUG_ON(psgl == NULL);
1848 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1849 + psgl->offset;
1850 ppage_offset = 0;
1851 }
1852
1853 sdt = paddr + ppage_offset;
1854
1855 switch (scsi_debug_guard) {
1856 case 1:
1857 csum = ip_compute_csum(daddr,
1858 scsi_debug_sector_size);
1859 break;
1860 case 0:
1861 csum = cpu_to_be16(crc_t10dif(daddr,
1862 scsi_debug_sector_size));
1863 break;
1864 default:
1865 BUG();
1866 ret = 0;
1867 goto out;
1868 }
1869
1870 if (sdt->guard_tag != csum) {
1871 printk(KERN_ERR
1872 "%s: GUARD check failed on sector %lu " \
1873 "rcvd 0x%04x, calculated 0x%04x\n",
1874 __func__, (unsigned long)sector,
1875 be16_to_cpu(sdt->guard_tag),
1876 be16_to_cpu(csum));
1877 ret = 0x01;
1878 dump_sector(daddr, scsi_debug_sector_size);
1879 goto out;
1880 }
1881
Martin K. Petersen395cef02009-09-18 17:33:03 -04001882 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001883 be32_to_cpu(sdt->ref_tag)
1884 != (start_sec & 0xffffffff)) {
1885 printk(KERN_ERR
1886 "%s: REF check failed on sector %lu\n",
1887 __func__, (unsigned long)sector);
1888 ret = 0x03;
1889 dump_sector(daddr, scsi_debug_sector_size);
1890 goto out;
1891 }
1892
Martin K. Petersen395cef02009-09-18 17:33:03 -04001893 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1894 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1895 printk(KERN_ERR
1896 "%s: REF check failed on sector %lu\n",
1897 __func__, (unsigned long)sector);
1898 ret = 0x03;
1899 dump_sector(daddr, scsi_debug_sector_size);
1900 goto out;
1901 }
1902
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001903 /* Would be great to copy this in bigger
1904 * chunks. However, for the sake of
1905 * correctness we need to verify each sector
1906 * before writing it to "stable" storage
1907 */
1908 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1909
1910 sector++;
1911
1912 if (sector == sdebug_store_sectors)
1913 sector = 0; /* Force wrap */
1914
1915 start_sec++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001916 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001917 daddr += scsi_debug_sector_size;
1918 ppage_offset += sizeof(struct sd_dif_tuple);
1919 }
1920
1921 kunmap_atomic(daddr, KM_IRQ0);
1922 }
1923
1924 kunmap_atomic(paddr, KM_IRQ1);
1925
1926 dix_writes++;
1927
1928 return 0;
1929
1930out:
1931 dif_errors++;
1932 kunmap_atomic(daddr, KM_IRQ0);
1933 kunmap_atomic(paddr, KM_IRQ1);
1934 return ret;
1935}
1936
Martin K. Petersen44d92692009-10-15 14:45:27 -04001937static unsigned int map_state(sector_t lba, unsigned int *num)
1938{
1939 unsigned int granularity, alignment, mapped;
1940 sector_t block, next, end;
1941
1942 granularity = scsi_debug_unmap_granularity;
1943 alignment = granularity - scsi_debug_unmap_alignment;
1944 block = lba + alignment;
1945 do_div(block, granularity);
1946
1947 mapped = test_bit(block, map_storep);
1948
1949 if (mapped)
1950 next = find_next_zero_bit(map_storep, map_size, block);
1951 else
1952 next = find_next_bit(map_storep, map_size, block);
1953
1954 end = next * granularity - scsi_debug_unmap_alignment;
1955 *num = end - lba;
1956
1957 return mapped;
1958}
1959
1960static void map_region(sector_t lba, unsigned int len)
1961{
1962 unsigned int granularity, alignment;
1963 sector_t end = lba + len;
1964
1965 granularity = scsi_debug_unmap_granularity;
1966 alignment = granularity - scsi_debug_unmap_alignment;
1967
1968 while (lba < end) {
1969 sector_t block, rem;
1970
1971 block = lba + alignment;
1972 rem = do_div(block, granularity);
1973
1974 set_bit(block, map_storep);
1975
1976 lba += granularity - rem;
1977 }
1978}
1979
1980static void unmap_region(sector_t lba, unsigned int len)
1981{
1982 unsigned int granularity, alignment;
1983 sector_t end = lba + len;
1984
1985 granularity = scsi_debug_unmap_granularity;
1986 alignment = granularity - scsi_debug_unmap_alignment;
1987
1988 while (lba < end) {
1989 sector_t block, rem;
1990
1991 block = lba + alignment;
1992 rem = do_div(block, granularity);
1993
1994 if (rem == 0 && lba + granularity <= end)
1995 clear_bit(block, map_storep);
1996
1997 lba += granularity - rem;
1998 }
1999}
2000
FUJITA Tomonori19789102008-03-30 00:59:56 +09002001static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002002 unsigned int num, struct sdebug_dev_info *devip,
2003 u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004{
2005 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002006 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
FUJITA Tomonori19789102008-03-30 00:59:56 +09002008 ret = check_device_access_params(devip, lba, num);
2009 if (ret)
2010 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002012 /* DIX + T10 DIF */
2013 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002014 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002015
2016 if (prot_ret) {
2017 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2018 return illegal_condition_result;
2019 }
2020 }
2021
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002023 ret = do_device_access(SCpnt, devip, lba, num, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002024 if (scsi_debug_unmap_granularity)
2025 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002027 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002029 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002031 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04002032 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002033
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 return 0;
2035}
2036
Martin K. Petersen44d92692009-10-15 14:45:27 -04002037static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
2038 unsigned int num, struct sdebug_dev_info *devip,
2039 u32 ei_lba, unsigned int unmap)
2040{
2041 unsigned long iflags;
2042 unsigned long long i;
2043 int ret;
2044
2045 ret = check_device_access_params(devip, lba, num);
2046 if (ret)
2047 return ret;
2048
2049 write_lock_irqsave(&atomic_rw, iflags);
2050
2051 if (unmap && scsi_debug_unmap_granularity) {
2052 unmap_region(lba, num);
2053 goto out;
2054 }
2055
2056 /* Else fetch one logical block */
2057 ret = fetch_to_dev_buffer(scmd,
2058 fake_storep + (lba * scsi_debug_sector_size),
2059 scsi_debug_sector_size);
2060
2061 if (-1 == ret) {
2062 write_unlock_irqrestore(&atomic_rw, iflags);
2063 return (DID_ERROR << 16);
2064 } else if ((ret < (num * scsi_debug_sector_size)) &&
2065 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2066 printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
2067 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
2068
2069 /* Copy first sector to remaining blocks */
2070 for (i = 1 ; i < num ; i++)
2071 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2072 fake_storep + (lba * scsi_debug_sector_size),
2073 scsi_debug_sector_size);
2074
2075 if (scsi_debug_unmap_granularity)
2076 map_region(lba, num);
2077out:
2078 write_unlock_irqrestore(&atomic_rw, iflags);
2079
2080 return 0;
2081}
2082
2083struct unmap_block_desc {
2084 __be64 lba;
2085 __be32 blocks;
2086 __be32 __reserved;
2087};
2088
2089static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2090{
2091 unsigned char *buf;
2092 struct unmap_block_desc *desc;
2093 unsigned int i, payload_len, descriptors;
2094 int ret;
2095
2096 ret = check_readiness(scmd, 1, devip);
2097 if (ret)
2098 return ret;
2099
2100 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2101 BUG_ON(scsi_bufflen(scmd) != payload_len);
2102
2103 descriptors = (payload_len - 8) / 16;
2104
2105 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2106 if (!buf)
2107 return check_condition_result;
2108
2109 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2110
2111 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2112 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2113
2114 desc = (void *)&buf[8];
2115
2116 for (i = 0 ; i < descriptors ; i++) {
2117 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2118 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2119
2120 ret = check_device_access_params(devip, lba, num);
2121 if (ret)
2122 goto out;
2123
2124 unmap_region(lba, num);
2125 }
2126
2127 ret = 0;
2128
2129out:
2130 kfree(buf);
2131
2132 return ret;
2133}
2134
2135#define SDEBUG_GET_LBA_STATUS_LEN 32
2136
2137static int resp_get_lba_status(struct scsi_cmnd * scmd,
2138 struct sdebug_dev_info * devip)
2139{
2140 unsigned long long lba;
2141 unsigned int alloc_len, mapped, num;
2142 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2143 int ret;
2144
2145 ret = check_readiness(scmd, 1, devip);
2146 if (ret)
2147 return ret;
2148
2149 lba = get_unaligned_be64(&scmd->cmnd[2]);
2150 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2151
2152 if (alloc_len < 24)
2153 return 0;
2154
2155 ret = check_device_access_params(devip, lba, 1);
2156 if (ret)
2157 return ret;
2158
2159 mapped = map_state(lba, &num);
2160
2161 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2162 put_unaligned_be32(16, &arr[0]); /* Parameter Data Length */
2163 put_unaligned_be64(lba, &arr[8]); /* LBA */
2164 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2165 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2166
2167 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2168}
2169
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002170#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171
2172static int resp_report_luns(struct scsi_cmnd * scp,
2173 struct sdebug_dev_info * devip)
2174{
2175 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002176 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 unsigned char *cmd = (unsigned char *)scp->cmnd;
2178 int select_report = (int)cmd[2];
2179 struct scsi_lun *one_lun;
2180 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002181 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
2183 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002184 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2186 0);
2187 return check_condition_result;
2188 }
2189 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2190 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2191 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002192 if (1 == select_report)
2193 lun_cnt = 0;
2194 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2195 --lun_cnt;
2196 wlun = (select_report > 0) ? 1 : 0;
2197 num = lun_cnt + wlun;
2198 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2199 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2200 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2201 sizeof(struct scsi_lun)), num);
2202 if (n < num) {
2203 wlun = 0;
2204 lun_cnt = n;
2205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002207 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2208 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2209 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2210 i++, lun++) {
2211 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 if (upper)
2213 one_lun[i].scsi_lun[0] =
2214 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002215 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002217 if (wlun) {
2218 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2219 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2220 i++;
2221 }
2222 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 return fill_from_dev_buffer(scp, arr,
2224 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2225}
2226
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002227static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2228 unsigned int num, struct sdebug_dev_info *devip)
2229{
2230 int i, j, ret = -1;
2231 unsigned char *kaddr, *buf;
2232 unsigned int offset;
2233 struct scatterlist *sg;
2234 struct scsi_data_buffer *sdb = scsi_in(scp);
2235
2236 /* better not to use temporary buffer. */
2237 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2238 if (!buf)
2239 return ret;
2240
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002241 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002242
2243 offset = 0;
2244 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2245 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2246 if (!kaddr)
2247 goto out;
2248
2249 for (j = 0; j < sg->length; j++)
2250 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2251
2252 offset += sg->length;
2253 kunmap_atomic(kaddr, KM_USER0);
2254 }
2255 ret = 0;
2256out:
2257 kfree(buf);
2258
2259 return ret;
2260}
2261
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262/* When timer goes off this function is called. */
2263static void timer_intr_handler(unsigned long indx)
2264{
2265 struct sdebug_queued_cmd * sqcp;
2266 unsigned long iflags;
2267
2268 if (indx >= SCSI_DEBUG_CANQUEUE) {
2269 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2270 "large\n");
2271 return;
2272 }
2273 spin_lock_irqsave(&queued_arr_lock, iflags);
2274 sqcp = &queued_arr[(int)indx];
2275 if (! sqcp->in_use) {
2276 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2277 "interrupt\n");
2278 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2279 return;
2280 }
2281 sqcp->in_use = 0;
2282 if (sqcp->done_funct) {
2283 sqcp->a_cmnd->result = sqcp->scsi_result;
2284 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2285 }
2286 sqcp->done_funct = NULL;
2287 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2288}
2289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002291static struct sdebug_dev_info *
2292sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002293{
2294 struct sdebug_dev_info *devip;
2295
2296 devip = kzalloc(sizeof(*devip), flags);
2297 if (devip) {
2298 devip->sdbg_host = sdbg_host;
2299 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2300 }
2301 return devip;
2302}
2303
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2305{
2306 struct sdebug_host_info * sdbg_host;
2307 struct sdebug_dev_info * open_devip = NULL;
2308 struct sdebug_dev_info * devip =
2309 (struct sdebug_dev_info *)sdev->hostdata;
2310
2311 if (devip)
2312 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002313 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2314 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 printk(KERN_ERR "Host info NULL\n");
2316 return NULL;
2317 }
2318 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2319 if ((devip->used) && (devip->channel == sdev->channel) &&
2320 (devip->target == sdev->id) &&
2321 (devip->lun == sdev->lun))
2322 return devip;
2323 else {
2324 if ((!devip->used) && (!open_devip))
2325 open_devip = devip;
2326 }
2327 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002328 if (!open_devip) { /* try and make a new one */
2329 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2330 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002332 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 return NULL;
2334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002336
2337 open_devip->channel = sdev->channel;
2338 open_devip->target = sdev->id;
2339 open_devip->lun = sdev->lun;
2340 open_devip->sdbg_host = sdbg_host;
2341 open_devip->reset = 1;
2342 open_devip->used = 1;
2343 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2344 if (scsi_debug_dsense)
2345 open_devip->sense_buff[0] = 0x72;
2346 else {
2347 open_devip->sense_buff[0] = 0x70;
2348 open_devip->sense_buff[7] = 0xa;
2349 }
2350 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2351 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2352
2353 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354}
2355
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002356static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002358 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2359 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2360 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002361 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002362 return 0;
2363}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002365static int scsi_debug_slave_configure(struct scsi_device *sdp)
2366{
2367 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002368
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002370 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2371 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2372 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2373 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2374 devip = devInfoReg(sdp);
2375 if (NULL == devip)
2376 return 1; /* no resources, will be marked offline */
2377 sdp->hostdata = devip;
2378 if (sdp->host->cmd_per_lun)
2379 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2380 sdp->host->cmd_per_lun);
2381 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
2382 return 0;
2383}
2384
2385static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2386{
2387 struct sdebug_dev_info *devip =
2388 (struct sdebug_dev_info *)sdp->hostdata;
2389
2390 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2391 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2392 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2393 if (devip) {
2394 /* make this slot avaliable for re-use */
2395 devip->used = 0;
2396 sdp->hostdata = NULL;
2397 }
2398}
2399
2400/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2401static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2402{
2403 unsigned long iflags;
2404 int k;
2405 struct sdebug_queued_cmd *sqcp;
2406
2407 spin_lock_irqsave(&queued_arr_lock, iflags);
2408 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2409 sqcp = &queued_arr[k];
2410 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2411 del_timer_sync(&sqcp->cmnd_timer);
2412 sqcp->in_use = 0;
2413 sqcp->a_cmnd = NULL;
2414 break;
2415 }
2416 }
2417 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2418 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2419}
2420
2421/* Deletes (stops) timers of all queued commands */
2422static void stop_all_queued(void)
2423{
2424 unsigned long iflags;
2425 int k;
2426 struct sdebug_queued_cmd *sqcp;
2427
2428 spin_lock_irqsave(&queued_arr_lock, iflags);
2429 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2430 sqcp = &queued_arr[k];
2431 if (sqcp->in_use && sqcp->a_cmnd) {
2432 del_timer_sync(&sqcp->cmnd_timer);
2433 sqcp->in_use = 0;
2434 sqcp->a_cmnd = NULL;
2435 }
2436 }
2437 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438}
2439
2440static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2441{
2442 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2443 printk(KERN_INFO "scsi_debug: abort\n");
2444 ++num_aborts;
2445 stop_queued_cmnd(SCpnt);
2446 return SUCCESS;
2447}
2448
2449static int scsi_debug_biosparam(struct scsi_device *sdev,
2450 struct block_device * bdev, sector_t capacity, int *info)
2451{
2452 int res;
2453 unsigned char *buf;
2454
2455 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2456 printk(KERN_INFO "scsi_debug: biosparam\n");
2457 buf = scsi_bios_ptable(bdev);
2458 if (buf) {
2459 res = scsi_partsize(buf, capacity,
2460 &info[2], &info[0], &info[1]);
2461 kfree(buf);
2462 if (! res)
2463 return res;
2464 }
2465 info[0] = sdebug_heads;
2466 info[1] = sdebug_sectors_per;
2467 info[2] = sdebug_cylinders_per;
2468 return 0;
2469}
2470
2471static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2472{
2473 struct sdebug_dev_info * devip;
2474
2475 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2476 printk(KERN_INFO "scsi_debug: device_reset\n");
2477 ++num_dev_resets;
2478 if (SCpnt) {
2479 devip = devInfoReg(SCpnt->device);
2480 if (devip)
2481 devip->reset = 1;
2482 }
2483 return SUCCESS;
2484}
2485
2486static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2487{
2488 struct sdebug_host_info *sdbg_host;
2489 struct sdebug_dev_info * dev_info;
2490 struct scsi_device * sdp;
2491 struct Scsi_Host * hp;
2492
2493 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2494 printk(KERN_INFO "scsi_debug: bus_reset\n");
2495 ++num_bus_resets;
2496 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002497 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 if (sdbg_host) {
2499 list_for_each_entry(dev_info,
2500 &sdbg_host->dev_info_list,
2501 dev_list)
2502 dev_info->reset = 1;
2503 }
2504 }
2505 return SUCCESS;
2506}
2507
2508static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2509{
2510 struct sdebug_host_info * sdbg_host;
2511 struct sdebug_dev_info * dev_info;
2512
2513 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2514 printk(KERN_INFO "scsi_debug: host_reset\n");
2515 ++num_host_resets;
2516 spin_lock(&sdebug_host_list_lock);
2517 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2518 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2519 dev_list)
2520 dev_info->reset = 1;
2521 }
2522 spin_unlock(&sdebug_host_list_lock);
2523 stop_all_queued();
2524 return SUCCESS;
2525}
2526
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527/* Initializes timers in queued array */
2528static void __init init_all_queued(void)
2529{
2530 unsigned long iflags;
2531 int k;
2532 struct sdebug_queued_cmd * sqcp;
2533
2534 spin_lock_irqsave(&queued_arr_lock, iflags);
2535 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2536 sqcp = &queued_arr[k];
2537 init_timer(&sqcp->cmnd_timer);
2538 sqcp->in_use = 0;
2539 sqcp->a_cmnd = NULL;
2540 }
2541 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2542}
2543
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002544static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002545 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546{
2547 struct partition * pp;
2548 int starts[SDEBUG_MAX_PARTS + 2];
2549 int sectors_per_part, num_sectors, k;
2550 int heads_by_sects, start_sec, end_sec;
2551
2552 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002553 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 return;
2555 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2556 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2557 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2558 "partitions to %d\n", SDEBUG_MAX_PARTS);
2559 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002560 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 sectors_per_part = (num_sectors - sdebug_sectors_per)
2562 / scsi_debug_num_parts;
2563 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2564 starts[0] = sdebug_sectors_per;
2565 for (k = 1; k < scsi_debug_num_parts; ++k)
2566 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2567 * heads_by_sects;
2568 starts[scsi_debug_num_parts] = num_sectors;
2569 starts[scsi_debug_num_parts + 1] = 0;
2570
2571 ramp[510] = 0x55; /* magic partition markings */
2572 ramp[511] = 0xAA;
2573 pp = (struct partition *)(ramp + 0x1be);
2574 for (k = 0; starts[k + 1]; ++k, ++pp) {
2575 start_sec = starts[k];
2576 end_sec = starts[k + 1] - 1;
2577 pp->boot_ind = 0;
2578
2579 pp->cyl = start_sec / heads_by_sects;
2580 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2581 / sdebug_sectors_per;
2582 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2583
2584 pp->end_cyl = end_sec / heads_by_sects;
2585 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2586 / sdebug_sectors_per;
2587 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2588
2589 pp->start_sect = start_sec;
2590 pp->nr_sects = end_sec - start_sec + 1;
2591 pp->sys_ind = 0x83; /* plain Linux partition */
2592 }
2593}
2594
2595static int schedule_resp(struct scsi_cmnd * cmnd,
2596 struct sdebug_dev_info * devip,
2597 done_funct_t done, int scsi_result, int delta_jiff)
2598{
2599 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2600 if (scsi_result) {
2601 struct scsi_device * sdp = cmnd->device;
2602
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002603 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2604 "non-zero result=0x%x\n", sdp->host->host_no,
2605 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 }
2607 }
2608 if (cmnd && devip) {
2609 /* simulate autosense by this driver */
2610 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2611 memcpy(cmnd->sense_buffer, devip->sense_buff,
2612 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2613 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2614 }
2615 if (delta_jiff <= 0) {
2616 if (cmnd)
2617 cmnd->result = scsi_result;
2618 if (done)
2619 done(cmnd);
2620 return 0;
2621 } else {
2622 unsigned long iflags;
2623 int k;
2624 struct sdebug_queued_cmd * sqcp = NULL;
2625
2626 spin_lock_irqsave(&queued_arr_lock, iflags);
2627 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2628 sqcp = &queued_arr[k];
2629 if (! sqcp->in_use)
2630 break;
2631 }
2632 if (k >= SCSI_DEBUG_CANQUEUE) {
2633 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2634 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2635 return 1; /* report busy to mid level */
2636 }
2637 sqcp->in_use = 1;
2638 sqcp->a_cmnd = cmnd;
2639 sqcp->scsi_result = scsi_result;
2640 sqcp->done_funct = done;
2641 sqcp->cmnd_timer.function = timer_intr_handler;
2642 sqcp->cmnd_timer.data = k;
2643 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2644 add_timer(&sqcp->cmnd_timer);
2645 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2646 if (cmnd)
2647 cmnd->result = 0;
2648 return 0;
2649 }
2650}
Douglas Gilbert23183912006-09-16 20:30:47 -04002651/* Note: The following macros create attribute files in the
2652 /sys/module/scsi_debug/parameters directory. Unfortunately this
2653 driver is unaware of a change and cannot trigger auxiliary actions
2654 as it can when the corresponding attribute in the
2655 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2656 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002657module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2658module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2659module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2660module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2661module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002662module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002663module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2664module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2665module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2666module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2667module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2668module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2669module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2670module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002671module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2672 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002673module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002674module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2675module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2676module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2677module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002678module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2679module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002680module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
2681module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2682module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
2683module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
2685MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2686MODULE_DESCRIPTION("SCSI debug adapter driver");
2687MODULE_LICENSE("GPL");
2688MODULE_VERSION(SCSI_DEBUG_VERSION);
2689
2690MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2691MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002692MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2693MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002694MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002695MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002696MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2697MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002699MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002700MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2702MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002703MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002704MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002705MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
2706MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
2707MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002708MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2709MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2710MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2711MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Martin K. Petersen44d92692009-10-15 14:45:27 -04002712MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)");
2713MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)");
2714MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)");
2715MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716
2717static char sdebug_info[256];
2718
2719static const char * scsi_debug_info(struct Scsi_Host * shp)
2720{
2721 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2722 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2723 scsi_debug_version_date, scsi_debug_dev_size_mb,
2724 scsi_debug_opts);
2725 return sdebug_info;
2726}
2727
2728/* scsi_debug_proc_info
2729 * Used if the driver currently has no own support for /proc/scsi
2730 */
2731static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2732 int length, int inout)
2733{
2734 int len, pos, begin;
2735 int orig_length;
2736
2737 orig_length = length;
2738
2739 if (inout == 1) {
2740 char arr[16];
2741 int minLen = length > 15 ? 15 : length;
2742
2743 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2744 return -EACCES;
2745 memcpy(arr, buffer, minLen);
2746 arr[minLen] = '\0';
2747 if (1 != sscanf(arr, "%d", &pos))
2748 return -EINVAL;
2749 scsi_debug_opts = pos;
2750 if (scsi_debug_every_nth != 0)
2751 scsi_debug_cmnd_count = 0;
2752 return length;
2753 }
2754 begin = 0;
2755 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2756 "%s [%s]\n"
2757 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2758 "every_nth=%d(curr:%d)\n"
2759 "delay=%d, max_luns=%d, scsi_level=%d\n"
2760 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2761 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002762 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2764 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2765 scsi_debug_cmnd_count, scsi_debug_delay,
2766 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002767 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2768 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002769 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 if (pos < offset) {
2771 len = 0;
2772 begin = pos;
2773 }
2774 *start = buffer + (offset - begin); /* Start of wanted data */
2775 len -= (offset - begin);
2776 if (len > length)
2777 len = length;
2778 return len;
2779}
2780
2781static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2782{
2783 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2784}
2785
2786static ssize_t sdebug_delay_store(struct device_driver * ddp,
2787 const char * buf, size_t count)
2788{
2789 int delay;
2790 char work[20];
2791
2792 if (1 == sscanf(buf, "%10s", work)) {
2793 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2794 scsi_debug_delay = delay;
2795 return count;
2796 }
2797 }
2798 return -EINVAL;
2799}
2800DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2801 sdebug_delay_store);
2802
2803static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2804{
2805 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2806}
2807
2808static ssize_t sdebug_opts_store(struct device_driver * ddp,
2809 const char * buf, size_t count)
2810{
2811 int opts;
2812 char work[20];
2813
2814 if (1 == sscanf(buf, "%10s", work)) {
2815 if (0 == strnicmp(work,"0x", 2)) {
2816 if (1 == sscanf(&work[2], "%x", &opts))
2817 goto opts_done;
2818 } else {
2819 if (1 == sscanf(work, "%d", &opts))
2820 goto opts_done;
2821 }
2822 }
2823 return -EINVAL;
2824opts_done:
2825 scsi_debug_opts = opts;
2826 scsi_debug_cmnd_count = 0;
2827 return count;
2828}
2829DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2830 sdebug_opts_store);
2831
2832static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2833{
2834 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2835}
2836static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2837 const char * buf, size_t count)
2838{
2839 int n;
2840
2841 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2842 scsi_debug_ptype = n;
2843 return count;
2844 }
2845 return -EINVAL;
2846}
2847DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2848
2849static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2850{
2851 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2852}
2853static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2854 const char * buf, size_t count)
2855{
2856 int n;
2857
2858 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2859 scsi_debug_dsense = n;
2860 return count;
2861 }
2862 return -EINVAL;
2863}
2864DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2865 sdebug_dsense_store);
2866
Douglas Gilbert23183912006-09-16 20:30:47 -04002867static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2868{
2869 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2870}
2871static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2872 const char * buf, size_t count)
2873{
2874 int n;
2875
2876 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2877 scsi_debug_fake_rw = n;
2878 return count;
2879 }
2880 return -EINVAL;
2881}
2882DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2883 sdebug_fake_rw_store);
2884
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002885static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2886{
2887 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2888}
2889static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2890 const char * buf, size_t count)
2891{
2892 int n;
2893
2894 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2895 scsi_debug_no_lun_0 = n;
2896 return count;
2897 }
2898 return -EINVAL;
2899}
2900DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2901 sdebug_no_lun_0_store);
2902
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2904{
2905 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2906}
2907static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2908 const char * buf, size_t count)
2909{
2910 int n;
2911
2912 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2913 scsi_debug_num_tgts = n;
2914 sdebug_max_tgts_luns();
2915 return count;
2916 }
2917 return -EINVAL;
2918}
2919DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2920 sdebug_num_tgts_store);
2921
2922static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2923{
2924 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2925}
2926DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2927
2928static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2929{
2930 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2931}
2932DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2933
2934static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2935{
2936 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2937}
2938static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2939 const char * buf, size_t count)
2940{
2941 int nth;
2942
2943 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2944 scsi_debug_every_nth = nth;
2945 scsi_debug_cmnd_count = 0;
2946 return count;
2947 }
2948 return -EINVAL;
2949}
2950DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2951 sdebug_every_nth_store);
2952
2953static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2954{
2955 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2956}
2957static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2958 const char * buf, size_t count)
2959{
2960 int n;
2961
2962 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2963 scsi_debug_max_luns = n;
2964 sdebug_max_tgts_luns();
2965 return count;
2966 }
2967 return -EINVAL;
2968}
2969DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2970 sdebug_max_luns_store);
2971
2972static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2973{
2974 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2975}
2976DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2977
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002978static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2979{
2980 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2981}
2982static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2983 const char * buf, size_t count)
2984{
2985 int n;
2986
2987 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2988 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002989
2990 sdebug_capacity = get_sdebug_capacity();
2991
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002992 return count;
2993 }
2994 return -EINVAL;
2995}
2996DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2997 sdebug_virtual_gb_store);
2998
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
3000{
3001 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
3002}
3003
3004static ssize_t sdebug_add_host_store(struct device_driver * ddp,
3005 const char * buf, size_t count)
3006{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003007 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003009 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 if (delta_hosts > 0) {
3012 do {
3013 sdebug_add_adapter();
3014 } while (--delta_hosts);
3015 } else if (delta_hosts < 0) {
3016 do {
3017 sdebug_remove_adapter();
3018 } while (++delta_hosts);
3019 }
3020 return count;
3021}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003022DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 sdebug_add_host_store);
3024
Douglas Gilbert23183912006-09-16 20:30:47 -04003025static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
3026 char * buf)
3027{
3028 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3029}
3030static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
3031 const char * buf, size_t count)
3032{
3033 int n;
3034
3035 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3036 scsi_debug_vpd_use_hostno = n;
3037 return count;
3038 }
3039 return -EINVAL;
3040}
3041DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
3042 sdebug_vpd_use_hostno_store);
3043
Martin K. Petersen597136a2008-06-05 00:12:59 -04003044static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3045{
3046 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3047}
3048DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3049
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003050static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3051{
3052 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3053}
3054DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3055
3056static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3057{
3058 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3059}
3060DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3061
3062static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3063{
3064 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3065}
3066DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3067
3068static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3069{
3070 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3071}
3072DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3073
Martin K. Petersen44d92692009-10-15 14:45:27 -04003074static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
3075{
3076 ssize_t count;
3077
3078 if (scsi_debug_unmap_granularity == 0)
3079 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3080 sdebug_store_sectors);
3081
3082 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3083
3084 buf[count++] = '\n';
3085 buf[count++] = 0;
3086
3087 return count;
3088}
3089DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
3090
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003091
Douglas Gilbert23183912006-09-16 20:30:47 -04003092/* Note: The following function creates attribute files in the
3093 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3094 files (over those found in the /sys/module/scsi_debug/parameters
3095 directory) is that auxiliary actions can be triggered when an attribute
3096 is changed. For example see: sdebug_add_host_store() above.
3097 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003098static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003100 int ret;
3101
3102 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3103 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
3104 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3105 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3106 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04003107 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003108 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003109 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003110 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003111 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003112 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3113 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
3114 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04003115 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
3116 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003117 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003118 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3119 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3120 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3121 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003122 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003123 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124}
3125
3126static void do_remove_driverfs_files(void)
3127{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003128 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003129 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3130 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3131 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3132 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003133 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04003134 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3135 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
3137 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
3138 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003140 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
3141 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003143 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
3145 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3146 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3147 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
3148 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3149}
3150
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003151static void pseudo_0_release(struct device *dev)
3152{
3153 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3154 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
3155}
3156
3157static struct device pseudo_primary = {
Kay Sievers71610f52008-12-03 22:41:36 +01003158 .init_name = "pseudo_0",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003159 .release = pseudo_0_release,
3160};
3161
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162static int __init scsi_debug_init(void)
3163{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003164 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 int host_to_add;
3166 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003167 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168
Martin K. Petersen597136a2008-06-05 00:12:59 -04003169 switch (scsi_debug_sector_size) {
3170 case 512:
3171 case 1024:
3172 case 2048:
3173 case 4096:
3174 break;
3175 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003176 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04003177 scsi_debug_sector_size);
3178 return -EINVAL;
3179 }
3180
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003181 switch (scsi_debug_dif) {
3182
3183 case SD_DIF_TYPE0_PROTECTION:
3184 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003185 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003186 case SD_DIF_TYPE3_PROTECTION:
3187 break;
3188
3189 default:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003190 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003191 return -EINVAL;
3192 }
3193
3194 if (scsi_debug_guard > 1) {
3195 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3196 return -EINVAL;
3197 }
3198
3199 if (scsi_debug_ato > 1) {
3200 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3201 return -EINVAL;
3202 }
3203
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003204 if (scsi_debug_physblk_exp > 15) {
3205 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3206 scsi_debug_physblk_exp);
3207 return -EINVAL;
3208 }
3209
3210 if (scsi_debug_lowest_aligned > 0x3fff) {
3211 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3212 scsi_debug_lowest_aligned);
3213 return -EINVAL;
3214 }
3215
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216 if (scsi_debug_dev_size_mb < 1)
3217 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003218 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003219 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003220 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
3222 /* play around with geometry, don't waste too much on track 0 */
3223 sdebug_heads = 8;
3224 sdebug_sectors_per = 32;
3225 if (scsi_debug_dev_size_mb >= 16)
3226 sdebug_heads = 32;
3227 else if (scsi_debug_dev_size_mb >= 256)
3228 sdebug_heads = 64;
3229 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3230 (sdebug_sectors_per * sdebug_heads);
3231 if (sdebug_cylinders_per >= 1024) {
3232 /* other LLDs do this; implies >= 1GB ram disk ... */
3233 sdebug_heads = 255;
3234 sdebug_sectors_per = 63;
3235 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3236 (sdebug_sectors_per * sdebug_heads);
3237 }
3238
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 fake_storep = vmalloc(sz);
3240 if (NULL == fake_storep) {
3241 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
3242 return -ENOMEM;
3243 }
3244 memset(fake_storep, 0, sz);
3245 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003246 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003248 if (scsi_debug_dif) {
3249 int dif_size;
3250
3251 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3252 dif_storep = vmalloc(dif_size);
3253
3254 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3255 dif_size, dif_storep);
3256
3257 if (dif_storep == NULL) {
3258 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3259 ret = -ENOMEM;
3260 goto free_vm;
3261 }
3262
3263 memset(dif_storep, 0xff, dif_size);
3264 }
3265
Martin K. Petersen44d92692009-10-15 14:45:27 -04003266 if (scsi_debug_unmap_granularity) {
3267 unsigned int map_bytes;
3268
3269 if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
3270 printk(KERN_ERR
3271 "%s: ERR: unmap_granularity < unmap_alignment\n",
3272 __func__);
3273 return -EINVAL;
3274 }
3275
3276 map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
3277 map_bytes = map_size >> 3;
3278 map_storep = vmalloc(map_bytes);
3279
3280 printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
3281 map_size);
3282
3283 if (map_storep == NULL) {
3284 printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
3285 ret = -ENOMEM;
3286 goto free_vm;
3287 }
3288
3289 memset(map_storep, 0x0, map_bytes);
3290
3291 /* Map first 1KB for partition table */
3292 if (scsi_debug_num_parts)
3293 map_region(0, 2);
3294 }
3295
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003296 ret = device_register(&pseudo_primary);
3297 if (ret < 0) {
3298 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
3299 ret);
3300 goto free_vm;
3301 }
3302 ret = bus_register(&pseudo_lld_bus);
3303 if (ret < 0) {
3304 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
3305 ret);
3306 goto dev_unreg;
3307 }
3308 ret = driver_register(&sdebug_driverfs_driver);
3309 if (ret < 0) {
3310 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
3311 ret);
3312 goto bus_unreg;
3313 }
3314 ret = do_create_driverfs_files();
3315 if (ret < 0) {
3316 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
3317 ret);
3318 goto del_files;
3319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003321 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 host_to_add = scsi_debug_add_host;
3324 scsi_debug_add_host = 0;
3325
3326 for (k = 0; k < host_to_add; k++) {
3327 if (sdebug_add_adapter()) {
3328 printk(KERN_ERR "scsi_debug_init: "
3329 "sdebug_add_adapter failed k=%d\n", k);
3330 break;
3331 }
3332 }
3333
3334 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3335 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
3336 scsi_debug_add_host);
3337 }
3338 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003339
3340del_files:
3341 do_remove_driverfs_files();
3342 driver_unregister(&sdebug_driverfs_driver);
3343bus_unreg:
3344 bus_unregister(&pseudo_lld_bus);
3345dev_unreg:
3346 device_unregister(&pseudo_primary);
3347free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003348 if (map_storep)
3349 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003350 if (dif_storep)
3351 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003352 vfree(fake_storep);
3353
3354 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355}
3356
3357static void __exit scsi_debug_exit(void)
3358{
3359 int k = scsi_debug_add_host;
3360
3361 stop_all_queued();
3362 for (; k; k--)
3363 sdebug_remove_adapter();
3364 do_remove_driverfs_files();
3365 driver_unregister(&sdebug_driverfs_driver);
3366 bus_unregister(&pseudo_lld_bus);
3367 device_unregister(&pseudo_primary);
3368
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003369 if (dif_storep)
3370 vfree(dif_storep);
3371
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 vfree(fake_storep);
3373}
3374
3375device_initcall(scsi_debug_init);
3376module_exit(scsi_debug_exit);
3377
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378static void sdebug_release_adapter(struct device * dev)
3379{
3380 struct sdebug_host_info *sdbg_host;
3381
3382 sdbg_host = to_sdebug_host(dev);
3383 kfree(sdbg_host);
3384}
3385
3386static int sdebug_add_adapter(void)
3387{
3388 int k, devs_per_host;
3389 int error = 0;
3390 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003391 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003393 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 if (NULL == sdbg_host) {
3395 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003396 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 return -ENOMEM;
3398 }
3399
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3401
3402 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3403 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003404 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3405 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003407 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 error = -ENOMEM;
3409 goto clean;
3410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 }
3412
3413 spin_lock(&sdebug_host_list_lock);
3414 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3415 spin_unlock(&sdebug_host_list_lock);
3416
3417 sdbg_host->dev.bus = &pseudo_lld_bus;
3418 sdbg_host->dev.parent = &pseudo_primary;
3419 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003420 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
3422 error = device_register(&sdbg_host->dev);
3423
3424 if (error)
3425 goto clean;
3426
3427 ++scsi_debug_add_host;
3428 return error;
3429
3430clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003431 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3432 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 list_del(&sdbg_devinfo->dev_list);
3434 kfree(sdbg_devinfo);
3435 }
3436
3437 kfree(sdbg_host);
3438 return error;
3439}
3440
3441static void sdebug_remove_adapter(void)
3442{
3443 struct sdebug_host_info * sdbg_host = NULL;
3444
3445 spin_lock(&sdebug_host_list_lock);
3446 if (!list_empty(&sdebug_host_list)) {
3447 sdbg_host = list_entry(sdebug_host_list.prev,
3448 struct sdebug_host_info, host_list);
3449 list_del(&sdbg_host->host_list);
3450 }
3451 spin_unlock(&sdebug_host_list_lock);
3452
3453 if (!sdbg_host)
3454 return;
3455
3456 device_unregister(&sdbg_host->dev);
3457 --scsi_debug_add_host;
3458}
3459
FUJITA Tomonori639db472008-03-20 11:09:19 +09003460static
3461int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
3462{
3463 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3464 int len, k;
3465 unsigned int num;
3466 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003467 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003468 int errsts = 0;
3469 int target = SCpnt->device->id;
3470 struct sdebug_dev_info *devip = NULL;
3471 int inj_recovered = 0;
3472 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003473 int inj_dif = 0;
3474 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003475 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003476 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003477
3478 scsi_set_resid(SCpnt, 0);
3479 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3480 printk(KERN_INFO "scsi_debug: cmd ");
3481 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3482 printk("%02x ", (int)cmd[k]);
3483 printk("\n");
3484 }
3485
3486 if (target == SCpnt->device->host->hostt->this_id) {
3487 printk(KERN_INFO "scsi_debug: initiator's id used as "
3488 "target!\n");
3489 return schedule_resp(SCpnt, NULL, done,
3490 DID_NO_CONNECT << 16, 0);
3491 }
3492
3493 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3494 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3495 return schedule_resp(SCpnt, NULL, done,
3496 DID_NO_CONNECT << 16, 0);
3497 devip = devInfoReg(SCpnt->device);
3498 if (NULL == devip)
3499 return schedule_resp(SCpnt, NULL, done,
3500 DID_NO_CONNECT << 16, 0);
3501
3502 if ((scsi_debug_every_nth != 0) &&
3503 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3504 scsi_debug_cmnd_count = 0;
3505 if (scsi_debug_every_nth < -1)
3506 scsi_debug_every_nth = -1;
3507 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3508 return 0; /* ignore command causing timeout */
3509 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3510 inj_recovered = 1; /* to reads and writes below */
3511 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3512 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003513 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3514 inj_dif = 1; /* to reads and writes below */
3515 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3516 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003517 }
3518
3519 if (devip->wlun) {
3520 switch (*cmd) {
3521 case INQUIRY:
3522 case REQUEST_SENSE:
3523 case TEST_UNIT_READY:
3524 case REPORT_LUNS:
3525 break; /* only allowable wlun commands */
3526 default:
3527 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3528 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3529 "not supported for wlun\n", *cmd);
3530 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3531 INVALID_OPCODE, 0);
3532 errsts = check_condition_result;
3533 return schedule_resp(SCpnt, devip, done, errsts,
3534 0);
3535 }
3536 }
3537
3538 switch (*cmd) {
3539 case INQUIRY: /* mandatory, ignore unit attention */
3540 delay_override = 1;
3541 errsts = resp_inquiry(SCpnt, target, devip);
3542 break;
3543 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3544 delay_override = 1;
3545 errsts = resp_requests(SCpnt, devip);
3546 break;
3547 case REZERO_UNIT: /* actually this is REWIND for SSC */
3548 case START_STOP:
3549 errsts = resp_start_stop(SCpnt, devip);
3550 break;
3551 case ALLOW_MEDIUM_REMOVAL:
3552 errsts = check_readiness(SCpnt, 1, devip);
3553 if (errsts)
3554 break;
3555 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3556 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3557 cmd[4] ? "inhibited" : "enabled");
3558 break;
3559 case SEND_DIAGNOSTIC: /* mandatory */
3560 errsts = check_readiness(SCpnt, 1, devip);
3561 break;
3562 case TEST_UNIT_READY: /* mandatory */
3563 delay_override = 1;
3564 errsts = check_readiness(SCpnt, 0, devip);
3565 break;
3566 case RESERVE:
3567 errsts = check_readiness(SCpnt, 1, devip);
3568 break;
3569 case RESERVE_10:
3570 errsts = check_readiness(SCpnt, 1, devip);
3571 break;
3572 case RELEASE:
3573 errsts = check_readiness(SCpnt, 1, devip);
3574 break;
3575 case RELEASE_10:
3576 errsts = check_readiness(SCpnt, 1, devip);
3577 break;
3578 case READ_CAPACITY:
3579 errsts = resp_readcap(SCpnt, devip);
3580 break;
3581 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003582 if (cmd[1] == SAI_READ_CAPACITY_16)
3583 errsts = resp_readcap16(SCpnt, devip);
3584 else if (cmd[1] == SAI_GET_LBA_STATUS) {
3585
3586 if (scsi_debug_unmap_max_desc == 0) {
3587 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3588 INVALID_COMMAND_OPCODE, 0);
3589 errsts = check_condition_result;
3590 } else
3591 errsts = resp_get_lba_status(SCpnt, devip);
3592 } else {
FUJITA Tomonori639db472008-03-20 11:09:19 +09003593 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3594 INVALID_OPCODE, 0);
3595 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003596 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09003597 break;
3598 case MAINTENANCE_IN:
3599 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3600 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3601 INVALID_OPCODE, 0);
3602 errsts = check_condition_result;
3603 break;
3604 }
3605 errsts = resp_report_tgtpgs(SCpnt, devip);
3606 break;
3607 case READ_16:
3608 case READ_12:
3609 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003610 /* READ{10,12,16} and DIF Type 2 are natural enemies */
3611 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3612 cmd[1] & 0xe0) {
3613 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3614 INVALID_COMMAND_OPCODE, 0);
3615 errsts = check_condition_result;
3616 break;
3617 }
3618
3619 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3620 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3621 (cmd[1] & 0xe0) == 0)
3622 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3623
3624 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003625 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003626read:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003627 errsts = check_readiness(SCpnt, 0, devip);
3628 if (errsts)
3629 break;
3630 if (scsi_debug_fake_rw)
3631 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003632 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3633 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003634 if (inj_recovered && (0 == errsts)) {
3635 mk_sense_buffer(devip, RECOVERED_ERROR,
3636 THRESHOLD_EXCEEDED, 0);
3637 errsts = check_condition_result;
3638 } else if (inj_transport && (0 == errsts)) {
3639 mk_sense_buffer(devip, ABORTED_COMMAND,
3640 TRANSPORT_PROBLEM, ACK_NAK_TO);
3641 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003642 } else if (inj_dif && (0 == errsts)) {
3643 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3644 errsts = illegal_condition_result;
3645 } else if (inj_dix && (0 == errsts)) {
3646 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3647 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003648 }
3649 break;
3650 case REPORT_LUNS: /* mandatory, ignore unit attention */
3651 delay_override = 1;
3652 errsts = resp_report_luns(SCpnt, devip);
3653 break;
3654 case VERIFY: /* 10 byte SBC-2 command */
3655 errsts = check_readiness(SCpnt, 0, devip);
3656 break;
3657 case WRITE_16:
3658 case WRITE_12:
3659 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003660 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3661 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3662 cmd[1] & 0xe0) {
3663 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3664 INVALID_COMMAND_OPCODE, 0);
3665 errsts = check_condition_result;
3666 break;
3667 }
3668
3669 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3670 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3671 (cmd[1] & 0xe0) == 0)
3672 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3673
3674 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003675 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003676write:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003677 errsts = check_readiness(SCpnt, 0, devip);
3678 if (errsts)
3679 break;
3680 if (scsi_debug_fake_rw)
3681 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003682 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3683 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003684 if (inj_recovered && (0 == errsts)) {
3685 mk_sense_buffer(devip, RECOVERED_ERROR,
3686 THRESHOLD_EXCEEDED, 0);
3687 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003688 } else if (inj_dif && (0 == errsts)) {
3689 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3690 errsts = illegal_condition_result;
3691 } else if (inj_dix && (0 == errsts)) {
3692 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3693 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003694 }
3695 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003696 case WRITE_SAME_16:
3697 if (cmd[1] & 0x8)
3698 unmap = 1;
3699 /* fall through */
3700 case WRITE_SAME:
3701 errsts = check_readiness(SCpnt, 0, devip);
3702 if (errsts)
3703 break;
3704 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3705 errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
3706 break;
3707 case UNMAP:
3708 errsts = check_readiness(SCpnt, 0, devip);
3709 if (errsts)
3710 break;
3711
3712 if (scsi_debug_unmap_max_desc == 0) {
3713 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3714 INVALID_COMMAND_OPCODE, 0);
3715 errsts = check_condition_result;
3716 } else
3717 errsts = resp_unmap(SCpnt, devip);
3718 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003719 case MODE_SENSE:
3720 case MODE_SENSE_10:
3721 errsts = resp_mode_sense(SCpnt, target, devip);
3722 break;
3723 case MODE_SELECT:
3724 errsts = resp_mode_select(SCpnt, 1, devip);
3725 break;
3726 case MODE_SELECT_10:
3727 errsts = resp_mode_select(SCpnt, 0, devip);
3728 break;
3729 case LOG_SENSE:
3730 errsts = resp_log_sense(SCpnt, devip);
3731 break;
3732 case SYNCHRONIZE_CACHE:
3733 delay_override = 1;
3734 errsts = check_readiness(SCpnt, 0, devip);
3735 break;
3736 case WRITE_BUFFER:
3737 errsts = check_readiness(SCpnt, 1, devip);
3738 break;
3739 case XDWRITEREAD_10:
3740 if (!scsi_bidi_cmnd(SCpnt)) {
3741 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3742 INVALID_FIELD_IN_CDB, 0);
3743 errsts = check_condition_result;
3744 break;
3745 }
3746
3747 errsts = check_readiness(SCpnt, 0, devip);
3748 if (errsts)
3749 break;
3750 if (scsi_debug_fake_rw)
3751 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003752 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3753 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003754 if (errsts)
3755 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003756 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003757 if (errsts)
3758 break;
3759 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3760 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003761 case VARIABLE_LENGTH_CMD:
3762 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3763
3764 if ((cmd[10] & 0xe0) == 0)
3765 printk(KERN_ERR
3766 "Unprotected RD/WR to DIF device\n");
3767
3768 if (cmd[9] == READ_32) {
3769 BUG_ON(SCpnt->cmd_len < 32);
3770 goto read;
3771 }
3772
3773 if (cmd[9] == WRITE_32) {
3774 BUG_ON(SCpnt->cmd_len < 32);
3775 goto write;
3776 }
3777 }
3778
3779 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3780 INVALID_FIELD_IN_CDB, 0);
3781 errsts = check_condition_result;
3782 break;
3783
FUJITA Tomonori639db472008-03-20 11:09:19 +09003784 default:
3785 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3786 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3787 "supported\n", *cmd);
3788 errsts = check_readiness(SCpnt, 1, devip);
3789 if (errsts)
3790 break; /* Unit attention takes precedence */
3791 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3792 errsts = check_condition_result;
3793 break;
3794 }
3795 return schedule_resp(SCpnt, devip, done, errsts,
3796 (delay_override ? 0 : scsi_debug_delay));
3797}
3798
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003799static struct scsi_host_template sdebug_driver_template = {
3800 .proc_info = scsi_debug_proc_info,
3801 .proc_name = sdebug_proc_name,
3802 .name = "SCSI DEBUG",
3803 .info = scsi_debug_info,
3804 .slave_alloc = scsi_debug_slave_alloc,
3805 .slave_configure = scsi_debug_slave_configure,
3806 .slave_destroy = scsi_debug_slave_destroy,
3807 .ioctl = scsi_debug_ioctl,
3808 .queuecommand = scsi_debug_queuecommand,
3809 .eh_abort_handler = scsi_debug_abort,
3810 .eh_bus_reset_handler = scsi_debug_bus_reset,
3811 .eh_device_reset_handler = scsi_debug_device_reset,
3812 .eh_host_reset_handler = scsi_debug_host_reset,
3813 .bios_param = scsi_debug_biosparam,
3814 .can_queue = SCSI_DEBUG_CANQUEUE,
3815 .this_id = 7,
3816 .sg_tablesize = 256,
3817 .cmd_per_lun = 16,
3818 .max_sectors = 0xffff,
3819 .use_clustering = DISABLE_CLUSTERING,
3820 .module = THIS_MODULE,
3821};
3822
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823static int sdebug_driver_probe(struct device * dev)
3824{
3825 int error = 0;
3826 struct sdebug_host_info *sdbg_host;
3827 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003828 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829
3830 sdbg_host = to_sdebug_host(dev);
3831
3832 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3833 if (NULL == hpnt) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003834 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 error = -ENODEV;
3836 return error;
3837 }
3838
3839 sdbg_host->shost = hpnt;
3840 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3841 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3842 hpnt->max_id = scsi_debug_num_tgts + 1;
3843 else
3844 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003845 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003847 host_prot = 0;
3848
3849 switch (scsi_debug_dif) {
3850
3851 case SD_DIF_TYPE1_PROTECTION:
3852 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3853 if (scsi_debug_dix)
3854 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3855 break;
3856
3857 case SD_DIF_TYPE2_PROTECTION:
3858 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3859 if (scsi_debug_dix)
3860 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3861 break;
3862
3863 case SD_DIF_TYPE3_PROTECTION:
3864 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3865 if (scsi_debug_dix)
3866 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3867 break;
3868
3869 default:
3870 if (scsi_debug_dix)
3871 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3872 break;
3873 }
3874
3875 scsi_host_set_prot(hpnt, host_prot);
3876
3877 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3878 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3879 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3880 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3881 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3882 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3883 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3884 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3885
3886 if (scsi_debug_guard == 1)
3887 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3888 else
3889 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3890
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 error = scsi_add_host(hpnt, &sdbg_host->dev);
3892 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003893 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 error = -ENODEV;
3895 scsi_host_put(hpnt);
3896 } else
3897 scsi_scan_host(hpnt);
3898
3899
3900 return error;
3901}
3902
3903static int sdebug_driver_remove(struct device * dev)
3904{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003906 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
3908 sdbg_host = to_sdebug_host(dev);
3909
3910 if (!sdbg_host) {
3911 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003912 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 return -ENODEV;
3914 }
3915
3916 scsi_remove_host(sdbg_host->shost);
3917
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003918 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3919 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 list_del(&sdbg_devinfo->dev_list);
3921 kfree(sdbg_devinfo);
3922 }
3923
3924 scsi_host_put(sdbg_host->shost);
3925 return 0;
3926}
3927
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003928static int pseudo_lld_bus_match(struct device *dev,
3929 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003931 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003933
3934static struct bus_type pseudo_lld_bus = {
3935 .name = "pseudo",
3936 .match = pseudo_lld_bus_match,
3937 .probe = sdebug_driver_probe,
3938 .remove = sdebug_driver_remove,
3939};