blob: cb4bf16b4e66804cf2040db1f710c22a1da27658 [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
688static unsigned char vpdb0_data[] = {
689 /* from 4th byte */ 0,0,0,4,
690 0,0,0x4,0,
691 0,0,0,64,
692};
693
694static int inquiry_evpd_b0(unsigned char * arr)
695{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400696 unsigned int gran;
697
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400698 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400699 gran = 1 << scsi_debug_physblk_exp;
700 arr[2] = (gran >> 8) & 0xff;
701 arr[3] = gran & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400702 if (sdebug_store_sectors > 0x400) {
703 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
704 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
705 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
706 arr[7] = sdebug_store_sectors & 0xff;
707 }
Martin K. Petersen44d92692009-10-15 14:45:27 -0400708
709 if (scsi_debug_unmap_max_desc) {
710 unsigned int blocks;
711
712 if (scsi_debug_unmap_max_blocks)
713 blocks = scsi_debug_unmap_max_blocks;
714 else
715 blocks = 0xffffffff;
716
717 put_unaligned_be32(blocks, &arr[16]);
718 put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]);
719 }
720
721 if (scsi_debug_unmap_alignment) {
722 put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]);
723 arr[28] |= 0x80; /* UGAVALID */
724 }
725
726 if (scsi_debug_unmap_granularity) {
727 put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]);
728 return 0x3c; /* Mandatory page length for thin provisioning */
729 }
730
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400731 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600734static int inquiry_evpd_b1(unsigned char *arr)
735{
736 memset(arr, 0, 0x3c);
737 arr[0] = 0;
738 arr[1] = 1;
739
740 return 0x3c;
741}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400744#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
746static int resp_inquiry(struct scsi_cmnd * scp, int target,
747 struct sdebug_dev_info * devip)
748{
749 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200750 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200752 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
754 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500755 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
756 if (! arr)
757 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400758 if (devip->wlun)
759 pq_pdt = 0x1e; /* present, wlun */
760 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
761 pq_pdt = 0x7f; /* not present, no device type */
762 else
763 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 arr[0] = pq_pdt;
765 if (0x2 & cmd[1]) { /* CMDDT bit set */
766 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
767 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200768 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 return check_condition_result;
770 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200771 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400772 char lu_id_str[6];
773 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200775 port_group_id = (((host_no + 1) & 0x7f) << 8) +
776 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400777 if (0 == scsi_debug_vpd_use_hostno)
778 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400779 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
780 (devip->target * 1000) + devip->lun);
781 target_dev_id = ((host_no + 1) * 2000) +
782 (devip->target * 1000) - 3;
783 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400785 arr[1] = cmd[2]; /*sanity */
786 n = 4;
787 arr[n++] = 0x0; /* this page */
788 arr[n++] = 0x80; /* unit serial number */
789 arr[n++] = 0x83; /* device identification */
790 arr[n++] = 0x84; /* software interface ident. */
791 arr[n++] = 0x85; /* management network addresses */
792 arr[n++] = 0x86; /* extended inquiry */
793 arr[n++] = 0x87; /* mode page policy */
794 arr[n++] = 0x88; /* SCSI ports */
795 arr[n++] = 0x89; /* ATA information */
796 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600797 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400798 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400800 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400802 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400804 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200805 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
806 target_dev_id, lu_id_num,
807 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400808 } else if (0x84 == cmd[2]) { /* Software interface ident. */
809 arr[1] = cmd[2]; /*sanity */
810 arr[3] = inquiry_evpd_84(&arr[4]);
811 } else if (0x85 == cmd[2]) { /* Management network addresses */
812 arr[1] = cmd[2]; /*sanity */
813 arr[3] = inquiry_evpd_85(&arr[4]);
814 } else if (0x86 == cmd[2]) { /* extended inquiry */
815 arr[1] = cmd[2]; /*sanity */
816 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500817 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
818 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
819 else if (scsi_debug_dif)
820 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
821 else
822 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400823 arr[5] = 0x7; /* head of q, ordered + simple q's */
824 } else if (0x87 == cmd[2]) { /* mode page policy */
825 arr[1] = cmd[2]; /*sanity */
826 arr[3] = 0x8; /* number of following entries */
827 arr[4] = 0x2; /* disconnect-reconnect mp */
828 arr[6] = 0x80; /* mlus, shared */
829 arr[8] = 0x18; /* protocol specific lu */
830 arr[10] = 0x82; /* mlus, per initiator port */
831 } else if (0x88 == cmd[2]) { /* SCSI Ports */
832 arr[1] = cmd[2]; /*sanity */
833 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
834 } else if (0x89 == cmd[2]) { /* ATA information */
835 arr[1] = cmd[2]; /*sanity */
836 n = inquiry_evpd_89(&arr[4]);
837 arr[2] = (n >> 8);
838 arr[3] = (n & 0xff);
839 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
840 arr[1] = cmd[2]; /*sanity */
841 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600842 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
843 arr[1] = cmd[2]; /*sanity */
844 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 } else {
846 /* Illegal request, invalid field in cdb */
847 mk_sense_buffer(devip, ILLEGAL_REQUEST,
848 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200849 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 return check_condition_result;
851 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400852 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200853 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400854 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200855 kfree(arr);
856 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 }
858 /* drops through here for a standard inquiry */
859 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
860 arr[2] = scsi_debug_scsi_level;
861 arr[3] = 2; /* response_data_format==2 */
862 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500863 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200864 if (0 == scsi_debug_vpd_use_hostno)
865 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400866 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400868 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 memcpy(&arr[8], inq_vendor_id, 8);
870 memcpy(&arr[16], inq_product_id, 16);
871 memcpy(&arr[32], inq_product_rev, 4);
872 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400873 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
874 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
875 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400877 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400879 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400881 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200882 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200884 kfree(arr);
885 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886}
887
888static int resp_requests(struct scsi_cmnd * scp,
889 struct sdebug_dev_info * devip)
890{
891 unsigned char * sbuff;
892 unsigned char *cmd = (unsigned char *)scp->cmnd;
893 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400894 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 int len = 18;
896
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400897 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400899 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
900 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400902 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
903 if (want_dsense) {
904 arr[0] = 0x72;
905 arr[1] = 0x0; /* NO_SENSE in sense_key */
906 arr[2] = THRESHOLD_EXCEEDED;
907 arr[3] = 0xff; /* TEST set and MRIE==6 */
908 } else {
909 arr[0] = 0x70;
910 arr[2] = 0x0; /* NO_SENSE in sense_key */
911 arr[7] = 0xa; /* 18 byte sense buffer */
912 arr[12] = THRESHOLD_EXCEEDED;
913 arr[13] = 0xff; /* TEST set and MRIE==6 */
914 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400915 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400917 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
918 /* DESC bit set and sense_buff in fixed format */
919 memset(arr, 0, sizeof(arr));
920 arr[0] = 0x72;
921 arr[1] = sbuff[2]; /* sense key */
922 arr[2] = sbuff[12]; /* asc */
923 arr[3] = sbuff[13]; /* ascq */
924 len = 8;
925 }
926 }
927 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 return fill_from_dev_buffer(scp, arr, len);
929}
930
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400931static int resp_start_stop(struct scsi_cmnd * scp,
932 struct sdebug_dev_info * devip)
933{
934 unsigned char *cmd = (unsigned char *)scp->cmnd;
935 int power_cond, errsts, start;
936
937 if ((errsts = check_readiness(scp, 1, devip)))
938 return errsts;
939 power_cond = (cmd[4] & 0xf0) >> 4;
940 if (power_cond) {
941 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
942 0);
943 return check_condition_result;
944 }
945 start = cmd[4] & 1;
946 if (start == devip->stopped)
947 devip->stopped = !start;
948 return 0;
949}
950
FUJITA Tomonori28898872008-03-30 00:59:55 +0900951static sector_t get_sdebug_capacity(void)
952{
953 if (scsi_debug_virtual_gb > 0)
FUJITA Tomonori73da9c12009-04-22 17:42:25 -0700954 return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
FUJITA Tomonori28898872008-03-30 00:59:55 +0900955 else
956 return sdebug_store_sectors;
957}
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959#define SDEBUG_READCAP_ARR_SZ 8
960static int resp_readcap(struct scsi_cmnd * scp,
961 struct sdebug_dev_info * devip)
962{
963 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400964 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 int errsts;
966
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400967 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400969 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900970 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400972 if (sdebug_capacity < 0xffffffff) {
973 capac = (unsigned int)sdebug_capacity - 1;
974 arr[0] = (capac >> 24);
975 arr[1] = (capac >> 16) & 0xff;
976 arr[2] = (capac >> 8) & 0xff;
977 arr[3] = capac & 0xff;
978 } else {
979 arr[0] = 0xff;
980 arr[1] = 0xff;
981 arr[2] = 0xff;
982 arr[3] = 0xff;
983 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400984 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
985 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
987}
988
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400989#define SDEBUG_READCAP16_ARR_SZ 32
990static int resp_readcap16(struct scsi_cmnd * scp,
991 struct sdebug_dev_info * devip)
992{
993 unsigned char *cmd = (unsigned char *)scp->cmnd;
994 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
995 unsigned long long capac;
996 int errsts, k, alloc_len;
997
998 if ((errsts = check_readiness(scp, 1, devip)))
999 return errsts;
1000 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1001 + cmd[13]);
1002 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001003 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001004 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1005 capac = sdebug_capacity - 1;
1006 for (k = 0; k < 8; ++k, capac >>= 8)
1007 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001008 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
1009 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
1010 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
1011 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001012 arr[13] = scsi_debug_physblk_exp & 0xf;
1013 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001014
1015 if (scsi_debug_unmap_granularity)
1016 arr[14] |= 0x80; /* TPE */
1017
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001018 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001019
1020 if (scsi_debug_dif) {
1021 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
1022 arr[12] |= 1; /* PROT_EN */
1023 }
1024
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001025 return fill_from_dev_buffer(scp, arr,
1026 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1027}
1028
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001029#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1030
1031static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1032 struct sdebug_dev_info * devip)
1033{
1034 unsigned char *cmd = (unsigned char *)scp->cmnd;
1035 unsigned char * arr;
1036 int host_no = devip->sdbg_host->shost->host_no;
1037 int n, ret, alen, rlen;
1038 int port_group_a, port_group_b, port_a, port_b;
1039
1040 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1041 + cmd[9]);
1042
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001043 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1044 if (! arr)
1045 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001046 /*
1047 * EVPD page 0x88 states we have two ports, one
1048 * real and a fake port with no device connected.
1049 * So we create two port groups with one port each
1050 * and set the group with port B to unavailable.
1051 */
1052 port_a = 0x1; /* relative port A */
1053 port_b = 0x2; /* relative port B */
1054 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1055 (devip->channel & 0x7f);
1056 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1057 (devip->channel & 0x7f) + 0x80;
1058
1059 /*
1060 * The asymmetric access state is cycled according to the host_id.
1061 */
1062 n = 4;
1063 if (0 == scsi_debug_vpd_use_hostno) {
1064 arr[n++] = host_no % 3; /* Asymm access state */
1065 arr[n++] = 0x0F; /* claim: all states are supported */
1066 } else {
1067 arr[n++] = 0x0; /* Active/Optimized path */
1068 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1069 }
1070 arr[n++] = (port_group_a >> 8) & 0xff;
1071 arr[n++] = port_group_a & 0xff;
1072 arr[n++] = 0; /* Reserved */
1073 arr[n++] = 0; /* Status code */
1074 arr[n++] = 0; /* Vendor unique */
1075 arr[n++] = 0x1; /* One port per group */
1076 arr[n++] = 0; /* Reserved */
1077 arr[n++] = 0; /* Reserved */
1078 arr[n++] = (port_a >> 8) & 0xff;
1079 arr[n++] = port_a & 0xff;
1080 arr[n++] = 3; /* Port unavailable */
1081 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1082 arr[n++] = (port_group_b >> 8) & 0xff;
1083 arr[n++] = port_group_b & 0xff;
1084 arr[n++] = 0; /* Reserved */
1085 arr[n++] = 0; /* Status code */
1086 arr[n++] = 0; /* Vendor unique */
1087 arr[n++] = 0x1; /* One port per group */
1088 arr[n++] = 0; /* Reserved */
1089 arr[n++] = 0; /* Reserved */
1090 arr[n++] = (port_b >> 8) & 0xff;
1091 arr[n++] = port_b & 0xff;
1092
1093 rlen = n - 4;
1094 arr[0] = (rlen >> 24) & 0xff;
1095 arr[1] = (rlen >> 16) & 0xff;
1096 arr[2] = (rlen >> 8) & 0xff;
1097 arr[3] = rlen & 0xff;
1098
1099 /*
1100 * Return the smallest value of either
1101 * - The allocated length
1102 * - The constructed command length
1103 * - The maximum array size
1104 */
1105 rlen = min(alen,n);
1106 ret = fill_from_dev_buffer(scp, arr,
1107 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1108 kfree(arr);
1109 return ret;
1110}
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112/* <<Following mode page info copied from ST318451LW>> */
1113
1114static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1115{ /* Read-Write Error Recovery page for mode_sense */
1116 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1117 5, 0, 0xff, 0xff};
1118
1119 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1120 if (1 == pcontrol)
1121 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1122 return sizeof(err_recov_pg);
1123}
1124
1125static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1126{ /* Disconnect-Reconnect page for mode_sense */
1127 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1128 0, 0, 0, 0, 0, 0, 0, 0};
1129
1130 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1131 if (1 == pcontrol)
1132 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1133 return sizeof(disconnect_pg);
1134}
1135
1136static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1137{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001138 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1139 0, 0, 0, 0, 0, 0, 0, 0,
1140 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Martin K. Petersen597136a2008-06-05 00:12:59 -04001142 memcpy(p, format_pg, sizeof(format_pg));
1143 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1144 p[11] = sdebug_sectors_per & 0xff;
1145 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1146 p[13] = scsi_debug_sector_size & 0xff;
1147 if (DEV_REMOVEABLE(target))
1148 p[20] |= 0x20; /* should agree with INQUIRY */
1149 if (1 == pcontrol)
1150 memset(p + 2, 0, sizeof(format_pg) - 2);
1151 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152}
1153
1154static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1155{ /* Caching page for mode_sense */
1156 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1157 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1158
1159 memcpy(p, caching_pg, sizeof(caching_pg));
1160 if (1 == pcontrol)
1161 memset(p + 2, 0, sizeof(caching_pg) - 2);
1162 return sizeof(caching_pg);
1163}
1164
1165static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1166{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001167 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1168 0, 0, 0, 0};
1169 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 0, 0, 0x2, 0x4b};
1171
1172 if (scsi_debug_dsense)
1173 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001174 else
1175 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001176
1177 if (scsi_debug_ato)
1178 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1181 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001182 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1183 else if (2 == pcontrol)
1184 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 return sizeof(ctrl_m_pg);
1186}
1187
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001188
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1190{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001191 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1192 0, 0, 0x0, 0x0};
1193 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1194 0, 0, 0x0, 0x0};
1195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1197 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001198 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1199 else if (2 == pcontrol)
1200 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return sizeof(iec_m_pg);
1202}
1203
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001204static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1205{ /* SAS SSP mode page - short format for mode_sense */
1206 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1207 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1208
1209 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1210 if (1 == pcontrol)
1211 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1212 return sizeof(sas_sf_m_pg);
1213}
1214
1215
1216static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1217 int target_dev_id)
1218{ /* SAS phy control and discover mode page for mode_sense */
1219 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1220 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1221 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1222 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1223 0x2, 0, 0, 0, 0, 0, 0, 0,
1224 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1225 0, 0, 0, 0, 0, 0, 0, 0,
1226 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1227 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1228 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1229 0x3, 0, 0, 0, 0, 0, 0, 0,
1230 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1231 0, 0, 0, 0, 0, 0, 0, 0,
1232 };
1233 int port_a, port_b;
1234
1235 port_a = target_dev_id + 1;
1236 port_b = port_a + 1;
1237 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1238 p[20] = (port_a >> 24);
1239 p[21] = (port_a >> 16) & 0xff;
1240 p[22] = (port_a >> 8) & 0xff;
1241 p[23] = port_a & 0xff;
1242 p[48 + 20] = (port_b >> 24);
1243 p[48 + 21] = (port_b >> 16) & 0xff;
1244 p[48 + 22] = (port_b >> 8) & 0xff;
1245 p[48 + 23] = port_b & 0xff;
1246 if (1 == pcontrol)
1247 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1248 return sizeof(sas_pcd_m_pg);
1249}
1250
1251static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1252{ /* SAS SSP shared protocol specific port mode subpage */
1253 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1254 0, 0, 0, 0, 0, 0, 0, 0,
1255 };
1256
1257 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1258 if (1 == pcontrol)
1259 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1260 return sizeof(sas_sha_m_pg);
1261}
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263#define SDEBUG_MAX_MSENSE_SZ 256
1264
1265static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1266 struct sdebug_dev_info * devip)
1267{
Douglas Gilbert23183912006-09-16 20:30:47 -04001268 unsigned char dbd, llbaa;
1269 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001271 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 unsigned char * ap;
1273 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1274 unsigned char *cmd = (unsigned char *)scp->cmnd;
1275
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001276 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001278 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 pcontrol = (cmd[2] & 0xc0) >> 6;
1280 pcode = cmd[2] & 0x3f;
1281 subpcode = cmd[3];
1282 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001283 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1284 if ((0 == scsi_debug_ptype) && (0 == dbd))
1285 bd_len = llbaa ? 16 : 8;
1286 else
1287 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1289 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1290 if (0x3 == pcontrol) { /* Saving values not supported */
1291 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1292 0);
1293 return check_condition_result;
1294 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001295 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1296 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001297 /* set DPOFUA bit for disks */
1298 if (0 == scsi_debug_ptype)
1299 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1300 else
1301 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 if (msense_6) {
1303 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001304 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 offset = 4;
1306 } else {
1307 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001308 if (16 == bd_len)
1309 arr[4] = 0x1; /* set LONGLBA bit */
1310 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 offset = 8;
1312 }
1313 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001314 if ((bd_len > 0) && (!sdebug_capacity))
1315 sdebug_capacity = get_sdebug_capacity();
1316
Douglas Gilbert23183912006-09-16 20:30:47 -04001317 if (8 == bd_len) {
1318 if (sdebug_capacity > 0xfffffffe) {
1319 ap[0] = 0xff;
1320 ap[1] = 0xff;
1321 ap[2] = 0xff;
1322 ap[3] = 0xff;
1323 } else {
1324 ap[0] = (sdebug_capacity >> 24) & 0xff;
1325 ap[1] = (sdebug_capacity >> 16) & 0xff;
1326 ap[2] = (sdebug_capacity >> 8) & 0xff;
1327 ap[3] = sdebug_capacity & 0xff;
1328 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001329 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1330 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001331 offset += bd_len;
1332 ap = arr + offset;
1333 } else if (16 == bd_len) {
1334 unsigned long long capac = sdebug_capacity;
1335
1336 for (k = 0; k < 8; ++k, capac >>= 8)
1337 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001338 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1339 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1340 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1341 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001342 offset += bd_len;
1343 ap = arr + offset;
1344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001346 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1347 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1349 0);
1350 return check_condition_result;
1351 }
1352 switch (pcode) {
1353 case 0x1: /* Read-Write error recovery page, direct access */
1354 len = resp_err_recov_pg(ap, pcontrol, target);
1355 offset += len;
1356 break;
1357 case 0x2: /* Disconnect-Reconnect page, all devices */
1358 len = resp_disconnect_pg(ap, pcontrol, target);
1359 offset += len;
1360 break;
1361 case 0x3: /* Format device page, direct access */
1362 len = resp_format_pg(ap, pcontrol, target);
1363 offset += len;
1364 break;
1365 case 0x8: /* Caching page, direct access */
1366 len = resp_caching_pg(ap, pcontrol, target);
1367 offset += len;
1368 break;
1369 case 0xa: /* Control Mode page, all devices */
1370 len = resp_ctrl_m_pg(ap, pcontrol, target);
1371 offset += len;
1372 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001373 case 0x19: /* if spc==1 then sas phy, control+discover */
1374 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1375 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1376 INVALID_FIELD_IN_CDB, 0);
1377 return check_condition_result;
1378 }
1379 len = 0;
1380 if ((0x0 == subpcode) || (0xff == subpcode))
1381 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1382 if ((0x1 == subpcode) || (0xff == subpcode))
1383 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1384 target_dev_id);
1385 if ((0x2 == subpcode) || (0xff == subpcode))
1386 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1387 offset += len;
1388 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 case 0x1c: /* Informational Exceptions Mode page, all devices */
1390 len = resp_iec_m_pg(ap, pcontrol, target);
1391 offset += len;
1392 break;
1393 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001394 if ((0 == subpcode) || (0xff == subpcode)) {
1395 len = resp_err_recov_pg(ap, pcontrol, target);
1396 len += resp_disconnect_pg(ap + len, pcontrol, target);
1397 len += resp_format_pg(ap + len, pcontrol, target);
1398 len += resp_caching_pg(ap + len, pcontrol, target);
1399 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1400 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1401 if (0xff == subpcode) {
1402 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1403 target, target_dev_id);
1404 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1405 }
1406 len += resp_iec_m_pg(ap + len, pcontrol, target);
1407 } else {
1408 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1409 INVALID_FIELD_IN_CDB, 0);
1410 return check_condition_result;
1411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 offset += len;
1413 break;
1414 default:
1415 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1416 0);
1417 return check_condition_result;
1418 }
1419 if (msense_6)
1420 arr[0] = offset - 1;
1421 else {
1422 arr[0] = ((offset - 2) >> 8) & 0xff;
1423 arr[1] = (offset - 2) & 0xff;
1424 }
1425 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1426}
1427
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001428#define SDEBUG_MAX_MSELECT_SZ 512
1429
1430static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1431 struct sdebug_dev_info * devip)
1432{
1433 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1434 int param_len, res, errsts, mpage;
1435 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1436 unsigned char *cmd = (unsigned char *)scp->cmnd;
1437
1438 if ((errsts = check_readiness(scp, 1, devip)))
1439 return errsts;
1440 memset(arr, 0, sizeof(arr));
1441 pf = cmd[1] & 0x10;
1442 sp = cmd[1] & 0x1;
1443 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1444 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1445 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1446 INVALID_FIELD_IN_CDB, 0);
1447 return check_condition_result;
1448 }
1449 res = fetch_to_dev_buffer(scp, arr, param_len);
1450 if (-1 == res)
1451 return (DID_ERROR << 16);
1452 else if ((res < param_len) &&
1453 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1454 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1455 " IO sent=%d bytes\n", param_len, res);
1456 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1457 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001458 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001459 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1460 INVALID_FIELD_IN_PARAM_LIST, 0);
1461 return check_condition_result;
1462 }
1463 off = bd_len + (mselect6 ? 4 : 8);
1464 mpage = arr[off] & 0x3f;
1465 ps = !!(arr[off] & 0x80);
1466 if (ps) {
1467 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1468 INVALID_FIELD_IN_PARAM_LIST, 0);
1469 return check_condition_result;
1470 }
1471 spf = !!(arr[off] & 0x40);
1472 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1473 (arr[off + 1] + 2);
1474 if ((pg_len + off) > param_len) {
1475 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1476 PARAMETER_LIST_LENGTH_ERR, 0);
1477 return check_condition_result;
1478 }
1479 switch (mpage) {
1480 case 0xa: /* Control Mode page */
1481 if (ctrl_m_pg[1] == arr[off + 1]) {
1482 memcpy(ctrl_m_pg + 2, arr + off + 2,
1483 sizeof(ctrl_m_pg) - 2);
1484 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1485 return 0;
1486 }
1487 break;
1488 case 0x1c: /* Informational Exceptions Mode page */
1489 if (iec_m_pg[1] == arr[off + 1]) {
1490 memcpy(iec_m_pg + 2, arr + off + 2,
1491 sizeof(iec_m_pg) - 2);
1492 return 0;
1493 }
1494 break;
1495 default:
1496 break;
1497 }
1498 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1499 INVALID_FIELD_IN_PARAM_LIST, 0);
1500 return check_condition_result;
1501}
1502
1503static int resp_temp_l_pg(unsigned char * arr)
1504{
1505 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1506 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1507 };
1508
1509 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1510 return sizeof(temp_l_pg);
1511}
1512
1513static int resp_ie_l_pg(unsigned char * arr)
1514{
1515 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1516 };
1517
1518 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1519 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1520 arr[4] = THRESHOLD_EXCEEDED;
1521 arr[5] = 0xff;
1522 }
1523 return sizeof(ie_l_pg);
1524}
1525
1526#define SDEBUG_MAX_LSENSE_SZ 512
1527
1528static int resp_log_sense(struct scsi_cmnd * scp,
1529 struct sdebug_dev_info * devip)
1530{
Douglas Gilbert23183912006-09-16 20:30:47 -04001531 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001532 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1533 unsigned char *cmd = (unsigned char *)scp->cmnd;
1534
1535 if ((errsts = check_readiness(scp, 1, devip)))
1536 return errsts;
1537 memset(arr, 0, sizeof(arr));
1538 ppc = cmd[1] & 0x2;
1539 sp = cmd[1] & 0x1;
1540 if (ppc || sp) {
1541 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1542 INVALID_FIELD_IN_CDB, 0);
1543 return check_condition_result;
1544 }
1545 pcontrol = (cmd[2] & 0xc0) >> 6;
1546 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001547 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001548 alloc_len = (cmd[7] << 8) + cmd[8];
1549 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001550 if (0 == subpcode) {
1551 switch (pcode) {
1552 case 0x0: /* Supported log pages log page */
1553 n = 4;
1554 arr[n++] = 0x0; /* this page */
1555 arr[n++] = 0xd; /* Temperature */
1556 arr[n++] = 0x2f; /* Informational exceptions */
1557 arr[3] = n - 4;
1558 break;
1559 case 0xd: /* Temperature log page */
1560 arr[3] = resp_temp_l_pg(arr + 4);
1561 break;
1562 case 0x2f: /* Informational exceptions log page */
1563 arr[3] = resp_ie_l_pg(arr + 4);
1564 break;
1565 default:
1566 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1567 INVALID_FIELD_IN_CDB, 0);
1568 return check_condition_result;
1569 }
1570 } else if (0xff == subpcode) {
1571 arr[0] |= 0x40;
1572 arr[1] = subpcode;
1573 switch (pcode) {
1574 case 0x0: /* Supported log pages and subpages log page */
1575 n = 4;
1576 arr[n++] = 0x0;
1577 arr[n++] = 0x0; /* 0,0 page */
1578 arr[n++] = 0x0;
1579 arr[n++] = 0xff; /* this page */
1580 arr[n++] = 0xd;
1581 arr[n++] = 0x0; /* Temperature */
1582 arr[n++] = 0x2f;
1583 arr[n++] = 0x0; /* Informational exceptions */
1584 arr[3] = n - 4;
1585 break;
1586 case 0xd: /* Temperature subpages */
1587 n = 4;
1588 arr[n++] = 0xd;
1589 arr[n++] = 0x0; /* Temperature */
1590 arr[3] = n - 4;
1591 break;
1592 case 0x2f: /* Informational exceptions subpages */
1593 n = 4;
1594 arr[n++] = 0x2f;
1595 arr[n++] = 0x0; /* Informational exceptions */
1596 arr[3] = n - 4;
1597 break;
1598 default:
1599 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1600 INVALID_FIELD_IN_CDB, 0);
1601 return check_condition_result;
1602 }
1603 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001604 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1605 INVALID_FIELD_IN_CDB, 0);
1606 return check_condition_result;
1607 }
1608 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1609 return fill_from_dev_buffer(scp, arr,
1610 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1611}
1612
FUJITA Tomonori19789102008-03-30 00:59:56 +09001613static int check_device_access_params(struct sdebug_dev_info *devi,
1614 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001616 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001617 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 return check_condition_result;
1619 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001620 /* transfer length excessive (tie in to block limits VPD page) */
1621 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001622 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001623 return check_condition_result;
1624 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001625 return 0;
1626}
1627
1628static int do_device_access(struct scsi_cmnd *scmd,
1629 struct sdebug_dev_info *devi,
1630 unsigned long long lba, unsigned int num, int write)
1631{
1632 int ret;
1633 unsigned int block, rest = 0;
1634 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1635
1636 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1637
1638 block = do_div(lba, sdebug_store_sectors);
1639 if (block + num > sdebug_store_sectors)
1640 rest = block + num - sdebug_store_sectors;
1641
Martin K. Petersen597136a2008-06-05 00:12:59 -04001642 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1643 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001644 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001645 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001646
1647 return ret;
1648}
1649
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001650static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001651 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001652{
1653 unsigned int i, resid;
1654 struct scatterlist *psgl;
1655 struct sd_dif_tuple *sdt;
1656 sector_t sector;
1657 sector_t tmp_sec = start_sec;
1658 void *paddr;
1659
1660 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1661
1662 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1663
1664 for (i = 0 ; i < sectors ; i++) {
1665 u16 csum;
1666
1667 if (sdt[i].app_tag == 0xffff)
1668 continue;
1669
1670 sector = start_sec + i;
1671
1672 switch (scsi_debug_guard) {
1673 case 1:
1674 csum = ip_compute_csum(fake_storep +
1675 sector * scsi_debug_sector_size,
1676 scsi_debug_sector_size);
1677 break;
1678 case 0:
1679 csum = crc_t10dif(fake_storep +
1680 sector * scsi_debug_sector_size,
1681 scsi_debug_sector_size);
1682 csum = cpu_to_be16(csum);
1683 break;
1684 default:
1685 BUG();
1686 }
1687
1688 if (sdt[i].guard_tag != csum) {
1689 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1690 " rcvd 0x%04x, data 0x%04x\n", __func__,
1691 (unsigned long)sector,
1692 be16_to_cpu(sdt[i].guard_tag),
1693 be16_to_cpu(csum));
1694 dif_errors++;
1695 return 0x01;
1696 }
1697
Martin K. Petersen395cef02009-09-18 17:33:03 -04001698 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001699 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1700 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1701 __func__, (unsigned long)sector);
1702 dif_errors++;
1703 return 0x03;
1704 }
Martin K. Petersen395cef02009-09-18 17:33:03 -04001705
1706 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1707 be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
1708 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1709 __func__, (unsigned long)sector);
1710 dif_errors++;
1711 return 0x03;
1712 }
1713
1714 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001715 }
1716
1717 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1718 sector = start_sec;
1719
1720 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1721 int len = min(psgl->length, resid);
1722
1723 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1724 memcpy(paddr, dif_storep + dif_offset(sector), len);
1725
1726 sector += len >> 3;
1727 if (sector >= sdebug_store_sectors) {
1728 /* Force wrap */
1729 tmp_sec = sector;
1730 sector = do_div(tmp_sec, sdebug_store_sectors);
1731 }
1732 resid -= len;
1733 kunmap_atomic(paddr, KM_IRQ0);
1734 }
1735
1736 dix_reads++;
1737
1738 return 0;
1739}
1740
FUJITA Tomonori19789102008-03-30 00:59:56 +09001741static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001742 unsigned int num, struct sdebug_dev_info *devip,
1743 u32 ei_lba)
FUJITA Tomonori19789102008-03-30 00:59:56 +09001744{
1745 unsigned long iflags;
1746 int ret;
1747
1748 ret = check_device_access_params(devip, lba, num);
1749 if (ret)
1750 return ret;
1751
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001753 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1754 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1755 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1757 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001758 /* set info field and valid bit for fixed descriptor */
1759 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1760 devip->sense_buff[0] |= 0x80; /* Valid bit */
1761 ret = OPT_MEDIUM_ERR_ADDR;
1762 devip->sense_buff[3] = (ret >> 24) & 0xff;
1763 devip->sense_buff[4] = (ret >> 16) & 0xff;
1764 devip->sense_buff[5] = (ret >> 8) & 0xff;
1765 devip->sense_buff[6] = ret & 0xff;
1766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 return check_condition_result;
1768 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001769
1770 /* DIX + T10 DIF */
1771 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04001772 int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001773
1774 if (prot_ret) {
1775 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1776 return illegal_condition_result;
1777 }
1778 }
1779
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001781 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 read_unlock_irqrestore(&atomic_rw, iflags);
1783 return ret;
1784}
1785
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001786void dump_sector(unsigned char *buf, int len)
1787{
1788 int i, j;
1789
1790 printk(KERN_ERR ">>> Sector Dump <<<\n");
1791
1792 for (i = 0 ; i < len ; i += 16) {
1793 printk(KERN_ERR "%04d: ", i);
1794
1795 for (j = 0 ; j < 16 ; j++) {
1796 unsigned char c = buf[i+j];
1797 if (c >= 0x20 && c < 0x7e)
1798 printk(" %c ", buf[i+j]);
1799 else
1800 printk("%02x ", buf[i+j]);
1801 }
1802
1803 printk("\n");
1804 }
1805}
1806
1807static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001808 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001809{
1810 int i, j, ret;
1811 struct sd_dif_tuple *sdt;
1812 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1813 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1814 void *daddr, *paddr;
1815 sector_t tmp_sec = start_sec;
1816 sector_t sector;
1817 int ppage_offset;
1818 unsigned short csum;
1819
1820 sector = do_div(tmp_sec, sdebug_store_sectors);
1821
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001822 BUG_ON(scsi_sg_count(SCpnt) == 0);
1823 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1824
1825 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1826 ppage_offset = 0;
1827
1828 /* For each data page */
1829 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1830 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1831
1832 /* For each sector-sized chunk in data page */
1833 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1834
1835 /* If we're at the end of the current
1836 * protection page advance to the next one
1837 */
1838 if (ppage_offset >= psgl->length) {
1839 kunmap_atomic(paddr, KM_IRQ1);
1840 psgl = sg_next(psgl);
1841 BUG_ON(psgl == NULL);
1842 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1843 + psgl->offset;
1844 ppage_offset = 0;
1845 }
1846
1847 sdt = paddr + ppage_offset;
1848
1849 switch (scsi_debug_guard) {
1850 case 1:
1851 csum = ip_compute_csum(daddr,
1852 scsi_debug_sector_size);
1853 break;
1854 case 0:
1855 csum = cpu_to_be16(crc_t10dif(daddr,
1856 scsi_debug_sector_size));
1857 break;
1858 default:
1859 BUG();
1860 ret = 0;
1861 goto out;
1862 }
1863
1864 if (sdt->guard_tag != csum) {
1865 printk(KERN_ERR
1866 "%s: GUARD check failed on sector %lu " \
1867 "rcvd 0x%04x, calculated 0x%04x\n",
1868 __func__, (unsigned long)sector,
1869 be16_to_cpu(sdt->guard_tag),
1870 be16_to_cpu(csum));
1871 ret = 0x01;
1872 dump_sector(daddr, scsi_debug_sector_size);
1873 goto out;
1874 }
1875
Martin K. Petersen395cef02009-09-18 17:33:03 -04001876 if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001877 be32_to_cpu(sdt->ref_tag)
1878 != (start_sec & 0xffffffff)) {
1879 printk(KERN_ERR
1880 "%s: REF check failed on sector %lu\n",
1881 __func__, (unsigned long)sector);
1882 ret = 0x03;
1883 dump_sector(daddr, scsi_debug_sector_size);
1884 goto out;
1885 }
1886
Martin K. Petersen395cef02009-09-18 17:33:03 -04001887 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
1888 be32_to_cpu(sdt->ref_tag) != ei_lba) {
1889 printk(KERN_ERR
1890 "%s: REF check failed on sector %lu\n",
1891 __func__, (unsigned long)sector);
1892 ret = 0x03;
1893 dump_sector(daddr, scsi_debug_sector_size);
1894 goto out;
1895 }
1896
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001897 /* Would be great to copy this in bigger
1898 * chunks. However, for the sake of
1899 * correctness we need to verify each sector
1900 * before writing it to "stable" storage
1901 */
1902 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1903
1904 sector++;
1905
1906 if (sector == sdebug_store_sectors)
1907 sector = 0; /* Force wrap */
1908
1909 start_sec++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04001910 ei_lba++;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001911 daddr += scsi_debug_sector_size;
1912 ppage_offset += sizeof(struct sd_dif_tuple);
1913 }
1914
1915 kunmap_atomic(daddr, KM_IRQ0);
1916 }
1917
1918 kunmap_atomic(paddr, KM_IRQ1);
1919
1920 dix_writes++;
1921
1922 return 0;
1923
1924out:
1925 dif_errors++;
1926 kunmap_atomic(daddr, KM_IRQ0);
1927 kunmap_atomic(paddr, KM_IRQ1);
1928 return ret;
1929}
1930
Martin K. Petersen44d92692009-10-15 14:45:27 -04001931static unsigned int map_state(sector_t lba, unsigned int *num)
1932{
1933 unsigned int granularity, alignment, mapped;
1934 sector_t block, next, end;
1935
1936 granularity = scsi_debug_unmap_granularity;
1937 alignment = granularity - scsi_debug_unmap_alignment;
1938 block = lba + alignment;
1939 do_div(block, granularity);
1940
1941 mapped = test_bit(block, map_storep);
1942
1943 if (mapped)
1944 next = find_next_zero_bit(map_storep, map_size, block);
1945 else
1946 next = find_next_bit(map_storep, map_size, block);
1947
1948 end = next * granularity - scsi_debug_unmap_alignment;
1949 *num = end - lba;
1950
1951 return mapped;
1952}
1953
1954static void map_region(sector_t lba, unsigned int len)
1955{
1956 unsigned int granularity, alignment;
1957 sector_t end = lba + len;
1958
1959 granularity = scsi_debug_unmap_granularity;
1960 alignment = granularity - scsi_debug_unmap_alignment;
1961
1962 while (lba < end) {
1963 sector_t block, rem;
1964
1965 block = lba + alignment;
1966 rem = do_div(block, granularity);
1967
1968 set_bit(block, map_storep);
1969
1970 lba += granularity - rem;
1971 }
1972}
1973
1974static void unmap_region(sector_t lba, unsigned int len)
1975{
1976 unsigned int granularity, alignment;
1977 sector_t end = lba + len;
1978
1979 granularity = scsi_debug_unmap_granularity;
1980 alignment = granularity - scsi_debug_unmap_alignment;
1981
1982 while (lba < end) {
1983 sector_t block, rem;
1984
1985 block = lba + alignment;
1986 rem = do_div(block, granularity);
1987
1988 if (rem == 0 && lba + granularity <= end)
1989 clear_bit(block, map_storep);
1990
1991 lba += granularity - rem;
1992 }
1993}
1994
FUJITA Tomonori19789102008-03-30 00:59:56 +09001995static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
Martin K. Petersen395cef02009-09-18 17:33:03 -04001996 unsigned int num, struct sdebug_dev_info *devip,
1997 u32 ei_lba)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998{
1999 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002000 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
FUJITA Tomonori19789102008-03-30 00:59:56 +09002002 ret = check_device_access_params(devip, lba, num);
2003 if (ret)
2004 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002006 /* DIX + T10 DIF */
2007 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
Martin K. Petersen395cef02009-09-18 17:33:03 -04002008 int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002009
2010 if (prot_ret) {
2011 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
2012 return illegal_condition_result;
2013 }
2014 }
2015
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002017 ret = do_device_access(SCpnt, devip, lba, num, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002018 if (scsi_debug_unmap_granularity)
2019 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09002021 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002023 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002025 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04002026 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002027
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 return 0;
2029}
2030
Martin K. Petersen44d92692009-10-15 14:45:27 -04002031static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
2032 unsigned int num, struct sdebug_dev_info *devip,
2033 u32 ei_lba, unsigned int unmap)
2034{
2035 unsigned long iflags;
2036 unsigned long long i;
2037 int ret;
2038
2039 ret = check_device_access_params(devip, lba, num);
2040 if (ret)
2041 return ret;
2042
2043 write_lock_irqsave(&atomic_rw, iflags);
2044
2045 if (unmap && scsi_debug_unmap_granularity) {
2046 unmap_region(lba, num);
2047 goto out;
2048 }
2049
2050 /* Else fetch one logical block */
2051 ret = fetch_to_dev_buffer(scmd,
2052 fake_storep + (lba * scsi_debug_sector_size),
2053 scsi_debug_sector_size);
2054
2055 if (-1 == ret) {
2056 write_unlock_irqrestore(&atomic_rw, iflags);
2057 return (DID_ERROR << 16);
2058 } else if ((ret < (num * scsi_debug_sector_size)) &&
2059 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
2060 printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, "
2061 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
2062
2063 /* Copy first sector to remaining blocks */
2064 for (i = 1 ; i < num ; i++)
2065 memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size),
2066 fake_storep + (lba * scsi_debug_sector_size),
2067 scsi_debug_sector_size);
2068
2069 if (scsi_debug_unmap_granularity)
2070 map_region(lba, num);
2071out:
2072 write_unlock_irqrestore(&atomic_rw, iflags);
2073
2074 return 0;
2075}
2076
2077struct unmap_block_desc {
2078 __be64 lba;
2079 __be32 blocks;
2080 __be32 __reserved;
2081};
2082
2083static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
2084{
2085 unsigned char *buf;
2086 struct unmap_block_desc *desc;
2087 unsigned int i, payload_len, descriptors;
2088 int ret;
2089
2090 ret = check_readiness(scmd, 1, devip);
2091 if (ret)
2092 return ret;
2093
2094 payload_len = get_unaligned_be16(&scmd->cmnd[7]);
2095 BUG_ON(scsi_bufflen(scmd) != payload_len);
2096
2097 descriptors = (payload_len - 8) / 16;
2098
2099 buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
2100 if (!buf)
2101 return check_condition_result;
2102
2103 scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
2104
2105 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
2106 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
2107
2108 desc = (void *)&buf[8];
2109
2110 for (i = 0 ; i < descriptors ; i++) {
2111 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
2112 unsigned int num = get_unaligned_be32(&desc[i].blocks);
2113
2114 ret = check_device_access_params(devip, lba, num);
2115 if (ret)
2116 goto out;
2117
2118 unmap_region(lba, num);
2119 }
2120
2121 ret = 0;
2122
2123out:
2124 kfree(buf);
2125
2126 return ret;
2127}
2128
2129#define SDEBUG_GET_LBA_STATUS_LEN 32
2130
2131static int resp_get_lba_status(struct scsi_cmnd * scmd,
2132 struct sdebug_dev_info * devip)
2133{
2134 unsigned long long lba;
2135 unsigned int alloc_len, mapped, num;
2136 unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
2137 int ret;
2138
2139 ret = check_readiness(scmd, 1, devip);
2140 if (ret)
2141 return ret;
2142
2143 lba = get_unaligned_be64(&scmd->cmnd[2]);
2144 alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
2145
2146 if (alloc_len < 24)
2147 return 0;
2148
2149 ret = check_device_access_params(devip, lba, 1);
2150 if (ret)
2151 return ret;
2152
2153 mapped = map_state(lba, &num);
2154
2155 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
2156 put_unaligned_be32(16, &arr[0]); /* Parameter Data Length */
2157 put_unaligned_be64(lba, &arr[8]); /* LBA */
2158 put_unaligned_be32(num, &arr[16]); /* Number of blocks */
2159 arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
2160
2161 return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
2162}
2163
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002164#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
2166static int resp_report_luns(struct scsi_cmnd * scp,
2167 struct sdebug_dev_info * devip)
2168{
2169 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002170 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 unsigned char *cmd = (unsigned char *)scp->cmnd;
2172 int select_report = (int)cmd[2];
2173 struct scsi_lun *one_lun;
2174 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002175 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
2177 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002178 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
2180 0);
2181 return check_condition_result;
2182 }
2183 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
2184 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
2185 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002186 if (1 == select_report)
2187 lun_cnt = 0;
2188 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
2189 --lun_cnt;
2190 wlun = (select_report > 0) ? 1 : 0;
2191 num = lun_cnt + wlun;
2192 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
2193 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
2194 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
2195 sizeof(struct scsi_lun)), num);
2196 if (n < num) {
2197 wlun = 0;
2198 lun_cnt = n;
2199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002201 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
2202 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
2203 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
2204 i++, lun++) {
2205 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 if (upper)
2207 one_lun[i].scsi_lun[0] =
2208 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002209 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002211 if (wlun) {
2212 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
2213 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
2214 i++;
2215 }
2216 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217 return fill_from_dev_buffer(scp, arr,
2218 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
2219}
2220
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002221static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
2222 unsigned int num, struct sdebug_dev_info *devip)
2223{
2224 int i, j, ret = -1;
2225 unsigned char *kaddr, *buf;
2226 unsigned int offset;
2227 struct scatterlist *sg;
2228 struct scsi_data_buffer *sdb = scsi_in(scp);
2229
2230 /* better not to use temporary buffer. */
2231 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
2232 if (!buf)
2233 return ret;
2234
FUJITA Tomonori21a61822008-03-09 13:44:30 +09002235 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09002236
2237 offset = 0;
2238 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
2239 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
2240 if (!kaddr)
2241 goto out;
2242
2243 for (j = 0; j < sg->length; j++)
2244 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
2245
2246 offset += sg->length;
2247 kunmap_atomic(kaddr, KM_USER0);
2248 }
2249 ret = 0;
2250out:
2251 kfree(buf);
2252
2253 return ret;
2254}
2255
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256/* When timer goes off this function is called. */
2257static void timer_intr_handler(unsigned long indx)
2258{
2259 struct sdebug_queued_cmd * sqcp;
2260 unsigned long iflags;
2261
2262 if (indx >= SCSI_DEBUG_CANQUEUE) {
2263 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
2264 "large\n");
2265 return;
2266 }
2267 spin_lock_irqsave(&queued_arr_lock, iflags);
2268 sqcp = &queued_arr[(int)indx];
2269 if (! sqcp->in_use) {
2270 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
2271 "interrupt\n");
2272 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2273 return;
2274 }
2275 sqcp->in_use = 0;
2276 if (sqcp->done_funct) {
2277 sqcp->a_cmnd->result = sqcp->scsi_result;
2278 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2279 }
2280 sqcp->done_funct = NULL;
2281 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2282}
2283
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002285static struct sdebug_dev_info *
2286sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002287{
2288 struct sdebug_dev_info *devip;
2289
2290 devip = kzalloc(sizeof(*devip), flags);
2291 if (devip) {
2292 devip->sdbg_host = sdbg_host;
2293 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2294 }
2295 return devip;
2296}
2297
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2299{
2300 struct sdebug_host_info * sdbg_host;
2301 struct sdebug_dev_info * open_devip = NULL;
2302 struct sdebug_dev_info * devip =
2303 (struct sdebug_dev_info *)sdev->hostdata;
2304
2305 if (devip)
2306 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002307 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2308 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 printk(KERN_ERR "Host info NULL\n");
2310 return NULL;
2311 }
2312 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2313 if ((devip->used) && (devip->channel == sdev->channel) &&
2314 (devip->target == sdev->id) &&
2315 (devip->lun == sdev->lun))
2316 return devip;
2317 else {
2318 if ((!devip->used) && (!open_devip))
2319 open_devip = devip;
2320 }
2321 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002322 if (!open_devip) { /* try and make a new one */
2323 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2324 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002326 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 return NULL;
2328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002330
2331 open_devip->channel = sdev->channel;
2332 open_devip->target = sdev->id;
2333 open_devip->lun = sdev->lun;
2334 open_devip->sdbg_host = sdbg_host;
2335 open_devip->reset = 1;
2336 open_devip->used = 1;
2337 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2338 if (scsi_debug_dsense)
2339 open_devip->sense_buff[0] = 0x72;
2340 else {
2341 open_devip->sense_buff[0] = 0x70;
2342 open_devip->sense_buff[7] = 0xa;
2343 }
2344 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2345 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2346
2347 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348}
2349
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002350static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002352 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2353 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2354 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002355 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002356 return 0;
2357}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002359static int scsi_debug_slave_configure(struct scsi_device *sdp)
2360{
2361 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002362
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002364 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2365 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2366 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2367 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2368 devip = devInfoReg(sdp);
2369 if (NULL == devip)
2370 return 1; /* no resources, will be marked offline */
2371 sdp->hostdata = devip;
2372 if (sdp->host->cmd_per_lun)
2373 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2374 sdp->host->cmd_per_lun);
2375 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
2376 return 0;
2377}
2378
2379static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2380{
2381 struct sdebug_dev_info *devip =
2382 (struct sdebug_dev_info *)sdp->hostdata;
2383
2384 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2385 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2386 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2387 if (devip) {
2388 /* make this slot avaliable for re-use */
2389 devip->used = 0;
2390 sdp->hostdata = NULL;
2391 }
2392}
2393
2394/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2395static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2396{
2397 unsigned long iflags;
2398 int k;
2399 struct sdebug_queued_cmd *sqcp;
2400
2401 spin_lock_irqsave(&queued_arr_lock, iflags);
2402 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2403 sqcp = &queued_arr[k];
2404 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2405 del_timer_sync(&sqcp->cmnd_timer);
2406 sqcp->in_use = 0;
2407 sqcp->a_cmnd = NULL;
2408 break;
2409 }
2410 }
2411 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2412 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2413}
2414
2415/* Deletes (stops) timers of all queued commands */
2416static void stop_all_queued(void)
2417{
2418 unsigned long iflags;
2419 int k;
2420 struct sdebug_queued_cmd *sqcp;
2421
2422 spin_lock_irqsave(&queued_arr_lock, iflags);
2423 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2424 sqcp = &queued_arr[k];
2425 if (sqcp->in_use && sqcp->a_cmnd) {
2426 del_timer_sync(&sqcp->cmnd_timer);
2427 sqcp->in_use = 0;
2428 sqcp->a_cmnd = NULL;
2429 }
2430 }
2431 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432}
2433
2434static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2435{
2436 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2437 printk(KERN_INFO "scsi_debug: abort\n");
2438 ++num_aborts;
2439 stop_queued_cmnd(SCpnt);
2440 return SUCCESS;
2441}
2442
2443static int scsi_debug_biosparam(struct scsi_device *sdev,
2444 struct block_device * bdev, sector_t capacity, int *info)
2445{
2446 int res;
2447 unsigned char *buf;
2448
2449 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2450 printk(KERN_INFO "scsi_debug: biosparam\n");
2451 buf = scsi_bios_ptable(bdev);
2452 if (buf) {
2453 res = scsi_partsize(buf, capacity,
2454 &info[2], &info[0], &info[1]);
2455 kfree(buf);
2456 if (! res)
2457 return res;
2458 }
2459 info[0] = sdebug_heads;
2460 info[1] = sdebug_sectors_per;
2461 info[2] = sdebug_cylinders_per;
2462 return 0;
2463}
2464
2465static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2466{
2467 struct sdebug_dev_info * devip;
2468
2469 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2470 printk(KERN_INFO "scsi_debug: device_reset\n");
2471 ++num_dev_resets;
2472 if (SCpnt) {
2473 devip = devInfoReg(SCpnt->device);
2474 if (devip)
2475 devip->reset = 1;
2476 }
2477 return SUCCESS;
2478}
2479
2480static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2481{
2482 struct sdebug_host_info *sdbg_host;
2483 struct sdebug_dev_info * dev_info;
2484 struct scsi_device * sdp;
2485 struct Scsi_Host * hp;
2486
2487 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2488 printk(KERN_INFO "scsi_debug: bus_reset\n");
2489 ++num_bus_resets;
2490 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002491 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 if (sdbg_host) {
2493 list_for_each_entry(dev_info,
2494 &sdbg_host->dev_info_list,
2495 dev_list)
2496 dev_info->reset = 1;
2497 }
2498 }
2499 return SUCCESS;
2500}
2501
2502static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2503{
2504 struct sdebug_host_info * sdbg_host;
2505 struct sdebug_dev_info * dev_info;
2506
2507 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2508 printk(KERN_INFO "scsi_debug: host_reset\n");
2509 ++num_host_resets;
2510 spin_lock(&sdebug_host_list_lock);
2511 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2512 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2513 dev_list)
2514 dev_info->reset = 1;
2515 }
2516 spin_unlock(&sdebug_host_list_lock);
2517 stop_all_queued();
2518 return SUCCESS;
2519}
2520
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521/* Initializes timers in queued array */
2522static void __init init_all_queued(void)
2523{
2524 unsigned long iflags;
2525 int k;
2526 struct sdebug_queued_cmd * sqcp;
2527
2528 spin_lock_irqsave(&queued_arr_lock, iflags);
2529 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2530 sqcp = &queued_arr[k];
2531 init_timer(&sqcp->cmnd_timer);
2532 sqcp->in_use = 0;
2533 sqcp->a_cmnd = NULL;
2534 }
2535 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2536}
2537
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002538static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002539 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540{
2541 struct partition * pp;
2542 int starts[SDEBUG_MAX_PARTS + 2];
2543 int sectors_per_part, num_sectors, k;
2544 int heads_by_sects, start_sec, end_sec;
2545
2546 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002547 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 return;
2549 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2550 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2551 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2552 "partitions to %d\n", SDEBUG_MAX_PARTS);
2553 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002554 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 sectors_per_part = (num_sectors - sdebug_sectors_per)
2556 / scsi_debug_num_parts;
2557 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2558 starts[0] = sdebug_sectors_per;
2559 for (k = 1; k < scsi_debug_num_parts; ++k)
2560 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2561 * heads_by_sects;
2562 starts[scsi_debug_num_parts] = num_sectors;
2563 starts[scsi_debug_num_parts + 1] = 0;
2564
2565 ramp[510] = 0x55; /* magic partition markings */
2566 ramp[511] = 0xAA;
2567 pp = (struct partition *)(ramp + 0x1be);
2568 for (k = 0; starts[k + 1]; ++k, ++pp) {
2569 start_sec = starts[k];
2570 end_sec = starts[k + 1] - 1;
2571 pp->boot_ind = 0;
2572
2573 pp->cyl = start_sec / heads_by_sects;
2574 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2575 / sdebug_sectors_per;
2576 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2577
2578 pp->end_cyl = end_sec / heads_by_sects;
2579 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2580 / sdebug_sectors_per;
2581 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2582
2583 pp->start_sect = start_sec;
2584 pp->nr_sects = end_sec - start_sec + 1;
2585 pp->sys_ind = 0x83; /* plain Linux partition */
2586 }
2587}
2588
2589static int schedule_resp(struct scsi_cmnd * cmnd,
2590 struct sdebug_dev_info * devip,
2591 done_funct_t done, int scsi_result, int delta_jiff)
2592{
2593 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2594 if (scsi_result) {
2595 struct scsi_device * sdp = cmnd->device;
2596
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002597 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2598 "non-zero result=0x%x\n", sdp->host->host_no,
2599 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 }
2601 }
2602 if (cmnd && devip) {
2603 /* simulate autosense by this driver */
2604 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2605 memcpy(cmnd->sense_buffer, devip->sense_buff,
2606 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2607 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2608 }
2609 if (delta_jiff <= 0) {
2610 if (cmnd)
2611 cmnd->result = scsi_result;
2612 if (done)
2613 done(cmnd);
2614 return 0;
2615 } else {
2616 unsigned long iflags;
2617 int k;
2618 struct sdebug_queued_cmd * sqcp = NULL;
2619
2620 spin_lock_irqsave(&queued_arr_lock, iflags);
2621 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2622 sqcp = &queued_arr[k];
2623 if (! sqcp->in_use)
2624 break;
2625 }
2626 if (k >= SCSI_DEBUG_CANQUEUE) {
2627 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2628 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2629 return 1; /* report busy to mid level */
2630 }
2631 sqcp->in_use = 1;
2632 sqcp->a_cmnd = cmnd;
2633 sqcp->scsi_result = scsi_result;
2634 sqcp->done_funct = done;
2635 sqcp->cmnd_timer.function = timer_intr_handler;
2636 sqcp->cmnd_timer.data = k;
2637 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2638 add_timer(&sqcp->cmnd_timer);
2639 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2640 if (cmnd)
2641 cmnd->result = 0;
2642 return 0;
2643 }
2644}
Douglas Gilbert23183912006-09-16 20:30:47 -04002645/* Note: The following macros create attribute files in the
2646 /sys/module/scsi_debug/parameters directory. Unfortunately this
2647 driver is unaware of a change and cannot trigger auxiliary actions
2648 as it can when the corresponding attribute in the
2649 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2650 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002651module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2652module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2653module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2654module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2655module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002656module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002657module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2658module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2659module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2660module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2661module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2662module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2663module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2664module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002665module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2666 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002667module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002668module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2669module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2670module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2671module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002672module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2673module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002674module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
2675module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO);
2676module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
2677module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
2679MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2680MODULE_DESCRIPTION("SCSI debug adapter driver");
2681MODULE_LICENSE("GPL");
2682MODULE_VERSION(SCSI_DEBUG_VERSION);
2683
2684MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2685MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002686MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2687MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002688MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002689MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002690MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2691MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002693MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002694MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2696MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002697MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002698MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002699MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
2700MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
2701MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002702MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2703MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2704MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2705MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Martin K. Petersen44d92692009-10-15 14:45:27 -04002706MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0)");
2707MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=0)");
2708MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=0)");
2709MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710
2711static char sdebug_info[256];
2712
2713static const char * scsi_debug_info(struct Scsi_Host * shp)
2714{
2715 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2716 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2717 scsi_debug_version_date, scsi_debug_dev_size_mb,
2718 scsi_debug_opts);
2719 return sdebug_info;
2720}
2721
2722/* scsi_debug_proc_info
2723 * Used if the driver currently has no own support for /proc/scsi
2724 */
2725static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2726 int length, int inout)
2727{
2728 int len, pos, begin;
2729 int orig_length;
2730
2731 orig_length = length;
2732
2733 if (inout == 1) {
2734 char arr[16];
2735 int minLen = length > 15 ? 15 : length;
2736
2737 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2738 return -EACCES;
2739 memcpy(arr, buffer, minLen);
2740 arr[minLen] = '\0';
2741 if (1 != sscanf(arr, "%d", &pos))
2742 return -EINVAL;
2743 scsi_debug_opts = pos;
2744 if (scsi_debug_every_nth != 0)
2745 scsi_debug_cmnd_count = 0;
2746 return length;
2747 }
2748 begin = 0;
2749 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2750 "%s [%s]\n"
2751 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2752 "every_nth=%d(curr:%d)\n"
2753 "delay=%d, max_luns=%d, scsi_level=%d\n"
2754 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2755 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002756 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2758 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2759 scsi_debug_cmnd_count, scsi_debug_delay,
2760 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002761 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2762 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002763 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 if (pos < offset) {
2765 len = 0;
2766 begin = pos;
2767 }
2768 *start = buffer + (offset - begin); /* Start of wanted data */
2769 len -= (offset - begin);
2770 if (len > length)
2771 len = length;
2772 return len;
2773}
2774
2775static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2776{
2777 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2778}
2779
2780static ssize_t sdebug_delay_store(struct device_driver * ddp,
2781 const char * buf, size_t count)
2782{
2783 int delay;
2784 char work[20];
2785
2786 if (1 == sscanf(buf, "%10s", work)) {
2787 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2788 scsi_debug_delay = delay;
2789 return count;
2790 }
2791 }
2792 return -EINVAL;
2793}
2794DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2795 sdebug_delay_store);
2796
2797static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2798{
2799 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2800}
2801
2802static ssize_t sdebug_opts_store(struct device_driver * ddp,
2803 const char * buf, size_t count)
2804{
2805 int opts;
2806 char work[20];
2807
2808 if (1 == sscanf(buf, "%10s", work)) {
2809 if (0 == strnicmp(work,"0x", 2)) {
2810 if (1 == sscanf(&work[2], "%x", &opts))
2811 goto opts_done;
2812 } else {
2813 if (1 == sscanf(work, "%d", &opts))
2814 goto opts_done;
2815 }
2816 }
2817 return -EINVAL;
2818opts_done:
2819 scsi_debug_opts = opts;
2820 scsi_debug_cmnd_count = 0;
2821 return count;
2822}
2823DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2824 sdebug_opts_store);
2825
2826static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2827{
2828 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2829}
2830static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2831 const char * buf, size_t count)
2832{
2833 int n;
2834
2835 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2836 scsi_debug_ptype = n;
2837 return count;
2838 }
2839 return -EINVAL;
2840}
2841DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2842
2843static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2844{
2845 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2846}
2847static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2848 const char * buf, size_t count)
2849{
2850 int n;
2851
2852 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2853 scsi_debug_dsense = n;
2854 return count;
2855 }
2856 return -EINVAL;
2857}
2858DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2859 sdebug_dsense_store);
2860
Douglas Gilbert23183912006-09-16 20:30:47 -04002861static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2862{
2863 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2864}
2865static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2866 const char * buf, size_t count)
2867{
2868 int n;
2869
2870 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2871 scsi_debug_fake_rw = n;
2872 return count;
2873 }
2874 return -EINVAL;
2875}
2876DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2877 sdebug_fake_rw_store);
2878
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002879static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2880{
2881 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2882}
2883static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2884 const char * buf, size_t count)
2885{
2886 int n;
2887
2888 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2889 scsi_debug_no_lun_0 = n;
2890 return count;
2891 }
2892 return -EINVAL;
2893}
2894DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2895 sdebug_no_lun_0_store);
2896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2898{
2899 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2900}
2901static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2902 const char * buf, size_t count)
2903{
2904 int n;
2905
2906 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2907 scsi_debug_num_tgts = n;
2908 sdebug_max_tgts_luns();
2909 return count;
2910 }
2911 return -EINVAL;
2912}
2913DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2914 sdebug_num_tgts_store);
2915
2916static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2917{
2918 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2919}
2920DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2921
2922static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2923{
2924 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2925}
2926DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2927
2928static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2929{
2930 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2931}
2932static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2933 const char * buf, size_t count)
2934{
2935 int nth;
2936
2937 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2938 scsi_debug_every_nth = nth;
2939 scsi_debug_cmnd_count = 0;
2940 return count;
2941 }
2942 return -EINVAL;
2943}
2944DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2945 sdebug_every_nth_store);
2946
2947static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2948{
2949 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2950}
2951static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2952 const char * buf, size_t count)
2953{
2954 int n;
2955
2956 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2957 scsi_debug_max_luns = n;
2958 sdebug_max_tgts_luns();
2959 return count;
2960 }
2961 return -EINVAL;
2962}
2963DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2964 sdebug_max_luns_store);
2965
2966static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2967{
2968 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2969}
2970DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2971
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002972static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2973{
2974 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2975}
2976static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2977 const char * buf, size_t count)
2978{
2979 int n;
2980
2981 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2982 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002983
2984 sdebug_capacity = get_sdebug_capacity();
2985
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002986 return count;
2987 }
2988 return -EINVAL;
2989}
2990DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2991 sdebug_virtual_gb_store);
2992
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2994{
2995 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2996}
2997
2998static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2999 const char * buf, size_t count)
3000{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003001 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003003 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 if (delta_hosts > 0) {
3006 do {
3007 sdebug_add_adapter();
3008 } while (--delta_hosts);
3009 } else if (delta_hosts < 0) {
3010 do {
3011 sdebug_remove_adapter();
3012 } while (++delta_hosts);
3013 }
3014 return count;
3015}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09003016DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 sdebug_add_host_store);
3018
Douglas Gilbert23183912006-09-16 20:30:47 -04003019static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
3020 char * buf)
3021{
3022 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
3023}
3024static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
3025 const char * buf, size_t count)
3026{
3027 int n;
3028
3029 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
3030 scsi_debug_vpd_use_hostno = n;
3031 return count;
3032 }
3033 return -EINVAL;
3034}
3035DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
3036 sdebug_vpd_use_hostno_store);
3037
Martin K. Petersen597136a2008-06-05 00:12:59 -04003038static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
3039{
3040 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
3041}
3042DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
3043
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003044static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
3045{
3046 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
3047}
3048DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
3049
3050static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
3051{
3052 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
3053}
3054DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
3055
3056static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
3057{
3058 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
3059}
3060DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
3061
3062static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
3063{
3064 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
3065}
3066DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
3067
Martin K. Petersen44d92692009-10-15 14:45:27 -04003068static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)
3069{
3070 ssize_t count;
3071
3072 if (scsi_debug_unmap_granularity == 0)
3073 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
3074 sdebug_store_sectors);
3075
3076 count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
3077
3078 buf[count++] = '\n';
3079 buf[count++] = 0;
3080
3081 return count;
3082}
3083DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL);
3084
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003085
Douglas Gilbert23183912006-09-16 20:30:47 -04003086/* Note: The following function creates attribute files in the
3087 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
3088 files (over those found in the /sys/module/scsi_debug/parameters
3089 directory) is that auxiliary actions can be triggered when an attribute
3090 is changed. For example see: sdebug_add_host_store() above.
3091 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003092static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003094 int ret;
3095
3096 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3097 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
3098 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3099 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3100 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04003101 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003102 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003103 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003104 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003105 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003106 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
3107 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
3108 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04003109 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
3110 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003111 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003112 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
3113 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
3114 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
3115 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003116 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003117 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118}
3119
3120static void do_remove_driverfs_files(void)
3121{
Martin K. Petersen44d92692009-10-15 14:45:27 -04003122 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003123 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
3124 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
3125 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
3126 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04003127 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04003128 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
3129 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
3131 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
3132 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04003134 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
3135 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04003137 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
3139 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
3140 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
3141 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
3142 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
3143}
3144
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003145static void pseudo_0_release(struct device *dev)
3146{
3147 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3148 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
3149}
3150
3151static struct device pseudo_primary = {
Kay Sievers71610f52008-12-03 22:41:36 +01003152 .init_name = "pseudo_0",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003153 .release = pseudo_0_release,
3154};
3155
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156static int __init scsi_debug_init(void)
3157{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003158 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 int host_to_add;
3160 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003161 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
Martin K. Petersen597136a2008-06-05 00:12:59 -04003163 switch (scsi_debug_sector_size) {
3164 case 512:
3165 case 1024:
3166 case 2048:
3167 case 4096:
3168 break;
3169 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003170 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04003171 scsi_debug_sector_size);
3172 return -EINVAL;
3173 }
3174
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003175 switch (scsi_debug_dif) {
3176
3177 case SD_DIF_TYPE0_PROTECTION:
3178 case SD_DIF_TYPE1_PROTECTION:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003179 case SD_DIF_TYPE2_PROTECTION:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003180 case SD_DIF_TYPE3_PROTECTION:
3181 break;
3182
3183 default:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003184 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003185 return -EINVAL;
3186 }
3187
3188 if (scsi_debug_guard > 1) {
3189 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
3190 return -EINVAL;
3191 }
3192
3193 if (scsi_debug_ato > 1) {
3194 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
3195 return -EINVAL;
3196 }
3197
Martin K. Petersenea61fca2009-05-15 00:40:33 -04003198 if (scsi_debug_physblk_exp > 15) {
3199 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
3200 scsi_debug_physblk_exp);
3201 return -EINVAL;
3202 }
3203
3204 if (scsi_debug_lowest_aligned > 0x3fff) {
3205 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
3206 scsi_debug_lowest_aligned);
3207 return -EINVAL;
3208 }
3209
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 if (scsi_debug_dev_size_mb < 1)
3211 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09003212 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04003213 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09003214 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
3216 /* play around with geometry, don't waste too much on track 0 */
3217 sdebug_heads = 8;
3218 sdebug_sectors_per = 32;
3219 if (scsi_debug_dev_size_mb >= 16)
3220 sdebug_heads = 32;
3221 else if (scsi_debug_dev_size_mb >= 256)
3222 sdebug_heads = 64;
3223 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3224 (sdebug_sectors_per * sdebug_heads);
3225 if (sdebug_cylinders_per >= 1024) {
3226 /* other LLDs do this; implies >= 1GB ram disk ... */
3227 sdebug_heads = 255;
3228 sdebug_sectors_per = 63;
3229 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
3230 (sdebug_sectors_per * sdebug_heads);
3231 }
3232
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 fake_storep = vmalloc(sz);
3234 if (NULL == fake_storep) {
3235 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
3236 return -ENOMEM;
3237 }
3238 memset(fake_storep, 0, sz);
3239 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09003240 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003242 if (scsi_debug_dif) {
3243 int dif_size;
3244
3245 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
3246 dif_storep = vmalloc(dif_size);
3247
3248 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
3249 dif_size, dif_storep);
3250
3251 if (dif_storep == NULL) {
3252 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
3253 ret = -ENOMEM;
3254 goto free_vm;
3255 }
3256
3257 memset(dif_storep, 0xff, dif_size);
3258 }
3259
Martin K. Petersen44d92692009-10-15 14:45:27 -04003260 if (scsi_debug_unmap_granularity) {
3261 unsigned int map_bytes;
3262
3263 if (scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) {
3264 printk(KERN_ERR
3265 "%s: ERR: unmap_granularity < unmap_alignment\n",
3266 __func__);
3267 return -EINVAL;
3268 }
3269
3270 map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity);
3271 map_bytes = map_size >> 3;
3272 map_storep = vmalloc(map_bytes);
3273
3274 printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
3275 map_size);
3276
3277 if (map_storep == NULL) {
3278 printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n");
3279 ret = -ENOMEM;
3280 goto free_vm;
3281 }
3282
3283 memset(map_storep, 0x0, map_bytes);
3284
3285 /* Map first 1KB for partition table */
3286 if (scsi_debug_num_parts)
3287 map_region(0, 2);
3288 }
3289
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003290 ret = device_register(&pseudo_primary);
3291 if (ret < 0) {
3292 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
3293 ret);
3294 goto free_vm;
3295 }
3296 ret = bus_register(&pseudo_lld_bus);
3297 if (ret < 0) {
3298 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
3299 ret);
3300 goto dev_unreg;
3301 }
3302 ret = driver_register(&sdebug_driverfs_driver);
3303 if (ret < 0) {
3304 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
3305 ret);
3306 goto bus_unreg;
3307 }
3308 ret = do_create_driverfs_files();
3309 if (ret < 0) {
3310 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
3311 ret);
3312 goto del_files;
3313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003315 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 host_to_add = scsi_debug_add_host;
3318 scsi_debug_add_host = 0;
3319
3320 for (k = 0; k < host_to_add; k++) {
3321 if (sdebug_add_adapter()) {
3322 printk(KERN_ERR "scsi_debug_init: "
3323 "sdebug_add_adapter failed k=%d\n", k);
3324 break;
3325 }
3326 }
3327
3328 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
3329 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
3330 scsi_debug_add_host);
3331 }
3332 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003333
3334del_files:
3335 do_remove_driverfs_files();
3336 driver_unregister(&sdebug_driverfs_driver);
3337bus_unreg:
3338 bus_unregister(&pseudo_lld_bus);
3339dev_unreg:
3340 device_unregister(&pseudo_primary);
3341free_vm:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003342 if (map_storep)
3343 vfree(map_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003344 if (dif_storep)
3345 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003346 vfree(fake_storep);
3347
3348 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349}
3350
3351static void __exit scsi_debug_exit(void)
3352{
3353 int k = scsi_debug_add_host;
3354
3355 stop_all_queued();
3356 for (; k; k--)
3357 sdebug_remove_adapter();
3358 do_remove_driverfs_files();
3359 driver_unregister(&sdebug_driverfs_driver);
3360 bus_unregister(&pseudo_lld_bus);
3361 device_unregister(&pseudo_primary);
3362
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003363 if (dif_storep)
3364 vfree(dif_storep);
3365
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 vfree(fake_storep);
3367}
3368
3369device_initcall(scsi_debug_init);
3370module_exit(scsi_debug_exit);
3371
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372static void sdebug_release_adapter(struct device * dev)
3373{
3374 struct sdebug_host_info *sdbg_host;
3375
3376 sdbg_host = to_sdebug_host(dev);
3377 kfree(sdbg_host);
3378}
3379
3380static int sdebug_add_adapter(void)
3381{
3382 int k, devs_per_host;
3383 int error = 0;
3384 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003385 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003387 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 if (NULL == sdbg_host) {
3389 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003390 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 return -ENOMEM;
3392 }
3393
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3395
3396 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3397 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003398 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3399 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003401 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 error = -ENOMEM;
3403 goto clean;
3404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 }
3406
3407 spin_lock(&sdebug_host_list_lock);
3408 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3409 spin_unlock(&sdebug_host_list_lock);
3410
3411 sdbg_host->dev.bus = &pseudo_lld_bus;
3412 sdbg_host->dev.parent = &pseudo_primary;
3413 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003414 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415
3416 error = device_register(&sdbg_host->dev);
3417
3418 if (error)
3419 goto clean;
3420
3421 ++scsi_debug_add_host;
3422 return error;
3423
3424clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003425 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3426 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 list_del(&sdbg_devinfo->dev_list);
3428 kfree(sdbg_devinfo);
3429 }
3430
3431 kfree(sdbg_host);
3432 return error;
3433}
3434
3435static void sdebug_remove_adapter(void)
3436{
3437 struct sdebug_host_info * sdbg_host = NULL;
3438
3439 spin_lock(&sdebug_host_list_lock);
3440 if (!list_empty(&sdebug_host_list)) {
3441 sdbg_host = list_entry(sdebug_host_list.prev,
3442 struct sdebug_host_info, host_list);
3443 list_del(&sdbg_host->host_list);
3444 }
3445 spin_unlock(&sdebug_host_list_lock);
3446
3447 if (!sdbg_host)
3448 return;
3449
3450 device_unregister(&sdbg_host->dev);
3451 --scsi_debug_add_host;
3452}
3453
FUJITA Tomonori639db472008-03-20 11:09:19 +09003454static
3455int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
3456{
3457 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3458 int len, k;
3459 unsigned int num;
3460 unsigned long long lba;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003461 u32 ei_lba;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003462 int errsts = 0;
3463 int target = SCpnt->device->id;
3464 struct sdebug_dev_info *devip = NULL;
3465 int inj_recovered = 0;
3466 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003467 int inj_dif = 0;
3468 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003469 int delay_override = 0;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003470 int unmap = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003471
3472 scsi_set_resid(SCpnt, 0);
3473 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3474 printk(KERN_INFO "scsi_debug: cmd ");
3475 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3476 printk("%02x ", (int)cmd[k]);
3477 printk("\n");
3478 }
3479
3480 if (target == SCpnt->device->host->hostt->this_id) {
3481 printk(KERN_INFO "scsi_debug: initiator's id used as "
3482 "target!\n");
3483 return schedule_resp(SCpnt, NULL, done,
3484 DID_NO_CONNECT << 16, 0);
3485 }
3486
3487 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3488 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3489 return schedule_resp(SCpnt, NULL, done,
3490 DID_NO_CONNECT << 16, 0);
3491 devip = devInfoReg(SCpnt->device);
3492 if (NULL == devip)
3493 return schedule_resp(SCpnt, NULL, done,
3494 DID_NO_CONNECT << 16, 0);
3495
3496 if ((scsi_debug_every_nth != 0) &&
3497 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3498 scsi_debug_cmnd_count = 0;
3499 if (scsi_debug_every_nth < -1)
3500 scsi_debug_every_nth = -1;
3501 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3502 return 0; /* ignore command causing timeout */
3503 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3504 inj_recovered = 1; /* to reads and writes below */
3505 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3506 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003507 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3508 inj_dif = 1; /* to reads and writes below */
3509 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3510 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003511 }
3512
3513 if (devip->wlun) {
3514 switch (*cmd) {
3515 case INQUIRY:
3516 case REQUEST_SENSE:
3517 case TEST_UNIT_READY:
3518 case REPORT_LUNS:
3519 break; /* only allowable wlun commands */
3520 default:
3521 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3522 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3523 "not supported for wlun\n", *cmd);
3524 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3525 INVALID_OPCODE, 0);
3526 errsts = check_condition_result;
3527 return schedule_resp(SCpnt, devip, done, errsts,
3528 0);
3529 }
3530 }
3531
3532 switch (*cmd) {
3533 case INQUIRY: /* mandatory, ignore unit attention */
3534 delay_override = 1;
3535 errsts = resp_inquiry(SCpnt, target, devip);
3536 break;
3537 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3538 delay_override = 1;
3539 errsts = resp_requests(SCpnt, devip);
3540 break;
3541 case REZERO_UNIT: /* actually this is REWIND for SSC */
3542 case START_STOP:
3543 errsts = resp_start_stop(SCpnt, devip);
3544 break;
3545 case ALLOW_MEDIUM_REMOVAL:
3546 errsts = check_readiness(SCpnt, 1, devip);
3547 if (errsts)
3548 break;
3549 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3550 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3551 cmd[4] ? "inhibited" : "enabled");
3552 break;
3553 case SEND_DIAGNOSTIC: /* mandatory */
3554 errsts = check_readiness(SCpnt, 1, devip);
3555 break;
3556 case TEST_UNIT_READY: /* mandatory */
3557 delay_override = 1;
3558 errsts = check_readiness(SCpnt, 0, devip);
3559 break;
3560 case RESERVE:
3561 errsts = check_readiness(SCpnt, 1, devip);
3562 break;
3563 case RESERVE_10:
3564 errsts = check_readiness(SCpnt, 1, devip);
3565 break;
3566 case RELEASE:
3567 errsts = check_readiness(SCpnt, 1, devip);
3568 break;
3569 case RELEASE_10:
3570 errsts = check_readiness(SCpnt, 1, devip);
3571 break;
3572 case READ_CAPACITY:
3573 errsts = resp_readcap(SCpnt, devip);
3574 break;
3575 case SERVICE_ACTION_IN:
Martin K. Petersen44d92692009-10-15 14:45:27 -04003576 if (cmd[1] == SAI_READ_CAPACITY_16)
3577 errsts = resp_readcap16(SCpnt, devip);
3578 else if (cmd[1] == SAI_GET_LBA_STATUS) {
3579
3580 if (scsi_debug_unmap_max_desc == 0) {
3581 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3582 INVALID_COMMAND_OPCODE, 0);
3583 errsts = check_condition_result;
3584 } else
3585 errsts = resp_get_lba_status(SCpnt, devip);
3586 } else {
FUJITA Tomonori639db472008-03-20 11:09:19 +09003587 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3588 INVALID_OPCODE, 0);
3589 errsts = check_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003590 }
FUJITA Tomonori639db472008-03-20 11:09:19 +09003591 break;
3592 case MAINTENANCE_IN:
3593 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3594 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3595 INVALID_OPCODE, 0);
3596 errsts = check_condition_result;
3597 break;
3598 }
3599 errsts = resp_report_tgtpgs(SCpnt, devip);
3600 break;
3601 case READ_16:
3602 case READ_12:
3603 case READ_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003604 /* READ{10,12,16} and DIF Type 2 are natural enemies */
3605 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3606 cmd[1] & 0xe0) {
3607 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3608 INVALID_COMMAND_OPCODE, 0);
3609 errsts = check_condition_result;
3610 break;
3611 }
3612
3613 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3614 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3615 (cmd[1] & 0xe0) == 0)
3616 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3617
3618 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003619 case READ_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003620read:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003621 errsts = check_readiness(SCpnt, 0, devip);
3622 if (errsts)
3623 break;
3624 if (scsi_debug_fake_rw)
3625 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003626 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3627 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003628 if (inj_recovered && (0 == errsts)) {
3629 mk_sense_buffer(devip, RECOVERED_ERROR,
3630 THRESHOLD_EXCEEDED, 0);
3631 errsts = check_condition_result;
3632 } else if (inj_transport && (0 == errsts)) {
3633 mk_sense_buffer(devip, ABORTED_COMMAND,
3634 TRANSPORT_PROBLEM, ACK_NAK_TO);
3635 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003636 } else if (inj_dif && (0 == errsts)) {
3637 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3638 errsts = illegal_condition_result;
3639 } else if (inj_dix && (0 == errsts)) {
3640 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3641 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003642 }
3643 break;
3644 case REPORT_LUNS: /* mandatory, ignore unit attention */
3645 delay_override = 1;
3646 errsts = resp_report_luns(SCpnt, devip);
3647 break;
3648 case VERIFY: /* 10 byte SBC-2 command */
3649 errsts = check_readiness(SCpnt, 0, devip);
3650 break;
3651 case WRITE_16:
3652 case WRITE_12:
3653 case WRITE_10:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003654 /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
3655 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
3656 cmd[1] & 0xe0) {
3657 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3658 INVALID_COMMAND_OPCODE, 0);
3659 errsts = check_condition_result;
3660 break;
3661 }
3662
3663 if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
3664 scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
3665 (cmd[1] & 0xe0) == 0)
3666 printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
3667
3668 /* fall through */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003669 case WRITE_6:
Martin K. Petersen395cef02009-09-18 17:33:03 -04003670write:
FUJITA Tomonori639db472008-03-20 11:09:19 +09003671 errsts = check_readiness(SCpnt, 0, devip);
3672 if (errsts)
3673 break;
3674 if (scsi_debug_fake_rw)
3675 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003676 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3677 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003678 if (inj_recovered && (0 == errsts)) {
3679 mk_sense_buffer(devip, RECOVERED_ERROR,
3680 THRESHOLD_EXCEEDED, 0);
3681 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003682 } else if (inj_dif && (0 == errsts)) {
3683 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3684 errsts = illegal_condition_result;
3685 } else if (inj_dix && (0 == errsts)) {
3686 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3687 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003688 }
3689 break;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003690 case WRITE_SAME_16:
3691 if (cmd[1] & 0x8)
3692 unmap = 1;
3693 /* fall through */
3694 case WRITE_SAME:
3695 errsts = check_readiness(SCpnt, 0, devip);
3696 if (errsts)
3697 break;
3698 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3699 errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap);
3700 break;
3701 case UNMAP:
3702 errsts = check_readiness(SCpnt, 0, devip);
3703 if (errsts)
3704 break;
3705
3706 if (scsi_debug_unmap_max_desc == 0) {
3707 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3708 INVALID_COMMAND_OPCODE, 0);
3709 errsts = check_condition_result;
3710 } else
3711 errsts = resp_unmap(SCpnt, devip);
3712 break;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003713 case MODE_SENSE:
3714 case MODE_SENSE_10:
3715 errsts = resp_mode_sense(SCpnt, target, devip);
3716 break;
3717 case MODE_SELECT:
3718 errsts = resp_mode_select(SCpnt, 1, devip);
3719 break;
3720 case MODE_SELECT_10:
3721 errsts = resp_mode_select(SCpnt, 0, devip);
3722 break;
3723 case LOG_SENSE:
3724 errsts = resp_log_sense(SCpnt, devip);
3725 break;
3726 case SYNCHRONIZE_CACHE:
3727 delay_override = 1;
3728 errsts = check_readiness(SCpnt, 0, devip);
3729 break;
3730 case WRITE_BUFFER:
3731 errsts = check_readiness(SCpnt, 1, devip);
3732 break;
3733 case XDWRITEREAD_10:
3734 if (!scsi_bidi_cmnd(SCpnt)) {
3735 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3736 INVALID_FIELD_IN_CDB, 0);
3737 errsts = check_condition_result;
3738 break;
3739 }
3740
3741 errsts = check_readiness(SCpnt, 0, devip);
3742 if (errsts)
3743 break;
3744 if (scsi_debug_fake_rw)
3745 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003746 get_data_transfer_info(cmd, &lba, &num, &ei_lba);
3747 errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003748 if (errsts)
3749 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003750 errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
FUJITA Tomonori639db472008-03-20 11:09:19 +09003751 if (errsts)
3752 break;
3753 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3754 break;
Martin K. Petersen395cef02009-09-18 17:33:03 -04003755 case VARIABLE_LENGTH_CMD:
3756 if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
3757
3758 if ((cmd[10] & 0xe0) == 0)
3759 printk(KERN_ERR
3760 "Unprotected RD/WR to DIF device\n");
3761
3762 if (cmd[9] == READ_32) {
3763 BUG_ON(SCpnt->cmd_len < 32);
3764 goto read;
3765 }
3766
3767 if (cmd[9] == WRITE_32) {
3768 BUG_ON(SCpnt->cmd_len < 32);
3769 goto write;
3770 }
3771 }
3772
3773 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3774 INVALID_FIELD_IN_CDB, 0);
3775 errsts = check_condition_result;
3776 break;
3777
FUJITA Tomonori639db472008-03-20 11:09:19 +09003778 default:
3779 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3780 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3781 "supported\n", *cmd);
3782 errsts = check_readiness(SCpnt, 1, devip);
3783 if (errsts)
3784 break; /* Unit attention takes precedence */
3785 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3786 errsts = check_condition_result;
3787 break;
3788 }
3789 return schedule_resp(SCpnt, devip, done, errsts,
3790 (delay_override ? 0 : scsi_debug_delay));
3791}
3792
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003793static struct scsi_host_template sdebug_driver_template = {
3794 .proc_info = scsi_debug_proc_info,
3795 .proc_name = sdebug_proc_name,
3796 .name = "SCSI DEBUG",
3797 .info = scsi_debug_info,
3798 .slave_alloc = scsi_debug_slave_alloc,
3799 .slave_configure = scsi_debug_slave_configure,
3800 .slave_destroy = scsi_debug_slave_destroy,
3801 .ioctl = scsi_debug_ioctl,
3802 .queuecommand = scsi_debug_queuecommand,
3803 .eh_abort_handler = scsi_debug_abort,
3804 .eh_bus_reset_handler = scsi_debug_bus_reset,
3805 .eh_device_reset_handler = scsi_debug_device_reset,
3806 .eh_host_reset_handler = scsi_debug_host_reset,
3807 .bios_param = scsi_debug_biosparam,
3808 .can_queue = SCSI_DEBUG_CANQUEUE,
3809 .this_id = 7,
3810 .sg_tablesize = 256,
3811 .cmd_per_lun = 16,
3812 .max_sectors = 0xffff,
3813 .use_clustering = DISABLE_CLUSTERING,
3814 .module = THIS_MODULE,
3815};
3816
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817static int sdebug_driver_probe(struct device * dev)
3818{
3819 int error = 0;
3820 struct sdebug_host_info *sdbg_host;
3821 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003822 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823
3824 sdbg_host = to_sdebug_host(dev);
3825
3826 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3827 if (NULL == hpnt) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003828 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 error = -ENODEV;
3830 return error;
3831 }
3832
3833 sdbg_host->shost = hpnt;
3834 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3835 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3836 hpnt->max_id = scsi_debug_num_tgts + 1;
3837 else
3838 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003839 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003841 host_prot = 0;
3842
3843 switch (scsi_debug_dif) {
3844
3845 case SD_DIF_TYPE1_PROTECTION:
3846 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3847 if (scsi_debug_dix)
3848 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3849 break;
3850
3851 case SD_DIF_TYPE2_PROTECTION:
3852 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3853 if (scsi_debug_dix)
3854 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3855 break;
3856
3857 case SD_DIF_TYPE3_PROTECTION:
3858 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3859 if (scsi_debug_dix)
3860 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3861 break;
3862
3863 default:
3864 if (scsi_debug_dix)
3865 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3866 break;
3867 }
3868
3869 scsi_host_set_prot(hpnt, host_prot);
3870
3871 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3872 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3873 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3874 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3875 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3876 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3877 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3878 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3879
3880 if (scsi_debug_guard == 1)
3881 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3882 else
3883 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3884
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 error = scsi_add_host(hpnt, &sdbg_host->dev);
3886 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003887 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 error = -ENODEV;
3889 scsi_host_put(hpnt);
3890 } else
3891 scsi_scan_host(hpnt);
3892
3893
3894 return error;
3895}
3896
3897static int sdebug_driver_remove(struct device * dev)
3898{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003900 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901
3902 sdbg_host = to_sdebug_host(dev);
3903
3904 if (!sdbg_host) {
3905 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003906 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 return -ENODEV;
3908 }
3909
3910 scsi_remove_host(sdbg_host->shost);
3911
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003912 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3913 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 list_del(&sdbg_devinfo->dev_list);
3915 kfree(sdbg_devinfo);
3916 }
3917
3918 scsi_host_put(sdbg_host->shost);
3919 return 0;
3920}
3921
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003922static int pseudo_lld_bus_match(struct device *dev,
3923 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003925 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003927
3928static struct bus_type pseudo_lld_bus = {
3929 .name = "pseudo",
3930 .match = pseudo_lld_bus_match,
3931 .probe = sdebug_driver_probe,
3932 .remove = sdebug_driver_remove,
3933};