blob: 0b575c8710075e48c183547ac0dfd42eda6adb1e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
15 * For documentation see http://www.torque.net/sg/sdebug26.html
16 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/genhd.h>
36#include <linux/fs.h>
37#include <linux/init.h>
38#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/vmalloc.h>
40#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020041#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050043#include <linux/crc-t10dif.h>
44
45#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090046
Martin K. Petersen44d92692009-10-15 14:45:27 -040047#include <asm/unaligned.h>
48
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090049#include <scsi/scsi.h>
50#include <scsi/scsi_cmnd.h>
51#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <scsi/scsi_host.h>
53#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090054#include <scsi/scsi_eh.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040055#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Martin K. Petersenc6a44282009-01-04 03:08:19 -050057#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050060#define SCSI_DEBUG_VERSION "1.81"
61static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050063/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040064#define NO_ADDITIONAL_SENSE 0x0
65#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040067#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#define INVALID_OPCODE 0x20
69#define ADDR_OUT_OF_RANGE 0x21
Martin K. Petersen395cef02009-09-18 17:33:03 -040070#define INVALID_COMMAND_OPCODE 0x20
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040072#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define POWERON_RESET 0x29
74#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050075#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040076#define THRESHOLD_EXCEEDED 0x5d
77#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050079/* Additional Sense Code Qualifier (ASCQ) */
80#define ACK_NAK_TO 0x3
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
83
84/* Default values for driver parameters */
85#define DEF_NUM_HOST 1
86#define DEF_NUM_TGTS 1
87#define DEF_MAX_LUNS 1
88/* With these defaults, this driver will make 1 host with 1 target
89 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
90 */
91#define DEF_DELAY 1
92#define DEF_DEV_SIZE_MB 8
93#define DEF_EVERY_NTH 0
94#define DEF_NUM_PARTS 0
95#define DEF_OPTS 0
96#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
97#define DEF_PTYPE 0
98#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040099#define DEF_NO_LUN_0 0
100#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -0400101#define DEF_FAKE_RW 0
102#define DEF_VPD_USE_HOSTNO 1
Martin K. Petersen597136a2008-06-05 00:12:59 -0400103#define DEF_SECTOR_SIZE 512
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500104#define DEF_DIX 0
105#define DEF_DIF 0
106#define DEF_GUARD 0
107#define DEF_ATO 1
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400108#define DEF_PHYSBLK_EXP 0
109#define DEF_LOWEST_ALIGNED 0
Martin K. Petersen44d92692009-10-15 14:45:27 -0400110#define DEF_UNMAP_MAX_BLOCKS 0
111#define DEF_UNMAP_MAX_DESC 0
112#define DEF_UNMAP_GRANULARITY 0
113#define DEF_UNMAP_ALIGNMENT 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115/* bit mask values for scsi_debug_opts */
116#define SCSI_DEBUG_OPT_NOISE 1
117#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
118#define SCSI_DEBUG_OPT_TIMEOUT 4
119#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500120#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500121#define SCSI_DEBUG_OPT_DIF_ERR 32
122#define SCSI_DEBUG_OPT_DIX_ERR 64
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123/* When "every_nth" > 0 then modulo "every_nth" commands:
124 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
125 * - a RECOVERED_ERROR is simulated on successful read and write
126 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500127 * - a TRANSPORT_ERROR is simulated on successful read and write
128 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 *
130 * When "every_nth" < 0 then after "- every_nth" commands:
131 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
132 * - a RECOVERED_ERROR is simulated on successful read and write
133 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500134 * - a TRANSPORT_ERROR is simulated on successful read and write
135 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 * This will continue until some other action occurs (e.g. the user
137 * writing a new value (other than -1 or 1) to every_nth via sysfs).
138 */
139
140/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
141 * sector on read commands: */
142#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
143
144/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
145 * or "peripheral device" addressing (value 0) */
146#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400147#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149static int scsi_debug_add_host = DEF_NUM_HOST;
150static int scsi_debug_delay = DEF_DELAY;
151static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
152static int scsi_debug_every_nth = DEF_EVERY_NTH;
153static int scsi_debug_max_luns = DEF_MAX_LUNS;
154static int scsi_debug_num_parts = DEF_NUM_PARTS;
155static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
156static int scsi_debug_opts = DEF_OPTS;
157static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
158static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
159static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400160static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
161static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400162static int scsi_debug_fake_rw = DEF_FAKE_RW;
163static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400164static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500165static int scsi_debug_dix = DEF_DIX;
166static int scsi_debug_dif = DEF_DIF;
167static int scsi_debug_guard = DEF_GUARD;
168static int scsi_debug_ato = DEF_ATO;
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400169static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
170static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400171static int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
172static int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
173static int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY;
174static int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
176static int scsi_debug_cmnd_count = 0;
177
178#define DEV_READONLY(TGT) (0)
179#define DEV_REMOVEABLE(TGT) (0)
180
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400181static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182static sector_t sdebug_capacity; /* in sectors */
183
184/* old BIOS stuff, kernel may get rid of them but some mode sense pages
185 may still need them */
186static int sdebug_heads; /* heads per disk */
187static int sdebug_cylinders_per; /* cylinders per surface */
188static int sdebug_sectors_per; /* sectors per cylinder */
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#define SDEBUG_MAX_PARTS 4
191
192#define SDEBUG_SENSE_LEN 32
193
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900194#define SCSI_DEBUG_CANQUEUE 255
Martin K. Petersen395cef02009-09-18 17:33:03 -0400195#define SCSI_DEBUG_MAX_CMD_LEN 32
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197struct sdebug_dev_info {
198 struct list_head dev_list;
199 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
200 unsigned int channel;
201 unsigned int target;
202 unsigned int lun;
203 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400204 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400206 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 char used;
208};
209
210struct sdebug_host_info {
211 struct list_head host_list;
212 struct Scsi_Host *shost;
213 struct device dev;
214 struct list_head dev_info_list;
215};
216
217#define to_sdebug_host(d) \
218 container_of(d, struct sdebug_host_info, dev)
219
220static LIST_HEAD(sdebug_host_list);
221static DEFINE_SPINLOCK(sdebug_host_list_lock);
222
223typedef void (* done_funct_t) (struct scsi_cmnd *);
224
225struct sdebug_queued_cmd {
226 int in_use;
227 struct timer_list cmnd_timer;
228 done_funct_t done_funct;
229 struct scsi_cmnd * a_cmnd;
230 int scsi_result;
231};
232static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234static unsigned char * fake_storep; /* ramdisk storage */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500235static unsigned char *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400236static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Martin K. Petersen44d92692009-10-15 14:45:27 -0400238static unsigned long map_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239static int num_aborts = 0;
240static int num_dev_resets = 0;
241static int num_bus_resets = 0;
242static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500243static int dix_writes;
244static int dix_reads;
245static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
247static DEFINE_SPINLOCK(queued_arr_lock);
248static DEFINE_RWLOCK(atomic_rw);
249
250static char sdebug_proc_name[] = "scsi_debug";
251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252static struct bus_type pseudo_lld_bus;
253
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500254static inline sector_t dif_offset(sector_t sector)
255{
256 return sector << 3;
257}
258
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259static struct device_driver sdebug_driverfs_driver = {
260 .name = sdebug_proc_name,
261 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262};
263
264static const int check_condition_result =
265 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
266
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500267static const int illegal_condition_result =
268 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
269
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400270static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
271 0, 0, 0x2, 0x4b};
272static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
273 0, 0, 0x0, 0x0};
274
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275static int sdebug_add_adapter(void);
276static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900278static void sdebug_max_tgts_luns(void)
279{
280 struct sdebug_host_info *sdbg_host;
281 struct Scsi_Host *hpnt;
282
283 spin_lock(&sdebug_host_list_lock);
284 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
285 hpnt = sdbg_host->shost;
286 if ((hpnt->this_id >= 0) &&
287 (scsi_debug_num_tgts > hpnt->this_id))
288 hpnt->max_id = scsi_debug_num_tgts + 1;
289 else
290 hpnt->max_id = scsi_debug_num_tgts;
291 /* scsi_debug_max_luns; */
292 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
293 }
294 spin_unlock(&sdebug_host_list_lock);
295}
296
297static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
298 int asc, int asq)
299{
300 unsigned char *sbuff;
301
302 sbuff = devip->sense_buff;
303 memset(sbuff, 0, SDEBUG_SENSE_LEN);
304
305 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
306
307 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
308 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
309 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
310}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900312static void get_data_transfer_info(unsigned char *cmd,
Martin K. Petersen395cef02009-09-18 17:33:03 -0400313 unsigned long long *lba, unsigned int *num,
314 u32 *ei_lba)
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900315{
Martin K. Petersen395cef02009-09-18 17:33:03 -0400316 *ei_lba = 0;
317
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900318 switch (*cmd) {
Martin K. Petersen395cef02009-09-18 17:33:03 -0400319 case VARIABLE_LENGTH_CMD:
320 *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
321 (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
322 (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
323 (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
324
325 *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
326 (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
327
328 *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
329 (u32)cmd[28] << 24;
330 break;
331
Martin K. Petersen44d92692009-10-15 14:45:27 -0400332 case WRITE_SAME_16:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900333 case WRITE_16:
334 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900335 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
336 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
337 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
338 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
339
340 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
341 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900342 break;
343 case WRITE_12:
344 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900345 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
346 (u32)cmd[2] << 24;
347
348 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
349 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900350 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -0400351 case WRITE_SAME:
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900352 case WRITE_10:
353 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900354 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900355 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
356 (u32)cmd[2] << 24;
357
358 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900359 break;
360 case WRITE_6:
361 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900362 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
363 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900364 *num = (0 == cmd[4]) ? 256 : cmd[4];
365 break;
366 default:
367 break;
368 }
369}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
372{
373 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
374 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
375 }
376 return -EINVAL;
377 /* return -ENOTTY; // correct return but upsets fdisk */
378}
379
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400380static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
381 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382{
383 if (devip->reset) {
384 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
385 printk(KERN_INFO "scsi_debug: Reporting Unit "
386 "attention: power on reset\n");
387 devip->reset = 0;
388 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
389 return check_condition_result;
390 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400391 if ((0 == reset_only) && devip->stopped) {
392 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
393 printk(KERN_INFO "scsi_debug: Reporting Not "
394 "ready: initializing command required\n");
395 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
396 0x2);
397 return check_condition_result;
398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 return 0;
400}
401
402/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900403static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 int arr_len)
405{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900406 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900407 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900409 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900411 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900413
414 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
415 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900416 if (sdb->resid)
417 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400418 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900419 sdb->resid = scsi_bufflen(scp) - act_len;
420
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 return 0;
422}
423
424/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900425static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
426 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900428 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900430 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900432
433 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
435
436
437static const char * inq_vendor_id = "Linux ";
438static const char * inq_product_id = "scsi_debug ";
439static const char * inq_product_rev = "0004";
440
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200441static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
442 int target_dev_id, int dev_id_num,
443 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400444 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400446 int num, port_a;
447 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400449 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 /* T10 vendor identifier field format (faked) */
451 arr[0] = 0x2; /* ASCII */
452 arr[1] = 0x1;
453 arr[2] = 0x0;
454 memcpy(&arr[4], inq_vendor_id, 8);
455 memcpy(&arr[12], inq_product_id, 16);
456 memcpy(&arr[28], dev_id_str, dev_id_str_len);
457 num = 8 + 16 + dev_id_str_len;
458 arr[3] = num;
459 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400460 if (dev_id_num >= 0) {
461 /* NAA-5, Logical unit identifier (binary) */
462 arr[num++] = 0x1; /* binary (not necessarily sas) */
463 arr[num++] = 0x3; /* PIV=0, lu, naa */
464 arr[num++] = 0x0;
465 arr[num++] = 0x8;
466 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
467 arr[num++] = 0x33;
468 arr[num++] = 0x33;
469 arr[num++] = 0x30;
470 arr[num++] = (dev_id_num >> 24);
471 arr[num++] = (dev_id_num >> 16) & 0xff;
472 arr[num++] = (dev_id_num >> 8) & 0xff;
473 arr[num++] = dev_id_num & 0xff;
474 /* Target relative port number */
475 arr[num++] = 0x61; /* proto=sas, binary */
476 arr[num++] = 0x94; /* PIV=1, target port, rel port */
477 arr[num++] = 0x0; /* reserved */
478 arr[num++] = 0x4; /* length */
479 arr[num++] = 0x0; /* reserved */
480 arr[num++] = 0x0; /* reserved */
481 arr[num++] = 0x0;
482 arr[num++] = 0x1; /* relative port A */
483 }
484 /* NAA-5, Target port identifier */
485 arr[num++] = 0x61; /* proto=sas, binary */
486 arr[num++] = 0x93; /* piv=1, target port, naa */
487 arr[num++] = 0x0;
488 arr[num++] = 0x8;
489 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
490 arr[num++] = 0x22;
491 arr[num++] = 0x22;
492 arr[num++] = 0x20;
493 arr[num++] = (port_a >> 24);
494 arr[num++] = (port_a >> 16) & 0xff;
495 arr[num++] = (port_a >> 8) & 0xff;
496 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200497 /* NAA-5, Target port group identifier */
498 arr[num++] = 0x61; /* proto=sas, binary */
499 arr[num++] = 0x95; /* piv=1, target port group id */
500 arr[num++] = 0x0;
501 arr[num++] = 0x4;
502 arr[num++] = 0;
503 arr[num++] = 0;
504 arr[num++] = (port_group_id >> 8) & 0xff;
505 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400506 /* NAA-5, Target device identifier */
507 arr[num++] = 0x61; /* proto=sas, binary */
508 arr[num++] = 0xa3; /* piv=1, target device, naa */
509 arr[num++] = 0x0;
510 arr[num++] = 0x8;
511 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
512 arr[num++] = 0x22;
513 arr[num++] = 0x22;
514 arr[num++] = 0x20;
515 arr[num++] = (target_dev_id >> 24);
516 arr[num++] = (target_dev_id >> 16) & 0xff;
517 arr[num++] = (target_dev_id >> 8) & 0xff;
518 arr[num++] = target_dev_id & 0xff;
519 /* SCSI name string: Target device identifier */
520 arr[num++] = 0x63; /* proto=sas, UTF-8 */
521 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
522 arr[num++] = 0x0;
523 arr[num++] = 24;
524 memcpy(arr + num, "naa.52222220", 12);
525 num += 12;
526 snprintf(b, sizeof(b), "%08X", target_dev_id);
527 memcpy(arr + num, b, 8);
528 num += 8;
529 memset(arr + num, 0, 4);
530 num += 4;
531 return num;
532}
533
534
535static unsigned char vpd84_data[] = {
536/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
537 0x22,0x22,0x22,0x0,0xbb,0x1,
538 0x22,0x22,0x22,0x0,0xbb,0x2,
539};
540
541static int inquiry_evpd_84(unsigned char * arr)
542{
543 memcpy(arr, vpd84_data, sizeof(vpd84_data));
544 return sizeof(vpd84_data);
545}
546
547static int inquiry_evpd_85(unsigned char * arr)
548{
549 int num = 0;
550 const char * na1 = "https://www.kernel.org/config";
551 const char * na2 = "http://www.kernel.org/log";
552 int plen, olen;
553
554 arr[num++] = 0x1; /* lu, storage config */
555 arr[num++] = 0x0; /* reserved */
556 arr[num++] = 0x0;
557 olen = strlen(na1);
558 plen = olen + 1;
559 if (plen % 4)
560 plen = ((plen / 4) + 1) * 4;
561 arr[num++] = plen; /* length, null termianted, padded */
562 memcpy(arr + num, na1, olen);
563 memset(arr + num + olen, 0, plen - olen);
564 num += plen;
565
566 arr[num++] = 0x4; /* lu, logging */
567 arr[num++] = 0x0; /* reserved */
568 arr[num++] = 0x0;
569 olen = strlen(na2);
570 plen = olen + 1;
571 if (plen % 4)
572 plen = ((plen / 4) + 1) * 4;
573 arr[num++] = plen; /* length, null terminated, padded */
574 memcpy(arr + num, na2, olen);
575 memset(arr + num + olen, 0, plen - olen);
576 num += plen;
577
578 return num;
579}
580
581/* SCSI ports VPD page */
582static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
583{
584 int num = 0;
585 int port_a, port_b;
586
587 port_a = target_dev_id + 1;
588 port_b = port_a + 1;
589 arr[num++] = 0x0; /* reserved */
590 arr[num++] = 0x0; /* reserved */
591 arr[num++] = 0x0;
592 arr[num++] = 0x1; /* relative port 1 (primary) */
593 memset(arr + num, 0, 6);
594 num += 6;
595 arr[num++] = 0x0;
596 arr[num++] = 12; /* length tp descriptor */
597 /* naa-5 target port identifier (A) */
598 arr[num++] = 0x61; /* proto=sas, binary */
599 arr[num++] = 0x93; /* PIV=1, target port, NAA */
600 arr[num++] = 0x0; /* reserved */
601 arr[num++] = 0x8; /* length */
602 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
603 arr[num++] = 0x22;
604 arr[num++] = 0x22;
605 arr[num++] = 0x20;
606 arr[num++] = (port_a >> 24);
607 arr[num++] = (port_a >> 16) & 0xff;
608 arr[num++] = (port_a >> 8) & 0xff;
609 arr[num++] = port_a & 0xff;
610
611 arr[num++] = 0x0; /* reserved */
612 arr[num++] = 0x0; /* reserved */
613 arr[num++] = 0x0;
614 arr[num++] = 0x2; /* relative port 2 (secondary) */
615 memset(arr + num, 0, 6);
616 num += 6;
617 arr[num++] = 0x0;
618 arr[num++] = 12; /* length tp descriptor */
619 /* naa-5 target port identifier (B) */
620 arr[num++] = 0x61; /* proto=sas, binary */
621 arr[num++] = 0x93; /* PIV=1, target port, NAA */
622 arr[num++] = 0x0; /* reserved */
623 arr[num++] = 0x8; /* length */
624 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
625 arr[num++] = 0x22;
626 arr[num++] = 0x22;
627 arr[num++] = 0x20;
628 arr[num++] = (port_b >> 24);
629 arr[num++] = (port_b >> 16) & 0xff;
630 arr[num++] = (port_b >> 8) & 0xff;
631 arr[num++] = port_b & 0xff;
632
633 return num;
634}
635
636
637static unsigned char vpd89_data[] = {
638/* from 4th byte */ 0,0,0,0,
639'l','i','n','u','x',' ',' ',' ',
640'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
641'1','2','3','4',
6420x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6430xec,0,0,0,
6440x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6450,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6460x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6470x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6480x53,0x41,
6490x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6500x20,0x20,
6510x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6520x10,0x80,
6530,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6540x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6550x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6560,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6570x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6580x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6590,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6610,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6620,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6630x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6640,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6650xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6660,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
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,0xa5,0x51,
679};
680
681static int inquiry_evpd_89(unsigned char * arr)
682{
683 memcpy(arr, vpd89_data, sizeof(vpd89_data));
684 return sizeof(vpd89_data);
685}
686
687
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400688/* Block limits VPD page (SBC-3) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400689static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400690 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
691 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
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,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400694};
695
696static int inquiry_evpd_b0(unsigned char * arr)
697{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400698 unsigned int gran;
699
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400700 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400701 gran = 1 << scsi_debug_physblk_exp;
702 arr[2] = (gran >> 8) & 0xff;
703 arr[3] = gran & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400704 if (sdebug_store_sectors > 0x400) {
705 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
706 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
707 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
708 arr[7] = sdebug_store_sectors & 0xff;
709 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400710
711 if (scsi_debug_unmap_max_desc) {
712 unsigned int blocks;
713
714 if (scsi_debug_unmap_max_blocks)
715 blocks = scsi_debug_unmap_max_blocks;
716 else
717 blocks = 0xffffffff;
718
719 put_unaligned_be32(blocks, &arr[16]);
720 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
721 }
722
723 if (scsi_debug_unmap_alignment) {
724 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
725 arr[28] |= 0x80; /* UGAVALID */
726 }
727
728 if (scsi_debug_unmap_granularity) {
729 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
730 return 0x3c; /* Mandatory page length for thin provisioning */
731 }
732
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400733 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734}
735
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400736/* Block device characteristics VPD page (SBC-3) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600737static int inquiry_evpd_b1(unsigned char *arr)
738{
739 memset(arr, 0, 0x3c);
740 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -0400741 arr[1] = 1; /* non rotating medium (e.g. solid state) */
742 arr[2] = 0;
743 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600744
745 return 0x3c;
746}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400749#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751static int resp_inquiry(struct scsi_cmnd * scp, int target,
752 struct sdebug_dev_info * devip)
753{
754 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200755 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200757 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
759 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500760 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
761 if (! arr)
762 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400763 if (devip->wlun)
764 pq_pdt = 0x1e; /* present, wlun */
765 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
766 pq_pdt = 0x7f; /* not present, no device type */
767 else
768 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 arr[0] = pq_pdt;
770 if (0x2 & cmd[1]) { /* CMDDT bit set */
771 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
772 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200773 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return check_condition_result;
775 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200776 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400777 char lu_id_str[6];
778 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200780 port_group_id = (((host_no + 1) & 0x7f) << 8) +
781 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400782 if (0 == scsi_debug_vpd_use_hostno)
783 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400784 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
785 (devip->target * 1000) + devip->lun);
786 target_dev_id = ((host_no + 1) * 2000) +
787 (devip->target * 1000) - 3;
788 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400790 arr[1] = cmd[2]; /*sanity */
791 n = 4;
792 arr[n++] = 0x0; /* this page */
793 arr[n++] = 0x80; /* unit serial number */
794 arr[n++] = 0x83; /* device identification */
795 arr[n++] = 0x84; /* software interface ident. */
796 arr[n++] = 0x85; /* management network addresses */
797 arr[n++] = 0x86; /* extended inquiry */
798 arr[n++] = 0x87; /* mode page policy */
799 arr[n++] = 0x88; /* SCSI ports */
800 arr[n++] = 0x89; /* ATA information */
801 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600802 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400803 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400805 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400807 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400809 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200810 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
811 target_dev_id, lu_id_num,
812 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400813 } else if (0x84 == cmd[2]) { /* Software interface ident. */
814 arr[1] = cmd[2]; /*sanity */
815 arr[3] = inquiry_evpd_84(&arr[4]);
816 } else if (0x85 == cmd[2]) { /* Management network addresses */
817 arr[1] = cmd[2]; /*sanity */
818 arr[3] = inquiry_evpd_85(&arr[4]);
819 } else if (0x86 == cmd[2]) { /* extended inquiry */
820 arr[1] = cmd[2]; /*sanity */
821 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500822 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
823 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
824 else if (scsi_debug_dif)
825 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
826 else
827 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400828 arr[5] = 0x7; /* head of q, ordered + simple q's */
829 } else if (0x87 == cmd[2]) { /* mode page policy */
830 arr[1] = cmd[2]; /*sanity */
831 arr[3] = 0x8; /* number of following entries */
832 arr[4] = 0x2; /* disconnect-reconnect mp */
833 arr[6] = 0x80; /* mlus, shared */
834 arr[8] = 0x18; /* protocol specific lu */
835 arr[10] = 0x82; /* mlus, per initiator port */
836 } else if (0x88 == cmd[2]) { /* SCSI Ports */
837 arr[1] = cmd[2]; /*sanity */
838 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
839 } else if (0x89 == cmd[2]) { /* ATA information */
840 arr[1] = cmd[2]; /*sanity */
841 n = inquiry_evpd_89(&arr[4]);
842 arr[2] = (n >> 8);
843 arr[3] = (n & 0xff);
844 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
845 arr[1] = cmd[2]; /*sanity */
846 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600847 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
848 arr[1] = cmd[2]; /*sanity */
849 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 } else {
851 /* Illegal request, invalid field in cdb */
852 mk_sense_buffer(devip, ILLEGAL_REQUEST,
853 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200854 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 return check_condition_result;
856 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400857 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200858 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400859 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200860 kfree(arr);
861 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 }
863 /* drops through here for a standard inquiry */
864 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
865 arr[2] = scsi_debug_scsi_level;
866 arr[3] = 2; /* response_data_format==2 */
867 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500868 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200869 if (0 == scsi_debug_vpd_use_hostno)
870 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400871 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400873 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 memcpy(&arr[8], inq_vendor_id, 8);
875 memcpy(&arr[16], inq_product_id, 16);
876 memcpy(&arr[32], inq_product_rev, 4);
877 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400878 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
879 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
880 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400882 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400884 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400886 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200887 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200889 kfree(arr);
890 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891}
892
893static int resp_requests(struct scsi_cmnd * scp,
894 struct sdebug_dev_info * devip)
895{
896 unsigned char * sbuff;
897 unsigned char *cmd = (unsigned char *)scp->cmnd;
898 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400899 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 int len = 18;
901
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400902 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400904 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
905 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400907 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
908 if (want_dsense) {
909 arr[0] = 0x72;
910 arr[1] = 0x0; /* NO_SENSE in sense_key */
911 arr[2] = THRESHOLD_EXCEEDED;
912 arr[3] = 0xff; /* TEST set and MRIE==6 */
913 } else {
914 arr[0] = 0x70;
915 arr[2] = 0x0; /* NO_SENSE in sense_key */
916 arr[7] = 0xa; /* 18 byte sense buffer */
917 arr[12] = THRESHOLD_EXCEEDED;
918 arr[13] = 0xff; /* TEST set and MRIE==6 */
919 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400920 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400922 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
923 /* DESC bit set and sense_buff in fixed format */
924 memset(arr, 0, sizeof(arr));
925 arr[0] = 0x72;
926 arr[1] = sbuff[2]; /* sense key */
927 arr[2] = sbuff[12]; /* asc */
928 arr[3] = sbuff[13]; /* ascq */
929 len = 8;
930 }
931 }
932 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 return fill_from_dev_buffer(scp, arr, len);
934}
935
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400936static int resp_start_stop(struct scsi_cmnd * scp,
937 struct sdebug_dev_info * devip)
938{
939 unsigned char *cmd = (unsigned char *)scp->cmnd;
940 int power_cond, errsts, start;
941
942 if ((errsts = check_readiness(scp, 1, devip)))
943 return errsts;
944 power_cond = (cmd[4] & 0xf0) >> 4;
945 if (power_cond) {
946 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
947 0);
948 return check_condition_result;
949 }
950 start = cmd[4] & 1;
951 if (start == devip->stopped)
952 devip->stopped = !start;
953 return 0;
954}
955
FUJITA Tomonori28898872008-03-30 00:59:55 +0900956static sector_t get_sdebug_capacity(void)
957{
958 if (scsi_debug_virtual_gb > 0)
FUJITA Tomonori73da9c12009-04-22 17:42:25 -0700959 return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
FUJITA Tomonori28898872008-03-30 00:59:55 +0900960 else
961 return sdebug_store_sectors;
962}
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964#define SDEBUG_READCAP_ARR_SZ 8
965static int resp_readcap(struct scsi_cmnd * scp,
966 struct sdebug_dev_info * devip)
967{
968 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400969 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 int errsts;
971
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400972 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400974 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900975 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400977 if (sdebug_capacity < 0xffffffff) {
978 capac = (unsigned int)sdebug_capacity - 1;
979 arr[0] = (capac >> 24);
980 arr[1] = (capac >> 16) & 0xff;
981 arr[2] = (capac >> 8) & 0xff;
982 arr[3] = capac & 0xff;
983 } else {
984 arr[0] = 0xff;
985 arr[1] = 0xff;
986 arr[2] = 0xff;
987 arr[3] = 0xff;
988 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400989 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
990 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
992}
993
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400994#define SDEBUG_READCAP16_ARR_SZ 32
995static int resp_readcap16(struct scsi_cmnd * scp,
996 struct sdebug_dev_info * devip)
997{
998 unsigned char *cmd = (unsigned char *)scp->cmnd;
999 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1000 unsigned long long capac;
1001 int errsts, k, alloc_len;
1002
1003 if ((errsts = check_readiness(scp, 1, devip)))
1004 return errsts;
1005 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1006 + cmd[13]);
1007 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001008 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001009 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1010 capac = sdebug_capacity - 1;
1011 for (k = 0; k < 8; ++k, capac >>= 8)
1012 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001013 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1014 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1015 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1016 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001017 arr[13] = scsi_debug_physblk_exp & 0xf;
1018 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001019
1020 if (scsi_debug_unmap_granularity)
1021 arr[14] |= 0x80; /* TPE */
1022
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001023 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001024
1025 if (scsi_debug_dif) {
1026 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1027 arr[12] |= 1; /* PROT_EN */
1028 }
1029
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001030 return fill_from_dev_buffer(scp, arr,
1031 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1032}
1033
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001034#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1035
1036static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1037 struct sdebug_dev_info * devip)
1038{
1039 unsigned char *cmd = (unsigned char *)scp->cmnd;
1040 unsigned char * arr;
1041 int host_no = devip->sdbg_host->shost->host_no;
1042 int n, ret, alen, rlen;
1043 int port_group_a, port_group_b, port_a, port_b;
1044
1045 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1046 + cmd[9]);
1047
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001048 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1049 if (! arr)
1050 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001051 /*
1052 * EVPD page 0x88 states we have two ports, one
1053 * real and a fake port with no device connected.
1054 * So we create two port groups with one port each
1055 * and set the group with port B to unavailable.
1056 */
1057 port_a = 0x1; /* relative port A */
1058 port_b = 0x2; /* relative port B */
1059 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1060 (devip->channel & 0x7f);
1061 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1062 (devip->channel & 0x7f) + 0x80;
1063
1064 /*
1065 * The asymmetric access state is cycled according to the host_id.
1066 */
1067 n = 4;
1068 if (0 == scsi_debug_vpd_use_hostno) {
1069 arr[n++] = host_no % 3; /* Asymm access state */
1070 arr[n++] = 0x0F; /* claim: all states are supported */
1071 } else {
1072 arr[n++] = 0x0; /* Active/Optimized path */
1073 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1074 }
1075 arr[n++] = (port_group_a >> 8) & 0xff;
1076 arr[n++] = port_group_a & 0xff;
1077 arr[n++] = 0; /* Reserved */
1078 arr[n++] = 0; /* Status code */
1079 arr[n++] = 0; /* Vendor unique */
1080 arr[n++] = 0x1; /* One port per group */
1081 arr[n++] = 0; /* Reserved */
1082 arr[n++] = 0; /* Reserved */
1083 arr[n++] = (port_a >> 8) & 0xff;
1084 arr[n++] = port_a & 0xff;
1085 arr[n++] = 3; /* Port unavailable */
1086 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1087 arr[n++] = (port_group_b >> 8) & 0xff;
1088 arr[n++] = port_group_b & 0xff;
1089 arr[n++] = 0; /* Reserved */
1090 arr[n++] = 0; /* Status code */
1091 arr[n++] = 0; /* Vendor unique */
1092 arr[n++] = 0x1; /* One port per group */
1093 arr[n++] = 0; /* Reserved */
1094 arr[n++] = 0; /* Reserved */
1095 arr[n++] = (port_b >> 8) & 0xff;
1096 arr[n++] = port_b & 0xff;
1097
1098 rlen = n - 4;
1099 arr[0] = (rlen >> 24) & 0xff;
1100 arr[1] = (rlen >> 16) & 0xff;
1101 arr[2] = (rlen >> 8) & 0xff;
1102 arr[3] = rlen & 0xff;
1103
1104 /*
1105 * Return the smallest value of either
1106 * - The allocated length
1107 * - The constructed command length
1108 * - The maximum array size
1109 */
1110 rlen = min(alen,n);
1111 ret = fill_from_dev_buffer(scp, arr,
1112 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1113 kfree(arr);
1114 return ret;
1115}
1116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117/* <<Following mode page info copied from ST318451LW>> */
1118
1119static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1120{ /* Read-Write Error Recovery page for mode_sense */
1121 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1122 5, 0, 0xff, 0xff};
1123
1124 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1125 if (1 == pcontrol)
1126 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1127 return sizeof(err_recov_pg);
1128}
1129
1130static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1131{ /* Disconnect-Reconnect page for mode_sense */
1132 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1133 0, 0, 0, 0, 0, 0, 0, 0};
1134
1135 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1136 if (1 == pcontrol)
1137 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1138 return sizeof(disconnect_pg);
1139}
1140
1141static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1142{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001143 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1144 0, 0, 0, 0, 0, 0, 0, 0,
1145 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Martin K. Petersen597136a2008-06-05 00:12:59 -04001147 memcpy(p, format_pg, sizeof(format_pg));
1148 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1149 p[11] = sdebug_sectors_per & 0xff;
1150 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1151 p[13] = scsi_debug_sector_size & 0xff;
1152 if (DEV_REMOVEABLE(target))
1153 p[20] |= 0x20; /* should agree with INQUIRY */
1154 if (1 == pcontrol)
1155 memset(p + 2, 0, sizeof(format_pg) - 2);
1156 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157}
1158
1159static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1160{ /* Caching page for mode_sense */
1161 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1162 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1163
1164 memcpy(p, caching_pg, sizeof(caching_pg));
1165 if (1 == pcontrol)
1166 memset(p + 2, 0, sizeof(caching_pg) - 2);
1167 return sizeof(caching_pg);
1168}
1169
1170static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1171{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001172 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1173 0, 0, 0, 0};
1174 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 0, 0, 0x2, 0x4b};
1176
1177 if (scsi_debug_dsense)
1178 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001179 else
1180 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001181
1182 if (scsi_debug_ato)
1183 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1186 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001187 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1188 else if (2 == pcontrol)
1189 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 return sizeof(ctrl_m_pg);
1191}
1192
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1195{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001196 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1197 0, 0, 0x0, 0x0};
1198 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1199 0, 0, 0x0, 0x0};
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1202 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001203 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1204 else if (2 == pcontrol)
1205 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 return sizeof(iec_m_pg);
1207}
1208
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001209static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1210{ /* SAS SSP mode page - short format for mode_sense */
1211 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1212 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1213
1214 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1215 if (1 == pcontrol)
1216 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1217 return sizeof(sas_sf_m_pg);
1218}
1219
1220
1221static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1222 int target_dev_id)
1223{ /* SAS phy control and discover mode page for mode_sense */
1224 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1225 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1226 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1227 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1228 0x2, 0, 0, 0, 0, 0, 0, 0,
1229 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1230 0, 0, 0, 0, 0, 0, 0, 0,
1231 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1232 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1233 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1234 0x3, 0, 0, 0, 0, 0, 0, 0,
1235 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1236 0, 0, 0, 0, 0, 0, 0, 0,
1237 };
1238 int port_a, port_b;
1239
1240 port_a = target_dev_id + 1;
1241 port_b = port_a + 1;
1242 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1243 p[20] = (port_a >> 24);
1244 p[21] = (port_a >> 16) & 0xff;
1245 p[22] = (port_a >> 8) & 0xff;
1246 p[23] = port_a & 0xff;
1247 p[48 + 20] = (port_b >> 24);
1248 p[48 + 21] = (port_b >> 16) & 0xff;
1249 p[48 + 22] = (port_b >> 8) & 0xff;
1250 p[48 + 23] = port_b & 0xff;
1251 if (1 == pcontrol)
1252 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1253 return sizeof(sas_pcd_m_pg);
1254}
1255
1256static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1257{ /* SAS SSP shared protocol specific port mode subpage */
1258 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1259 0, 0, 0, 0, 0, 0, 0, 0,
1260 };
1261
1262 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1263 if (1 == pcontrol)
1264 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1265 return sizeof(sas_sha_m_pg);
1266}
1267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268#define SDEBUG_MAX_MSENSE_SZ 256
1269
1270static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1271 struct sdebug_dev_info * devip)
1272{
Douglas Gilbert23183912006-09-16 20:30:47 -04001273 unsigned char dbd, llbaa;
1274 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001276 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 unsigned char * ap;
1278 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1279 unsigned char *cmd = (unsigned char *)scp->cmnd;
1280
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001281 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001283 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 pcontrol = (cmd[2] & 0xc0) >> 6;
1285 pcode = cmd[2] & 0x3f;
1286 subpcode = cmd[3];
1287 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001288 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1289 if ((0 == scsi_debug_ptype) && (0 == dbd))
1290 bd_len = llbaa ? 16 : 8;
1291 else
1292 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1294 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1295 if (0x3 == pcontrol) { /* Saving values not supported */
1296 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1297 0);
1298 return check_condition_result;
1299 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001300 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1301 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001302 /* set DPOFUA bit for disks */
1303 if (0 == scsi_debug_ptype)
1304 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1305 else
1306 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 if (msense_6) {
1308 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001309 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 offset = 4;
1311 } else {
1312 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001313 if (16 == bd_len)
1314 arr[4] = 0x1; /* set LONGLBA bit */
1315 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 offset = 8;
1317 }
1318 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001319 if ((bd_len > 0) && (!sdebug_capacity))
1320 sdebug_capacity = get_sdebug_capacity();
1321
Douglas Gilbert23183912006-09-16 20:30:47 -04001322 if (8 == bd_len) {
1323 if (sdebug_capacity > 0xfffffffe) {
1324 ap[0] = 0xff;
1325 ap[1] = 0xff;
1326 ap[2] = 0xff;
1327 ap[3] = 0xff;
1328 } else {
1329 ap[0] = (sdebug_capacity >> 24) & 0xff;
1330 ap[1] = (sdebug_capacity >> 16) & 0xff;
1331 ap[2] = (sdebug_capacity >> 8) & 0xff;
1332 ap[3] = sdebug_capacity & 0xff;
1333 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001334 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1335 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001336 offset += bd_len;
1337 ap = arr + offset;
1338 } else if (16 == bd_len) {
1339 unsigned long long capac = sdebug_capacity;
1340
1341 for (k = 0; k < 8; ++k, capac >>= 8)
1342 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001343 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1344 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1345 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1346 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001347 offset += bd_len;
1348 ap = arr + offset;
1349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001351 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1352 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1354 0);
1355 return check_condition_result;
1356 }
1357 switch (pcode) {
1358 case 0x1: /* Read-Write error recovery page, direct access */
1359 len = resp_err_recov_pg(ap, pcontrol, target);
1360 offset += len;
1361 break;
1362 case 0x2: /* Disconnect-Reconnect page, all devices */
1363 len = resp_disconnect_pg(ap, pcontrol, target);
1364 offset += len;
1365 break;
1366 case 0x3: /* Format device page, direct access */
1367 len = resp_format_pg(ap, pcontrol, target);
1368 offset += len;
1369 break;
1370 case 0x8: /* Caching page, direct access */
1371 len = resp_caching_pg(ap, pcontrol, target);
1372 offset += len;
1373 break;
1374 case 0xa: /* Control Mode page, all devices */
1375 len = resp_ctrl_m_pg(ap, pcontrol, target);
1376 offset += len;
1377 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001378 case 0x19: /* if spc==1 then sas phy, control+discover */
1379 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1380 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1381 INVALID_FIELD_IN_CDB, 0);
1382 return check_condition_result;
1383 }
1384 len = 0;
1385 if ((0x0 == subpcode) || (0xff == subpcode))
1386 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1387 if ((0x1 == subpcode) || (0xff == subpcode))
1388 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1389 target_dev_id);
1390 if ((0x2 == subpcode) || (0xff == subpcode))
1391 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1392 offset += len;
1393 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 case 0x1c: /* Informational Exceptions Mode page, all devices */
1395 len = resp_iec_m_pg(ap, pcontrol, target);
1396 offset += len;
1397 break;
1398 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001399 if ((0 == subpcode) || (0xff == subpcode)) {
1400 len = resp_err_recov_pg(ap, pcontrol, target);
1401 len += resp_disconnect_pg(ap + len, pcontrol, target);
1402 len += resp_format_pg(ap + len, pcontrol, target);
1403 len += resp_caching_pg(ap + len, pcontrol, target);
1404 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1405 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1406 if (0xff == subpcode) {
1407 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1408 target, target_dev_id);
1409 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1410 }
1411 len += resp_iec_m_pg(ap + len, pcontrol, target);
1412 } else {
1413 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1414 INVALID_FIELD_IN_CDB, 0);
1415 return check_condition_result;
1416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 offset += len;
1418 break;
1419 default:
1420 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1421 0);
1422 return check_condition_result;
1423 }
1424 if (msense_6)
1425 arr[0] = offset - 1;
1426 else {
1427 arr[0] = ((offset - 2) >> 8) & 0xff;
1428 arr[1] = (offset - 2) & 0xff;
1429 }
1430 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1431}
1432
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001433#define SDEBUG_MAX_MSELECT_SZ 512
1434
1435static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1436 struct sdebug_dev_info * devip)
1437{
1438 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1439 int param_len, res, errsts, mpage;
1440 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1441 unsigned char *cmd = (unsigned char *)scp->cmnd;
1442
1443 if ((errsts = check_readiness(scp, 1, devip)))
1444 return errsts;
1445 memset(arr, 0, sizeof(arr));
1446 pf = cmd[1] & 0x10;
1447 sp = cmd[1] & 0x1;
1448 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1449 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1450 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1451 INVALID_FIELD_IN_CDB, 0);
1452 return check_condition_result;
1453 }
1454 res = fetch_to_dev_buffer(scp, arr, param_len);
1455 if (-1 == res)
1456 return (DID_ERROR << 16);
1457 else if ((res < param_len) &&
1458 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1459 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1460 " IO sent=%d bytes\n", param_len, res);
1461 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1462 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001463 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001464 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1465 INVALID_FIELD_IN_PARAM_LIST, 0);
1466 return check_condition_result;
1467 }
1468 off = bd_len + (mselect6 ? 4 : 8);
1469 mpage = arr[off] & 0x3f;
1470 ps = !!(arr[off] & 0x80);
1471 if (ps) {
1472 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1473 INVALID_FIELD_IN_PARAM_LIST, 0);
1474 return check_condition_result;
1475 }
1476 spf = !!(arr[off] & 0x40);
1477 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1478 (arr[off + 1] + 2);
1479 if ((pg_len + off) > param_len) {
1480 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1481 PARAMETER_LIST_LENGTH_ERR, 0);
1482 return check_condition_result;
1483 }
1484 switch (mpage) {
1485 case 0xa: /* Control Mode page */
1486 if (ctrl_m_pg[1] == arr[off + 1]) {
1487 memcpy(ctrl_m_pg + 2, arr + off + 2,
1488 sizeof(ctrl_m_pg) - 2);
1489 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1490 return 0;
1491 }
1492 break;
1493 case 0x1c: /* Informational Exceptions Mode page */
1494 if (iec_m_pg[1] == arr[off + 1]) {
1495 memcpy(iec_m_pg + 2, arr + off + 2,
1496 sizeof(iec_m_pg) - 2);
1497 return 0;
1498 }
1499 break;
1500 default:
1501 break;
1502 }
1503 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1504 INVALID_FIELD_IN_PARAM_LIST, 0);
1505 return check_condition_result;
1506}
1507
1508static int resp_temp_l_pg(unsigned char * arr)
1509{
1510 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1511 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1512 };
1513
1514 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1515 return sizeof(temp_l_pg);
1516}
1517
1518static int resp_ie_l_pg(unsigned char * arr)
1519{
1520 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1521 };
1522
1523 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1524 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1525 arr[4] = THRESHOLD_EXCEEDED;
1526 arr[5] = 0xff;
1527 }
1528 return sizeof(ie_l_pg);
1529}
1530
1531#define SDEBUG_MAX_LSENSE_SZ 512
1532
1533static int resp_log_sense(struct scsi_cmnd * scp,
1534 struct sdebug_dev_info * devip)
1535{
Douglas Gilbert23183912006-09-16 20:30:47 -04001536 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001537 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1538 unsigned char *cmd = (unsigned char *)scp->cmnd;
1539
1540 if ((errsts = check_readiness(scp, 1, devip)))
1541 return errsts;
1542 memset(arr, 0, sizeof(arr));
1543 ppc = cmd[1] & 0x2;
1544 sp = cmd[1] & 0x1;
1545 if (ppc || sp) {
1546 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1547 INVALID_FIELD_IN_CDB, 0);
1548 return check_condition_result;
1549 }
1550 pcontrol = (cmd[2] & 0xc0) >> 6;
1551 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001552 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001553 alloc_len = (cmd[7] << 8) + cmd[8];
1554 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001555 if (0 == subpcode) {
1556 switch (pcode) {
1557 case 0x0: /* Supported log pages log page */
1558 n = 4;
1559 arr[n++] = 0x0; /* this page */
1560 arr[n++] = 0xd; /* Temperature */
1561 arr[n++] = 0x2f; /* Informational exceptions */
1562 arr[3] = n - 4;
1563 break;
1564 case 0xd: /* Temperature log page */
1565 arr[3] = resp_temp_l_pg(arr + 4);
1566 break;
1567 case 0x2f: /* Informational exceptions log page */
1568 arr[3] = resp_ie_l_pg(arr + 4);
1569 break;
1570 default:
1571 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1572 INVALID_FIELD_IN_CDB, 0);
1573 return check_condition_result;
1574 }
1575 } else if (0xff == subpcode) {
1576 arr[0] |= 0x40;
1577 arr[1] = subpcode;
1578 switch (pcode) {
1579 case 0x0: /* Supported log pages and subpages log page */
1580 n = 4;
1581 arr[n++] = 0x0;
1582 arr[n++] = 0x0; /* 0,0 page */
1583 arr[n++] = 0x0;
1584 arr[n++] = 0xff; /* this page */
1585 arr[n++] = 0xd;
1586 arr[n++] = 0x0; /* Temperature */
1587 arr[n++] = 0x2f;
1588 arr[n++] = 0x0; /* Informational exceptions */
1589 arr[3] = n - 4;
1590 break;
1591 case 0xd: /* Temperature subpages */
1592 n = 4;
1593 arr[n++] = 0xd;
1594 arr[n++] = 0x0; /* Temperature */
1595 arr[3] = n - 4;
1596 break;
1597 case 0x2f: /* Informational exceptions subpages */
1598 n = 4;
1599 arr[n++] = 0x2f;
1600 arr[n++] = 0x0; /* Informational exceptions */
1601 arr[3] = n - 4;
1602 break;
1603 default:
1604 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1605 INVALID_FIELD_IN_CDB, 0);
1606 return check_condition_result;
1607 }
1608 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001609 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1610 INVALID_FIELD_IN_CDB, 0);
1611 return check_condition_result;
1612 }
1613 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1614 return fill_from_dev_buffer(scp, arr,
1615 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1616}
1617
FUJITA Tomonori19789102008-03-30 00:59:56 +09001618static int check_device_access_params(struct sdebug_dev_info *devi,
1619 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001621 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001622 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 return check_condition_result;
1624 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001625 /* transfer length excessive (tie in to block limits VPD page) */
1626 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001627 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001628 return check_condition_result;
1629 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001630 return 0;
1631}
1632
1633static int do_device_access(struct scsi_cmnd *scmd,
1634 struct sdebug_dev_info *devi,
1635 unsigned long long lba, unsigned int num, int write)
1636{
1637 int ret;
1638 unsigned int block, rest = 0;
1639 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1640
1641 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1642
1643 block = do_div(lba, sdebug_store_sectors);
1644 if (block + num > sdebug_store_sectors)
1645 rest = block + num - sdebug_store_sectors;
1646
Martin K. Petersen597136a2008-06-05 00:12:59 -04001647 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1648 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001649 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001650 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001651
1652 return ret;
1653}
1654
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001655static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001656 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001657{
1658 unsigned int i, resid;
1659 struct scatterlist *psgl;
1660 struct sd_dif_tuple *sdt;
1661 sector_t sector;
1662 sector_t tmp_sec = start_sec;
1663 void *paddr;
1664
1665 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1666
1667 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1668
1669 for (i = 0 ; i < sectors ; i++) {
1670 u16 csum;
1671
1672 if (sdt[i].app_tag == 0xffff)
1673 continue;
1674
1675 sector = start_sec + i;
1676
1677 switch (scsi_debug_guard) {
1678 case 1:
1679 csum = ip_compute_csum(fake_storep +
1680 sector * scsi_debug_sector_size,
1681 scsi_debug_sector_size);
1682 break;
1683 case 0:
1684 csum = crc_t10dif(fake_storep +
1685 sector * scsi_debug_sector_size,
1686 scsi_debug_sector_size);
1687 csum = cpu_to_be16(csum);
1688 break;
1689 default:
1690 BUG();
1691 }
1692
1693 if (sdt[i].guard_tag != csum) {
1694 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1695 " rcvd 0x%04x, data 0x%04x\n", __func__,
1696 (unsigned long)sector,
1697 be16_to_cpu(sdt[i].guard_tag),
1698 be16_to_cpu(csum));
1699 dif_errors++;
1700 return 0x01;
1701 }
1702
Martin K. Petersen395cef02009-09-18 17:33:03 -04001703 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001704 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1705 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1706 __func__, (unsigned long)sector);
1707 dif_errors++;
1708 return 0x03;
1709 }
Martin K. Petersen395cef02009-09-18 17:33:03 -04001710
1711 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1712 be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1713 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1714 __func__, (unsigned long)sector);
1715 dif_errors++;
1716 return 0x03;
1717 }
1718
1719 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001720 }
1721
1722 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1723 sector = start_sec;
1724
1725 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1726 int len = min(psgl->length, resid);
1727
1728 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1729 memcpy(paddr, dif_storep + dif_offset(sector), len);
1730
1731 sector += len >> 3;
1732 if (sector >= sdebug_store_sectors) {
1733 /* Force wrap */
1734 tmp_sec = sector;
1735 sector = do_div(tmp_sec, sdebug_store_sectors);
1736 }
1737 resid -= len;
1738 kunmap_atomic(paddr, KM_IRQ0);
1739 }
1740
1741 dix_reads++;
1742
1743 return 0;
1744}
1745
FUJITA Tomonori19789102008-03-30 00:59:56 +09001746static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001747 unsigned int num, struct sdebug_dev_info *devip,
1748 u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001749{
1750 unsigned long iflags;
1751 int ret;
1752
1753 ret = check_device_access_params(devip, lba, num);
1754 if (ret)
1755 return ret;
1756
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001758 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1759 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1760 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1762 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001763 /* set info field and valid bit for fixed descriptor */
1764 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1765 devip->sense_buff[0] |= 0x80; /* Valid bit */
1766 ret = OPT_MEDIUM_ERR_ADDR;
1767 devip->sense_buff[3] = (ret >> 24) & 0xff;
1768 devip->sense_buff[4] = (ret >> 16) & 0xff;
1769 devip->sense_buff[5] = (ret >> 8) & 0xff;
1770 devip->sense_buff[6] = ret & 0xff;
1771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 return check_condition_result;
1773 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001774
1775 /* DIX + T10 DIF */
1776 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001777 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001778
1779 if (prot_ret) {
1780 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1781 return illegal_condition_result;
1782 }
1783 }
1784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001786 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 read_unlock_irqrestore(&atomic_rw, iflags);
1788 return ret;
1789}
1790
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001791void dump_sector(unsigned char *buf, int len)
1792{
1793 int i, j;
1794
1795 printk(KERN_ERR ">>> Sector Dump <<<\n");
1796
1797 for (i = 0 ; i < len ; i += 16) {
1798 printk(KERN_ERR "%04d: ", i);
1799
1800 for (j = 0 ; j < 16 ; j++) {
1801 unsigned char c = buf[i+j];
1802 if (c >= 0x20 && c < 0x7e)
1803 printk(" %c ", buf[i+j]);
1804 else
1805 printk("%02x ", buf[i+j]);
1806 }
1807
1808 printk("\n");
1809 }
1810}
1811
1812static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001813 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001814{
1815 int i, j, ret;
1816 struct sd_dif_tuple *sdt;
1817 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1818 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1819 void *daddr, *paddr;
1820 sector_t tmp_sec = start_sec;
1821 sector_t sector;
1822 int ppage_offset;
1823 unsigned short csum;
1824
1825 sector = do_div(tmp_sec, sdebug_store_sectors);
1826
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001827 BUG_ON(scsi_sg_count(SCpnt) == 0);
1828 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1829
1830 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1831 ppage_offset = 0;
1832
1833 /* For each data page */
1834 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1835 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1836
1837 /* For each sector-sized chunk in data page */
1838 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1839
1840 /* If we're at the end of the current
1841 * protection page advance to the next one
1842 */
1843 if (ppage_offset >= psgl->length) {
1844 kunmap_atomic(paddr, KM_IRQ1);
1845 psgl = sg_next(psgl);
1846 BUG_ON(psgl == NULL);
1847 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1848 + psgl->offset;
1849 ppage_offset = 0;
1850 }
1851
1852 sdt = paddr + ppage_offset;
1853
1854 switch (scsi_debug_guard) {
1855 case 1:
1856 csum = ip_compute_csum(daddr,
1857 scsi_debug_sector_size);
1858 break;
1859 case 0:
1860 csum = cpu_to_be16(crc_t10dif(daddr,
1861 scsi_debug_sector_size));
1862 break;
1863 default:
1864 BUG();
1865 ret = 0;
1866 goto out;
1867 }
1868
1869 if (sdt->guard_tag != csum) {
1870 printk(KERN_ERR
1871 "%s: GUARD check failed on sector %lu " \
1872 "rcvd 0x%04x, calculated 0x%04x\n",
1873 __func__, (unsigned long)sector,
1874 be16_to_cpu(sdt->guard_tag),
1875 be16_to_cpu(csum));
1876 ret = 0x01;
1877 dump_sector(daddr, scsi_debug_sector_size);
1878 goto out;
1879 }
1880
Martin K. Petersen395cef02009-09-18 17:33:03 -04001881 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001882 be32_to_cpu(sdt->ref_tag)
1883 != (start_sec & 0xffffffff)) {
1884 printk(KERN_ERR
1885 "%s: REF check failed on sector %lu\n",
1886 __func__, (unsigned long)sector);
1887 ret = 0x03;
1888 dump_sector(daddr, scsi_debug_sector_size);
1889 goto out;
1890 }
1891
Martin K. Petersen395cef02009-09-18 17:33:03 -04001892 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1893 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1894 printk(KERN_ERR
1895 "%s: REF check failed on sector %lu\n",
1896 __func__, (unsigned long)sector);
1897 ret = 0x03;
1898 dump_sector(daddr, scsi_debug_sector_size);
1899 goto out;
1900 }
1901
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001902 /* Would be great to copy this in bigger
1903 * chunks. However, for the sake of
1904 * correctness we need to verify each sector
1905 * before writing it to "stable" storage
1906 */
1907 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1908
1909 sector++;
1910
1911 if (sector == sdebug_store_sectors)
1912 sector = 0; /* Force wrap */
1913
1914 start_sec++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001915 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001916 daddr += scsi_debug_sector_size;
1917 ppage_offset += sizeof(struct sd_dif_tuple);
1918 }
1919
1920 kunmap_atomic(daddr, KM_IRQ0);
1921 }
1922
1923 kunmap_atomic(paddr, KM_IRQ1);
1924
1925 dix_writes++;
1926
1927 return 0;
1928
1929out:
1930 dif_errors++;
1931 kunmap_atomic(daddr, KM_IRQ0);
1932 kunmap_atomic(paddr, KM_IRQ1);
1933 return ret;
1934}
1935
Martin K. Petersen44d92692009-10-15 14:45:27 -04001936static unsigned int map_state(sector_t lba, unsigned int *num)
1937{
1938 unsigned int granularity, alignment, mapped;
1939 sector_t block, next, end;
1940
1941 granularity = scsi_debug_unmap_granularity;
1942 alignment = granularity - scsi_debug_unmap_alignment;
1943 block = lba + alignment;
1944 do_div(block, granularity);
1945
1946 mapped = test_bit(block, map_storep);
1947
1948 if (mapped)
1949 next = find_next_zero_bit(map_storep, map_size, block);
1950 else
1951 next = find_next_bit(map_storep, map_size, block);
1952
1953 end = next * granularity - scsi_debug_unmap_alignment;
1954 *num = end - lba;
1955
1956 return mapped;
1957}
1958
1959static void map_region(sector_t lba, unsigned int len)
1960{
1961 unsigned int granularity, alignment;
1962 sector_t end = lba + len;
1963
1964 granularity = scsi_debug_unmap_granularity;
1965 alignment = granularity - scsi_debug_unmap_alignment;
1966
1967 while (lba < end) {
1968 sector_t block, rem;
1969
1970 block = lba + alignment;
1971 rem = do_div(block, granularity);
1972
1973 set_bit(block, map_storep);
1974
1975 lba += granularity - rem;
1976 }
1977}
1978
1979static void unmap_region(sector_t lba, unsigned int len)
1980{
1981 unsigned int granularity, alignment;
1982 sector_t end = lba + len;
1983
1984 granularity = scsi_debug_unmap_granularity;
1985 alignment = granularity - scsi_debug_unmap_alignment;
1986
1987 while (lba < end) {
1988 sector_t block, rem;
1989
1990 block = lba + alignment;
1991 rem = do_div(block, granularity);
1992
1993 if (rem == 0 && lba + granularity <= end)
1994 clear_bit(block, map_storep);
1995
1996 lba += granularity - rem;
1997 }
1998}
1999
FUJITA Tomonori19789102008-03-30 00:59:56 +09002000static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002001 unsigned int num, struct sdebug_dev_info *devip,
2002 u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003{
2004 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002005 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
FUJITA Tomonori19789102008-03-30 00:59:56 +09002007 ret = check_device_access_params(devip, lba, num);
2008 if (ret)
2009 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002011 /* DIX + T10 DIF */
2012 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002013 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002014
2015 if (prot_ret) {
2016 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2017 return illegal_condition_result;
2018 }
2019 }
2020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002022 ret = do_device_access(SCpnt, devip, lba, num, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002023 if (scsi_debug_unmap_granularity)
2024 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002026 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002028 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002030 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04002031 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002032
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 return 0;
2034}
2035
Martin K. Petersen44d92692009-10-15 14:45:27 -04002036static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
2037 unsigned int num, struct sdebug_dev_info *devip,
2038 u32 ei_lba, unsigned int unmap)
2039{
2040 unsigned long iflags;
2041 unsigned long long i;
2042 int ret;
2043
2044 ret = check_device_access_params(devip, lba, num);
2045 if (ret)
2046 return ret;
2047
2048 write_lock_irqsave(&atomic_rw, iflags);
2049
2050 if (unmap && scsi_debug_unmap_granularity) {
2051 unmap_region(lba, num);
2052 goto out;
2053 }
2054
2055 /* Else fetch one logical block */
2056 ret = fetch_to_dev_buffer(scmd,
2057 fake_storep + (lba * scsi_debug_sector_size),
2058 scsi_debug_sector_size);
2059
2060 if (-1 == ret) {
2061 write_unlock_irqrestore(&atomic_rw, iflags);
2062 return (DID_ERROR << 16);
2063 } else if ((ret < (num * scsi_debug_sector_size)) &&
2064 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2065 printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
2066 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
2067
2068 /* Copy first sector to remaining blocks */
2069 for (i = 1 ; i < num ; i++)
2070 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2071 fake_storep + (lba * scsi_debug_sector_size),
2072 scsi_debug_sector_size);
2073
2074 if (scsi_debug_unmap_granularity)
2075 map_region(lba, num);
2076out:
2077 write_unlock_irqrestore(&atomic_rw, iflags);
2078
2079 return 0;
2080}
2081
2082struct unmap_block_desc {
2083 __be64 lba;
2084 __be32 blocks;
2085 __be32 __reserved;
2086};
2087
2088static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2089{
2090 unsigned char *buf;
2091 struct unmap_block_desc *desc;
2092 unsigned int i, payload_len, descriptors;
2093 int ret;
2094
2095 ret = check_readiness(scmd, 1, devip);
2096 if (ret)
2097 return ret;
2098
2099 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2100 BUG_ON(scsi_bufflen(scmd) != payload_len);
2101
2102 descriptors = (payload_len - 8) / 16;
2103
2104 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2105 if (!buf)
2106 return check_condition_result;
2107
2108 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2109
2110 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2111 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2112
2113 desc = (void *)&buf[8];
2114
2115 for (i = 0 ; i < descriptors ; i++) {
2116 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2117 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2118
2119 ret = check_device_access_params(devip, lba, num);
2120 if (ret)
2121 goto out;
2122
2123 unmap_region(lba, num);
2124 }
2125
2126 ret = 0;
2127
2128out:
2129 kfree(buf);
2130
2131 return ret;
2132}
2133
2134#define SDEBUG_GET_LBA_STATUS_LEN 32
2135
2136static int resp_get_lba_status(struct scsi_cmnd * scmd,
2137 struct sdebug_dev_info * devip)
2138{
2139 unsigned long long lba;
2140 unsigned int alloc_len, mapped, num;
2141 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2142 int ret;
2143
2144 ret = check_readiness(scmd, 1, devip);
2145 if (ret)
2146 return ret;
2147
2148 lba = get_unaligned_be64(&scmd->cmnd[2]);
2149 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2150
2151 if (alloc_len < 24)
2152 return 0;
2153
2154 ret = check_device_access_params(devip, lba, 1);
2155 if (ret)
2156 return ret;
2157
2158 mapped = map_state(lba, &num);
2159
2160 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2161 put_unaligned_be32(16, &arr[0]); /* Parameter Data Length */
2162 put_unaligned_be64(lba, &arr[8]); /* LBA */
2163 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2164 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2165
2166 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2167}
2168
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002169#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
2171static int resp_report_luns(struct scsi_cmnd * scp,
2172 struct sdebug_dev_info * devip)
2173{
2174 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002175 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 unsigned char *cmd = (unsigned char *)scp->cmnd;
2177 int select_report = (int)cmd[2];
2178 struct scsi_lun *one_lun;
2179 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002180 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
2182 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002183 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2185 0);
2186 return check_condition_result;
2187 }
2188 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2189 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2190 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002191 if (1 == select_report)
2192 lun_cnt = 0;
2193 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2194 --lun_cnt;
2195 wlun = (select_report > 0) ? 1 : 0;
2196 num = lun_cnt + wlun;
2197 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2198 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2199 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2200 sizeof(struct scsi_lun)), num);
2201 if (n < num) {
2202 wlun = 0;
2203 lun_cnt = n;
2204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002206 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2207 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2208 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2209 i++, lun++) {
2210 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 if (upper)
2212 one_lun[i].scsi_lun[0] =
2213 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002214 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002216 if (wlun) {
2217 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2218 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2219 i++;
2220 }
2221 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 return fill_from_dev_buffer(scp, arr,
2223 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2224}
2225
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002226static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2227 unsigned int num, struct sdebug_dev_info *devip)
2228{
2229 int i, j, ret = -1;
2230 unsigned char *kaddr, *buf;
2231 unsigned int offset;
2232 struct scatterlist *sg;
2233 struct scsi_data_buffer *sdb = scsi_in(scp);
2234
2235 /* better not to use temporary buffer. */
2236 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2237 if (!buf)
2238 return ret;
2239
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002240 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002241
2242 offset = 0;
2243 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2244 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2245 if (!kaddr)
2246 goto out;
2247
2248 for (j = 0; j < sg->length; j++)
2249 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2250
2251 offset += sg->length;
2252 kunmap_atomic(kaddr, KM_USER0);
2253 }
2254 ret = 0;
2255out:
2256 kfree(buf);
2257
2258 return ret;
2259}
2260
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261/* When timer goes off this function is called. */
2262static void timer_intr_handler(unsigned long indx)
2263{
2264 struct sdebug_queued_cmd * sqcp;
2265 unsigned long iflags;
2266
2267 if (indx >= SCSI_DEBUG_CANQUEUE) {
2268 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2269 "large\n");
2270 return;
2271 }
2272 spin_lock_irqsave(&queued_arr_lock, iflags);
2273 sqcp = &queued_arr[(int)indx];
2274 if (! sqcp->in_use) {
2275 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2276 "interrupt\n");
2277 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2278 return;
2279 }
2280 sqcp->in_use = 0;
2281 if (sqcp->done_funct) {
2282 sqcp->a_cmnd->result = sqcp->scsi_result;
2283 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2284 }
2285 sqcp->done_funct = NULL;
2286 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2287}
2288
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002290static struct sdebug_dev_info *
2291sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002292{
2293 struct sdebug_dev_info *devip;
2294
2295 devip = kzalloc(sizeof(*devip), flags);
2296 if (devip) {
2297 devip->sdbg_host = sdbg_host;
2298 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2299 }
2300 return devip;
2301}
2302
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2304{
2305 struct sdebug_host_info * sdbg_host;
2306 struct sdebug_dev_info * open_devip = NULL;
2307 struct sdebug_dev_info * devip =
2308 (struct sdebug_dev_info *)sdev->hostdata;
2309
2310 if (devip)
2311 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002312 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2313 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 printk(KERN_ERR "Host info NULL\n");
2315 return NULL;
2316 }
2317 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2318 if ((devip->used) && (devip->channel == sdev->channel) &&
2319 (devip->target == sdev->id) &&
2320 (devip->lun == sdev->lun))
2321 return devip;
2322 else {
2323 if ((!devip->used) && (!open_devip))
2324 open_devip = devip;
2325 }
2326 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002327 if (!open_devip) { /* try and make a new one */
2328 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2329 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002331 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 return NULL;
2333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002335
2336 open_devip->channel = sdev->channel;
2337 open_devip->target = sdev->id;
2338 open_devip->lun = sdev->lun;
2339 open_devip->sdbg_host = sdbg_host;
2340 open_devip->reset = 1;
2341 open_devip->used = 1;
2342 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2343 if (scsi_debug_dsense)
2344 open_devip->sense_buff[0] = 0x72;
2345 else {
2346 open_devip->sense_buff[0] = 0x70;
2347 open_devip->sense_buff[7] = 0xa;
2348 }
2349 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2350 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2351
2352 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353}
2354
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002355static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002357 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2358 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2359 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002360 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002361 return 0;
2362}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002364static int scsi_debug_slave_configure(struct scsi_device *sdp)
2365{
2366 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002367
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002369 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2370 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2371 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2372 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2373 devip = devInfoReg(sdp);
2374 if (NULL == devip)
2375 return 1; /* no resources, will be marked offline */
2376 sdp->hostdata = devip;
2377 if (sdp->host->cmd_per_lun)
2378 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2379 sdp->host->cmd_per_lun);
2380 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
2381 return 0;
2382}
2383
2384static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2385{
2386 struct sdebug_dev_info *devip =
2387 (struct sdebug_dev_info *)sdp->hostdata;
2388
2389 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2390 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2391 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2392 if (devip) {
2393 /* make this slot avaliable for re-use */
2394 devip->used = 0;
2395 sdp->hostdata = NULL;
2396 }
2397}
2398
2399/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2400static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2401{
2402 unsigned long iflags;
2403 int k;
2404 struct sdebug_queued_cmd *sqcp;
2405
2406 spin_lock_irqsave(&queued_arr_lock, iflags);
2407 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2408 sqcp = &queued_arr[k];
2409 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2410 del_timer_sync(&sqcp->cmnd_timer);
2411 sqcp->in_use = 0;
2412 sqcp->a_cmnd = NULL;
2413 break;
2414 }
2415 }
2416 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2417 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2418}
2419
2420/* Deletes (stops) timers of all queued commands */
2421static void stop_all_queued(void)
2422{
2423 unsigned long iflags;
2424 int k;
2425 struct sdebug_queued_cmd *sqcp;
2426
2427 spin_lock_irqsave(&queued_arr_lock, iflags);
2428 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2429 sqcp = &queued_arr[k];
2430 if (sqcp->in_use && sqcp->a_cmnd) {
2431 del_timer_sync(&sqcp->cmnd_timer);
2432 sqcp->in_use = 0;
2433 sqcp->a_cmnd = NULL;
2434 }
2435 }
2436 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437}
2438
2439static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2440{
2441 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2442 printk(KERN_INFO "scsi_debug: abort\n");
2443 ++num_aborts;
2444 stop_queued_cmnd(SCpnt);
2445 return SUCCESS;
2446}
2447
2448static int scsi_debug_biosparam(struct scsi_device *sdev,
2449 struct block_device * bdev, sector_t capacity, int *info)
2450{
2451 int res;
2452 unsigned char *buf;
2453
2454 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2455 printk(KERN_INFO "scsi_debug: biosparam\n");
2456 buf = scsi_bios_ptable(bdev);
2457 if (buf) {
2458 res = scsi_partsize(buf, capacity,
2459 &info[2], &info[0], &info[1]);
2460 kfree(buf);
2461 if (! res)
2462 return res;
2463 }
2464 info[0] = sdebug_heads;
2465 info[1] = sdebug_sectors_per;
2466 info[2] = sdebug_cylinders_per;
2467 return 0;
2468}
2469
2470static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2471{
2472 struct sdebug_dev_info * devip;
2473
2474 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2475 printk(KERN_INFO "scsi_debug: device_reset\n");
2476 ++num_dev_resets;
2477 if (SCpnt) {
2478 devip = devInfoReg(SCpnt->device);
2479 if (devip)
2480 devip->reset = 1;
2481 }
2482 return SUCCESS;
2483}
2484
2485static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2486{
2487 struct sdebug_host_info *sdbg_host;
2488 struct sdebug_dev_info * dev_info;
2489 struct scsi_device * sdp;
2490 struct Scsi_Host * hp;
2491
2492 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2493 printk(KERN_INFO "scsi_debug: bus_reset\n");
2494 ++num_bus_resets;
2495 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002496 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 if (sdbg_host) {
2498 list_for_each_entry(dev_info,
2499 &sdbg_host->dev_info_list,
2500 dev_list)
2501 dev_info->reset = 1;
2502 }
2503 }
2504 return SUCCESS;
2505}
2506
2507static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2508{
2509 struct sdebug_host_info * sdbg_host;
2510 struct sdebug_dev_info * dev_info;
2511
2512 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2513 printk(KERN_INFO "scsi_debug: host_reset\n");
2514 ++num_host_resets;
2515 spin_lock(&sdebug_host_list_lock);
2516 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2517 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2518 dev_list)
2519 dev_info->reset = 1;
2520 }
2521 spin_unlock(&sdebug_host_list_lock);
2522 stop_all_queued();
2523 return SUCCESS;
2524}
2525
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526/* Initializes timers in queued array */
2527static void __init init_all_queued(void)
2528{
2529 unsigned long iflags;
2530 int k;
2531 struct sdebug_queued_cmd * sqcp;
2532
2533 spin_lock_irqsave(&queued_arr_lock, iflags);
2534 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2535 sqcp = &queued_arr[k];
2536 init_timer(&sqcp->cmnd_timer);
2537 sqcp->in_use = 0;
2538 sqcp->a_cmnd = NULL;
2539 }
2540 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2541}
2542
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002543static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002544 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545{
2546 struct partition * pp;
2547 int starts[SDEBUG_MAX_PARTS + 2];
2548 int sectors_per_part, num_sectors, k;
2549 int heads_by_sects, start_sec, end_sec;
2550
2551 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002552 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 return;
2554 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2555 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2556 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2557 "partitions to %d\n", SDEBUG_MAX_PARTS);
2558 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002559 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 sectors_per_part = (num_sectors - sdebug_sectors_per)
2561 / scsi_debug_num_parts;
2562 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2563 starts[0] = sdebug_sectors_per;
2564 for (k = 1; k < scsi_debug_num_parts; ++k)
2565 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2566 * heads_by_sects;
2567 starts[scsi_debug_num_parts] = num_sectors;
2568 starts[scsi_debug_num_parts + 1] = 0;
2569
2570 ramp[510] = 0x55; /* magic partition markings */
2571 ramp[511] = 0xAA;
2572 pp = (struct partition *)(ramp + 0x1be);
2573 for (k = 0; starts[k + 1]; ++k, ++pp) {
2574 start_sec = starts[k];
2575 end_sec = starts[k + 1] - 1;
2576 pp->boot_ind = 0;
2577
2578 pp->cyl = start_sec / heads_by_sects;
2579 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2580 / sdebug_sectors_per;
2581 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2582
2583 pp->end_cyl = end_sec / heads_by_sects;
2584 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2585 / sdebug_sectors_per;
2586 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2587
2588 pp->start_sect = start_sec;
2589 pp->nr_sects = end_sec - start_sec + 1;
2590 pp->sys_ind = 0x83; /* plain Linux partition */
2591 }
2592}
2593
2594static int schedule_resp(struct scsi_cmnd * cmnd,
2595 struct sdebug_dev_info * devip,
2596 done_funct_t done, int scsi_result, int delta_jiff)
2597{
2598 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2599 if (scsi_result) {
2600 struct scsi_device * sdp = cmnd->device;
2601
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002602 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2603 "non-zero result=0x%x\n", sdp->host->host_no,
2604 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 }
2606 }
2607 if (cmnd && devip) {
2608 /* simulate autosense by this driver */
2609 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2610 memcpy(cmnd->sense_buffer, devip->sense_buff,
2611 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2612 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2613 }
2614 if (delta_jiff <= 0) {
2615 if (cmnd)
2616 cmnd->result = scsi_result;
2617 if (done)
2618 done(cmnd);
2619 return 0;
2620 } else {
2621 unsigned long iflags;
2622 int k;
2623 struct sdebug_queued_cmd * sqcp = NULL;
2624
2625 spin_lock_irqsave(&queued_arr_lock, iflags);
2626 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2627 sqcp = &queued_arr[k];
2628 if (! sqcp->in_use)
2629 break;
2630 }
2631 if (k >= SCSI_DEBUG_CANQUEUE) {
2632 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2633 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2634 return 1; /* report busy to mid level */
2635 }
2636 sqcp->in_use = 1;
2637 sqcp->a_cmnd = cmnd;
2638 sqcp->scsi_result = scsi_result;
2639 sqcp->done_funct = done;
2640 sqcp->cmnd_timer.function = timer_intr_handler;
2641 sqcp->cmnd_timer.data = k;
2642 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2643 add_timer(&sqcp->cmnd_timer);
2644 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2645 if (cmnd)
2646 cmnd->result = 0;
2647 return 0;
2648 }
2649}
Douglas Gilbert23183912006-09-16 20:30:47 -04002650/* Note: The following macros create attribute files in the
2651 /sys/module/scsi_debug/parameters directory. Unfortunately this
2652 driver is unaware of a change and cannot trigger auxiliary actions
2653 as it can when the corresponding attribute in the
2654 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2655 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002656module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2657module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2658module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2659module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2660module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002661module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002662module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2663module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2664module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2665module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2666module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2667module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2668module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2669module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002670module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2671 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002672module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002673module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2674module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2675module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2676module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002677module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2678module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002679module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
2680module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2681module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
2682module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
2684MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2685MODULE_DESCRIPTION("SCSI debug adapter driver");
2686MODULE_LICENSE("GPL");
2687MODULE_VERSION(SCSI_DEBUG_VERSION);
2688
2689MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2690MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002691MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2692MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002693MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002694MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002695MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2696MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002698MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002699MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2701MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002702MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002703MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002704MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
2705MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
2706MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002707MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2708MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2709MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2710MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Martin K. Petersen44d92692009-10-15 14:45:27 -04002711MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)");
2712MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)");
2713MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)");
2714MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715
2716static char sdebug_info[256];
2717
2718static const char * scsi_debug_info(struct Scsi_Host * shp)
2719{
2720 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2721 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2722 scsi_debug_version_date, scsi_debug_dev_size_mb,
2723 scsi_debug_opts);
2724 return sdebug_info;
2725}
2726
2727/* scsi_debug_proc_info
2728 * Used if the driver currently has no own support for /proc/scsi
2729 */
2730static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2731 int length, int inout)
2732{
2733 int len, pos, begin;
2734 int orig_length;
2735
2736 orig_length = length;
2737
2738 if (inout == 1) {
2739 char arr[16];
2740 int minLen = length > 15 ? 15 : length;
2741
2742 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2743 return -EACCES;
2744 memcpy(arr, buffer, minLen);
2745 arr[minLen] = '\0';
2746 if (1 != sscanf(arr, "%d", &pos))
2747 return -EINVAL;
2748 scsi_debug_opts = pos;
2749 if (scsi_debug_every_nth != 0)
2750 scsi_debug_cmnd_count = 0;
2751 return length;
2752 }
2753 begin = 0;
2754 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2755 "%s [%s]\n"
2756 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2757 "every_nth=%d(curr:%d)\n"
2758 "delay=%d, max_luns=%d, scsi_level=%d\n"
2759 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2760 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002761 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2763 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2764 scsi_debug_cmnd_count, scsi_debug_delay,
2765 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002766 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2767 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002768 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 if (pos < offset) {
2770 len = 0;
2771 begin = pos;
2772 }
2773 *start = buffer + (offset - begin); /* Start of wanted data */
2774 len -= (offset - begin);
2775 if (len > length)
2776 len = length;
2777 return len;
2778}
2779
2780static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2781{
2782 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2783}
2784
2785static ssize_t sdebug_delay_store(struct device_driver * ddp,
2786 const char * buf, size_t count)
2787{
2788 int delay;
2789 char work[20];
2790
2791 if (1 == sscanf(buf, "%10s", work)) {
2792 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2793 scsi_debug_delay = delay;
2794 return count;
2795 }
2796 }
2797 return -EINVAL;
2798}
2799DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2800 sdebug_delay_store);
2801
2802static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2803{
2804 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2805}
2806
2807static ssize_t sdebug_opts_store(struct device_driver * ddp,
2808 const char * buf, size_t count)
2809{
2810 int opts;
2811 char work[20];
2812
2813 if (1 == sscanf(buf, "%10s", work)) {
2814 if (0 == strnicmp(work,"0x", 2)) {
2815 if (1 == sscanf(&work[2], "%x", &opts))
2816 goto opts_done;
2817 } else {
2818 if (1 == sscanf(work, "%d", &opts))
2819 goto opts_done;
2820 }
2821 }
2822 return -EINVAL;
2823opts_done:
2824 scsi_debug_opts = opts;
2825 scsi_debug_cmnd_count = 0;
2826 return count;
2827}
2828DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2829 sdebug_opts_store);
2830
2831static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2832{
2833 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2834}
2835static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2836 const char * buf, size_t count)
2837{
2838 int n;
2839
2840 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2841 scsi_debug_ptype = n;
2842 return count;
2843 }
2844 return -EINVAL;
2845}
2846DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2847
2848static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2849{
2850 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2851}
2852static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2853 const char * buf, size_t count)
2854{
2855 int n;
2856
2857 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2858 scsi_debug_dsense = n;
2859 return count;
2860 }
2861 return -EINVAL;
2862}
2863DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2864 sdebug_dsense_store);
2865
Douglas Gilbert23183912006-09-16 20:30:47 -04002866static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2867{
2868 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2869}
2870static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2871 const char * buf, size_t count)
2872{
2873 int n;
2874
2875 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2876 scsi_debug_fake_rw = n;
2877 return count;
2878 }
2879 return -EINVAL;
2880}
2881DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2882 sdebug_fake_rw_store);
2883
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002884static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2885{
2886 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2887}
2888static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2889 const char * buf, size_t count)
2890{
2891 int n;
2892
2893 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2894 scsi_debug_no_lun_0 = n;
2895 return count;
2896 }
2897 return -EINVAL;
2898}
2899DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2900 sdebug_no_lun_0_store);
2901
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2903{
2904 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2905}
2906static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2907 const char * buf, size_t count)
2908{
2909 int n;
2910
2911 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2912 scsi_debug_num_tgts = n;
2913 sdebug_max_tgts_luns();
2914 return count;
2915 }
2916 return -EINVAL;
2917}
2918DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2919 sdebug_num_tgts_store);
2920
2921static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2922{
2923 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2924}
2925DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2926
2927static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2928{
2929 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2930}
2931DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2932
2933static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2934{
2935 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2936}
2937static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2938 const char * buf, size_t count)
2939{
2940 int nth;
2941
2942 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2943 scsi_debug_every_nth = nth;
2944 scsi_debug_cmnd_count = 0;
2945 return count;
2946 }
2947 return -EINVAL;
2948}
2949DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2950 sdebug_every_nth_store);
2951
2952static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2953{
2954 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2955}
2956static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2957 const char * buf, size_t count)
2958{
2959 int n;
2960
2961 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2962 scsi_debug_max_luns = n;
2963 sdebug_max_tgts_luns();
2964 return count;
2965 }
2966 return -EINVAL;
2967}
2968DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2969 sdebug_max_luns_store);
2970
2971static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2972{
2973 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2974}
2975DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2976
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002977static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2978{
2979 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2980}
2981static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2982 const char * buf, size_t count)
2983{
2984 int n;
2985
2986 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2987 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002988
2989 sdebug_capacity = get_sdebug_capacity();
2990
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002991 return count;
2992 }
2993 return -EINVAL;
2994}
2995DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2996 sdebug_virtual_gb_store);
2997
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2999{
3000 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
3001}
3002
3003static ssize_t sdebug_add_host_store(struct device_driver * ddp,
3004 const char * buf, size_t count)
3005{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003006 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003008 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 if (delta_hosts > 0) {
3011 do {
3012 sdebug_add_adapter();
3013 } while (--delta_hosts);
3014 } else if (delta_hosts < 0) {
3015 do {
3016 sdebug_remove_adapter();
3017 } while (++delta_hosts);
3018 }
3019 return count;
3020}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003021DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 sdebug_add_host_store);
3023
Douglas Gilbert23183912006-09-16 20:30:47 -04003024static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
3025 char * buf)
3026{
3027 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3028}
3029static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
3030 const char * buf, size_t count)
3031{
3032 int n;
3033
3034 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3035 scsi_debug_vpd_use_hostno = n;
3036 return count;
3037 }
3038 return -EINVAL;
3039}
3040DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
3041 sdebug_vpd_use_hostno_store);
3042
Martin K. Petersen597136a2008-06-05 00:12:59 -04003043static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3044{
3045 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3046}
3047DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3048
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003049static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3050{
3051 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3052}
3053DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3054
3055static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3056{
3057 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3058}
3059DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3060
3061static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3062{
3063 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3064}
3065DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3066
3067static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3068{
3069 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3070}
3071DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3072
Martin K. Petersen44d92692009-10-15 14:45:27 -04003073static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
3074{
3075 ssize_t count;
3076
3077 if (scsi_debug_unmap_granularity == 0)
3078 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3079 sdebug_store_sectors);
3080
3081 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3082
3083 buf[count++] = '\n';
3084 buf[count++] = 0;
3085
3086 return count;
3087}
3088DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
3089
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003090
Douglas Gilbert23183912006-09-16 20:30:47 -04003091/* Note: The following function creates attribute files in the
3092 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3093 files (over those found in the /sys/module/scsi_debug/parameters
3094 directory) is that auxiliary actions can be triggered when an attribute
3095 is changed. For example see: sdebug_add_host_store() above.
3096 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003097static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003099 int ret;
3100
3101 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3102 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
3103 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3104 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3105 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04003106 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003107 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003108 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003109 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003110 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003111 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3112 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
3113 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04003114 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
3115 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003116 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003117 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3118 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3119 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3120 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003121 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003122 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123}
3124
3125static void do_remove_driverfs_files(void)
3126{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003127 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003128 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3129 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3130 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3131 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003132 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04003133 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3134 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
3136 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
3137 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003139 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
3140 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003142 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
3144 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3145 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3146 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
3147 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3148}
3149
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003150static void pseudo_0_release(struct device *dev)
3151{
3152 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3153 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
3154}
3155
3156static struct device pseudo_primary = {
Kay Sievers71610f52008-12-03 22:41:36 +01003157 .init_name = "pseudo_0",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003158 .release = pseudo_0_release,
3159};
3160
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161static int __init scsi_debug_init(void)
3162{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003163 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 int host_to_add;
3165 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003166 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167
Martin K. Petersen597136a2008-06-05 00:12:59 -04003168 switch (scsi_debug_sector_size) {
3169 case 512:
3170 case 1024:
3171 case 2048:
3172 case 4096:
3173 break;
3174 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003175 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04003176 scsi_debug_sector_size);
3177 return -EINVAL;
3178 }
3179
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003180 switch (scsi_debug_dif) {
3181
3182 case SD_DIF_TYPE0_PROTECTION:
3183 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003184 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003185 case SD_DIF_TYPE3_PROTECTION:
3186 break;
3187
3188 default:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003189 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003190 return -EINVAL;
3191 }
3192
3193 if (scsi_debug_guard > 1) {
3194 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3195 return -EINVAL;
3196 }
3197
3198 if (scsi_debug_ato > 1) {
3199 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3200 return -EINVAL;
3201 }
3202
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003203 if (scsi_debug_physblk_exp > 15) {
3204 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3205 scsi_debug_physblk_exp);
3206 return -EINVAL;
3207 }
3208
3209 if (scsi_debug_lowest_aligned > 0x3fff) {
3210 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3211 scsi_debug_lowest_aligned);
3212 return -EINVAL;
3213 }
3214
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 if (scsi_debug_dev_size_mb < 1)
3216 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003217 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003218 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003219 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
3221 /* play around with geometry, don't waste too much on track 0 */
3222 sdebug_heads = 8;
3223 sdebug_sectors_per = 32;
3224 if (scsi_debug_dev_size_mb >= 16)
3225 sdebug_heads = 32;
3226 else if (scsi_debug_dev_size_mb >= 256)
3227 sdebug_heads = 64;
3228 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3229 (sdebug_sectors_per * sdebug_heads);
3230 if (sdebug_cylinders_per >= 1024) {
3231 /* other LLDs do this; implies >= 1GB ram disk ... */
3232 sdebug_heads = 255;
3233 sdebug_sectors_per = 63;
3234 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3235 (sdebug_sectors_per * sdebug_heads);
3236 }
3237
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 fake_storep = vmalloc(sz);
3239 if (NULL == fake_storep) {
3240 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
3241 return -ENOMEM;
3242 }
3243 memset(fake_storep, 0, sz);
3244 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003245 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003247 if (scsi_debug_dif) {
3248 int dif_size;
3249
3250 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3251 dif_storep = vmalloc(dif_size);
3252
3253 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3254 dif_size, dif_storep);
3255
3256 if (dif_storep == NULL) {
3257 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3258 ret = -ENOMEM;
3259 goto free_vm;
3260 }
3261
3262 memset(dif_storep, 0xff, dif_size);
3263 }
3264
Martin K. Petersen44d92692009-10-15 14:45:27 -04003265 if (scsi_debug_unmap_granularity) {
3266 unsigned int map_bytes;
3267
3268 if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
3269 printk(KERN_ERR
3270 "%s: ERR: unmap_granularity < unmap_alignment\n",
3271 __func__);
3272 return -EINVAL;
3273 }
3274
3275 map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
3276 map_bytes = map_size >> 3;
3277 map_storep = vmalloc(map_bytes);
3278
3279 printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
3280 map_size);
3281
3282 if (map_storep == NULL) {
3283 printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
3284 ret = -ENOMEM;
3285 goto free_vm;
3286 }
3287
3288 memset(map_storep, 0x0, map_bytes);
3289
3290 /* Map first 1KB for partition table */
3291 if (scsi_debug_num_parts)
3292 map_region(0, 2);
3293 }
3294
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003295 ret = device_register(&pseudo_primary);
3296 if (ret < 0) {
3297 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
3298 ret);
3299 goto free_vm;
3300 }
3301 ret = bus_register(&pseudo_lld_bus);
3302 if (ret < 0) {
3303 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
3304 ret);
3305 goto dev_unreg;
3306 }
3307 ret = driver_register(&sdebug_driverfs_driver);
3308 if (ret < 0) {
3309 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
3310 ret);
3311 goto bus_unreg;
3312 }
3313 ret = do_create_driverfs_files();
3314 if (ret < 0) {
3315 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
3316 ret);
3317 goto del_files;
3318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003320 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 host_to_add = scsi_debug_add_host;
3323 scsi_debug_add_host = 0;
3324
3325 for (k = 0; k < host_to_add; k++) {
3326 if (sdebug_add_adapter()) {
3327 printk(KERN_ERR "scsi_debug_init: "
3328 "sdebug_add_adapter failed k=%d\n", k);
3329 break;
3330 }
3331 }
3332
3333 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3334 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
3335 scsi_debug_add_host);
3336 }
3337 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003338
3339del_files:
3340 do_remove_driverfs_files();
3341 driver_unregister(&sdebug_driverfs_driver);
3342bus_unreg:
3343 bus_unregister(&pseudo_lld_bus);
3344dev_unreg:
3345 device_unregister(&pseudo_primary);
3346free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003347 if (map_storep)
3348 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003349 if (dif_storep)
3350 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003351 vfree(fake_storep);
3352
3353 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354}
3355
3356static void __exit scsi_debug_exit(void)
3357{
3358 int k = scsi_debug_add_host;
3359
3360 stop_all_queued();
3361 for (; k; k--)
3362 sdebug_remove_adapter();
3363 do_remove_driverfs_files();
3364 driver_unregister(&sdebug_driverfs_driver);
3365 bus_unregister(&pseudo_lld_bus);
3366 device_unregister(&pseudo_primary);
3367
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003368 if (dif_storep)
3369 vfree(dif_storep);
3370
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 vfree(fake_storep);
3372}
3373
3374device_initcall(scsi_debug_init);
3375module_exit(scsi_debug_exit);
3376
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377static void sdebug_release_adapter(struct device * dev)
3378{
3379 struct sdebug_host_info *sdbg_host;
3380
3381 sdbg_host = to_sdebug_host(dev);
3382 kfree(sdbg_host);
3383}
3384
3385static int sdebug_add_adapter(void)
3386{
3387 int k, devs_per_host;
3388 int error = 0;
3389 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003390 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003392 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393 if (NULL == sdbg_host) {
3394 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003395 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 return -ENOMEM;
3397 }
3398
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3400
3401 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3402 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003403 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3404 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003406 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 error = -ENOMEM;
3408 goto clean;
3409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 }
3411
3412 spin_lock(&sdebug_host_list_lock);
3413 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3414 spin_unlock(&sdebug_host_list_lock);
3415
3416 sdbg_host->dev.bus = &pseudo_lld_bus;
3417 sdbg_host->dev.parent = &pseudo_primary;
3418 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003419 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
3421 error = device_register(&sdbg_host->dev);
3422
3423 if (error)
3424 goto clean;
3425
3426 ++scsi_debug_add_host;
3427 return error;
3428
3429clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003430 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3431 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 list_del(&sdbg_devinfo->dev_list);
3433 kfree(sdbg_devinfo);
3434 }
3435
3436 kfree(sdbg_host);
3437 return error;
3438}
3439
3440static void sdebug_remove_adapter(void)
3441{
3442 struct sdebug_host_info * sdbg_host = NULL;
3443
3444 spin_lock(&sdebug_host_list_lock);
3445 if (!list_empty(&sdebug_host_list)) {
3446 sdbg_host = list_entry(sdebug_host_list.prev,
3447 struct sdebug_host_info, host_list);
3448 list_del(&sdbg_host->host_list);
3449 }
3450 spin_unlock(&sdebug_host_list_lock);
3451
3452 if (!sdbg_host)
3453 return;
3454
3455 device_unregister(&sdbg_host->dev);
3456 --scsi_debug_add_host;
3457}
3458
FUJITA Tomonori639db472008-03-20 11:09:19 +09003459static
3460int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
3461{
3462 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3463 int len, k;
3464 unsigned int num;
3465 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003466 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003467 int errsts = 0;
3468 int target = SCpnt->device->id;
3469 struct sdebug_dev_info *devip = NULL;
3470 int inj_recovered = 0;
3471 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003472 int inj_dif = 0;
3473 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003474 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003475 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003476
3477 scsi_set_resid(SCpnt, 0);
3478 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3479 printk(KERN_INFO "scsi_debug: cmd ");
3480 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3481 printk("%02x ", (int)cmd[k]);
3482 printk("\n");
3483 }
3484
3485 if (target == SCpnt->device->host->hostt->this_id) {
3486 printk(KERN_INFO "scsi_debug: initiator's id used as "
3487 "target!\n");
3488 return schedule_resp(SCpnt, NULL, done,
3489 DID_NO_CONNECT << 16, 0);
3490 }
3491
3492 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3493 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3494 return schedule_resp(SCpnt, NULL, done,
3495 DID_NO_CONNECT << 16, 0);
3496 devip = devInfoReg(SCpnt->device);
3497 if (NULL == devip)
3498 return schedule_resp(SCpnt, NULL, done,
3499 DID_NO_CONNECT << 16, 0);
3500
3501 if ((scsi_debug_every_nth != 0) &&
3502 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3503 scsi_debug_cmnd_count = 0;
3504 if (scsi_debug_every_nth < -1)
3505 scsi_debug_every_nth = -1;
3506 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3507 return 0; /* ignore command causing timeout */
3508 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3509 inj_recovered = 1; /* to reads and writes below */
3510 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3511 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003512 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3513 inj_dif = 1; /* to reads and writes below */
3514 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3515 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003516 }
3517
3518 if (devip->wlun) {
3519 switch (*cmd) {
3520 case INQUIRY:
3521 case REQUEST_SENSE:
3522 case TEST_UNIT_READY:
3523 case REPORT_LUNS:
3524 break; /* only allowable wlun commands */
3525 default:
3526 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3527 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3528 "not supported for wlun\n", *cmd);
3529 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3530 INVALID_OPCODE, 0);
3531 errsts = check_condition_result;
3532 return schedule_resp(SCpnt, devip, done, errsts,
3533 0);
3534 }
3535 }
3536
3537 switch (*cmd) {
3538 case INQUIRY: /* mandatory, ignore unit attention */
3539 delay_override = 1;
3540 errsts = resp_inquiry(SCpnt, target, devip);
3541 break;
3542 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3543 delay_override = 1;
3544 errsts = resp_requests(SCpnt, devip);
3545 break;
3546 case REZERO_UNIT: /* actually this is REWIND for SSC */
3547 case START_STOP:
3548 errsts = resp_start_stop(SCpnt, devip);
3549 break;
3550 case ALLOW_MEDIUM_REMOVAL:
3551 errsts = check_readiness(SCpnt, 1, devip);
3552 if (errsts)
3553 break;
3554 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3555 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3556 cmd[4] ? "inhibited" : "enabled");
3557 break;
3558 case SEND_DIAGNOSTIC: /* mandatory */
3559 errsts = check_readiness(SCpnt, 1, devip);
3560 break;
3561 case TEST_UNIT_READY: /* mandatory */
3562 delay_override = 1;
3563 errsts = check_readiness(SCpnt, 0, devip);
3564 break;
3565 case RESERVE:
3566 errsts = check_readiness(SCpnt, 1, devip);
3567 break;
3568 case RESERVE_10:
3569 errsts = check_readiness(SCpnt, 1, devip);
3570 break;
3571 case RELEASE:
3572 errsts = check_readiness(SCpnt, 1, devip);
3573 break;
3574 case RELEASE_10:
3575 errsts = check_readiness(SCpnt, 1, devip);
3576 break;
3577 case READ_CAPACITY:
3578 errsts = resp_readcap(SCpnt, devip);
3579 break;
3580 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003581 if (cmd[1] == SAI_READ_CAPACITY_16)
3582 errsts = resp_readcap16(SCpnt, devip);
3583 else if (cmd[1] == SAI_GET_LBA_STATUS) {
3584
3585 if (scsi_debug_unmap_max_desc == 0) {
3586 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3587 INVALID_COMMAND_OPCODE, 0);
3588 errsts = check_condition_result;
3589 } else
3590 errsts = resp_get_lba_status(SCpnt, devip);
3591 } else {
FUJITA Tomonori639db472008-03-20 11:09:19 +09003592 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3593 INVALID_OPCODE, 0);
3594 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003595 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09003596 break;
3597 case MAINTENANCE_IN:
3598 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3599 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3600 INVALID_OPCODE, 0);
3601 errsts = check_condition_result;
3602 break;
3603 }
3604 errsts = resp_report_tgtpgs(SCpnt, devip);
3605 break;
3606 case READ_16:
3607 case READ_12:
3608 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003609 /* READ{10,12,16} and DIF Type 2 are natural enemies */
3610 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3611 cmd[1] & 0xe0) {
3612 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3613 INVALID_COMMAND_OPCODE, 0);
3614 errsts = check_condition_result;
3615 break;
3616 }
3617
3618 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3619 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3620 (cmd[1] & 0xe0) == 0)
3621 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3622
3623 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003624 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003625read:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003626 errsts = check_readiness(SCpnt, 0, devip);
3627 if (errsts)
3628 break;
3629 if (scsi_debug_fake_rw)
3630 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003631 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3632 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003633 if (inj_recovered && (0 == errsts)) {
3634 mk_sense_buffer(devip, RECOVERED_ERROR,
3635 THRESHOLD_EXCEEDED, 0);
3636 errsts = check_condition_result;
3637 } else if (inj_transport && (0 == errsts)) {
3638 mk_sense_buffer(devip, ABORTED_COMMAND,
3639 TRANSPORT_PROBLEM, ACK_NAK_TO);
3640 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003641 } else if (inj_dif && (0 == errsts)) {
3642 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3643 errsts = illegal_condition_result;
3644 } else if (inj_dix && (0 == errsts)) {
3645 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3646 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003647 }
3648 break;
3649 case REPORT_LUNS: /* mandatory, ignore unit attention */
3650 delay_override = 1;
3651 errsts = resp_report_luns(SCpnt, devip);
3652 break;
3653 case VERIFY: /* 10 byte SBC-2 command */
3654 errsts = check_readiness(SCpnt, 0, devip);
3655 break;
3656 case WRITE_16:
3657 case WRITE_12:
3658 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003659 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3660 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3661 cmd[1] & 0xe0) {
3662 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3663 INVALID_COMMAND_OPCODE, 0);
3664 errsts = check_condition_result;
3665 break;
3666 }
3667
3668 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3669 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3670 (cmd[1] & 0xe0) == 0)
3671 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3672
3673 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003674 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003675write:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003676 errsts = check_readiness(SCpnt, 0, devip);
3677 if (errsts)
3678 break;
3679 if (scsi_debug_fake_rw)
3680 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003681 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3682 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003683 if (inj_recovered && (0 == errsts)) {
3684 mk_sense_buffer(devip, RECOVERED_ERROR,
3685 THRESHOLD_EXCEEDED, 0);
3686 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003687 } else if (inj_dif && (0 == errsts)) {
3688 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3689 errsts = illegal_condition_result;
3690 } else if (inj_dix && (0 == errsts)) {
3691 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3692 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003693 }
3694 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003695 case WRITE_SAME_16:
3696 if (cmd[1] & 0x8)
3697 unmap = 1;
3698 /* fall through */
3699 case WRITE_SAME:
3700 errsts = check_readiness(SCpnt, 0, devip);
3701 if (errsts)
3702 break;
3703 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3704 errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
3705 break;
3706 case UNMAP:
3707 errsts = check_readiness(SCpnt, 0, devip);
3708 if (errsts)
3709 break;
3710
3711 if (scsi_debug_unmap_max_desc == 0) {
3712 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3713 INVALID_COMMAND_OPCODE, 0);
3714 errsts = check_condition_result;
3715 } else
3716 errsts = resp_unmap(SCpnt, devip);
3717 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003718 case MODE_SENSE:
3719 case MODE_SENSE_10:
3720 errsts = resp_mode_sense(SCpnt, target, devip);
3721 break;
3722 case MODE_SELECT:
3723 errsts = resp_mode_select(SCpnt, 1, devip);
3724 break;
3725 case MODE_SELECT_10:
3726 errsts = resp_mode_select(SCpnt, 0, devip);
3727 break;
3728 case LOG_SENSE:
3729 errsts = resp_log_sense(SCpnt, devip);
3730 break;
3731 case SYNCHRONIZE_CACHE:
3732 delay_override = 1;
3733 errsts = check_readiness(SCpnt, 0, devip);
3734 break;
3735 case WRITE_BUFFER:
3736 errsts = check_readiness(SCpnt, 1, devip);
3737 break;
3738 case XDWRITEREAD_10:
3739 if (!scsi_bidi_cmnd(SCpnt)) {
3740 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3741 INVALID_FIELD_IN_CDB, 0);
3742 errsts = check_condition_result;
3743 break;
3744 }
3745
3746 errsts = check_readiness(SCpnt, 0, devip);
3747 if (errsts)
3748 break;
3749 if (scsi_debug_fake_rw)
3750 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003751 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3752 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003753 if (errsts)
3754 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003755 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003756 if (errsts)
3757 break;
3758 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3759 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003760 case VARIABLE_LENGTH_CMD:
3761 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3762
3763 if ((cmd[10] & 0xe0) == 0)
3764 printk(KERN_ERR
3765 "Unprotected RD/WR to DIF device\n");
3766
3767 if (cmd[9] == READ_32) {
3768 BUG_ON(SCpnt->cmd_len < 32);
3769 goto read;
3770 }
3771
3772 if (cmd[9] == WRITE_32) {
3773 BUG_ON(SCpnt->cmd_len < 32);
3774 goto write;
3775 }
3776 }
3777
3778 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3779 INVALID_FIELD_IN_CDB, 0);
3780 errsts = check_condition_result;
3781 break;
3782
FUJITA Tomonori639db472008-03-20 11:09:19 +09003783 default:
3784 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3785 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3786 "supported\n", *cmd);
3787 errsts = check_readiness(SCpnt, 1, devip);
3788 if (errsts)
3789 break; /* Unit attention takes precedence */
3790 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3791 errsts = check_condition_result;
3792 break;
3793 }
3794 return schedule_resp(SCpnt, devip, done, errsts,
3795 (delay_override ? 0 : scsi_debug_delay));
3796}
3797
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003798static struct scsi_host_template sdebug_driver_template = {
3799 .proc_info = scsi_debug_proc_info,
3800 .proc_name = sdebug_proc_name,
3801 .name = "SCSI DEBUG",
3802 .info = scsi_debug_info,
3803 .slave_alloc = scsi_debug_slave_alloc,
3804 .slave_configure = scsi_debug_slave_configure,
3805 .slave_destroy = scsi_debug_slave_destroy,
3806 .ioctl = scsi_debug_ioctl,
3807 .queuecommand = scsi_debug_queuecommand,
3808 .eh_abort_handler = scsi_debug_abort,
3809 .eh_bus_reset_handler = scsi_debug_bus_reset,
3810 .eh_device_reset_handler = scsi_debug_device_reset,
3811 .eh_host_reset_handler = scsi_debug_host_reset,
3812 .bios_param = scsi_debug_biosparam,
3813 .can_queue = SCSI_DEBUG_CANQUEUE,
3814 .this_id = 7,
3815 .sg_tablesize = 256,
3816 .cmd_per_lun = 16,
3817 .max_sectors = 0xffff,
3818 .use_clustering = DISABLE_CLUSTERING,
3819 .module = THIS_MODULE,
3820};
3821
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822static int sdebug_driver_probe(struct device * dev)
3823{
3824 int error = 0;
3825 struct sdebug_host_info *sdbg_host;
3826 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003827 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
3829 sdbg_host = to_sdebug_host(dev);
3830
3831 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3832 if (NULL == hpnt) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003833 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 error = -ENODEV;
3835 return error;
3836 }
3837
3838 sdbg_host->shost = hpnt;
3839 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3840 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3841 hpnt->max_id = scsi_debug_num_tgts + 1;
3842 else
3843 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003844 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003846 host_prot = 0;
3847
3848 switch (scsi_debug_dif) {
3849
3850 case SD_DIF_TYPE1_PROTECTION:
3851 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3852 if (scsi_debug_dix)
3853 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3854 break;
3855
3856 case SD_DIF_TYPE2_PROTECTION:
3857 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3858 if (scsi_debug_dix)
3859 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3860 break;
3861
3862 case SD_DIF_TYPE3_PROTECTION:
3863 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3864 if (scsi_debug_dix)
3865 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3866 break;
3867
3868 default:
3869 if (scsi_debug_dix)
3870 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3871 break;
3872 }
3873
3874 scsi_host_set_prot(hpnt, host_prot);
3875
3876 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3877 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3878 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3879 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3880 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3881 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3882 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3883 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3884
3885 if (scsi_debug_guard == 1)
3886 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3887 else
3888 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3889
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 error = scsi_add_host(hpnt, &sdbg_host->dev);
3891 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003892 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 error = -ENODEV;
3894 scsi_host_put(hpnt);
3895 } else
3896 scsi_scan_host(hpnt);
3897
3898
3899 return error;
3900}
3901
3902static int sdebug_driver_remove(struct device * dev)
3903{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003905 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906
3907 sdbg_host = to_sdebug_host(dev);
3908
3909 if (!sdbg_host) {
3910 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003911 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 return -ENODEV;
3913 }
3914
3915 scsi_remove_host(sdbg_host->shost);
3916
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003917 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3918 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919 list_del(&sdbg_devinfo->dev_list);
3920 kfree(sdbg_devinfo);
3921 }
3922
3923 scsi_host_put(sdbg_host->shost);
3924 return 0;
3925}
3926
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003927static int pseudo_lld_bus_match(struct device *dev,
3928 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003930 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003932
3933static struct bus_type pseudo_lld_bus = {
3934 .name = "pseudo",
3935 .match = pseudo_lld_bus_match,
3936 .probe = sdebug_driver_probe,
3937 .remove = sdebug_driver_remove,
3938};