blob: 41a21772df1289525ad8859608d1d54c73461e76 [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
47#include <scsi/scsi.h>
48#include <scsi/scsi_cmnd.h>
49#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <scsi/scsi_host.h>
51#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090052#include <scsi/scsi_eh.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Martin K. Petersenc6a44282009-01-04 03:08:19 -050054#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050057#define SCSI_DEBUG_VERSION "1.81"
58static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050060/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040061#define NO_ADDITIONAL_SENSE 0x0
62#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040064#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define INVALID_OPCODE 0x20
66#define ADDR_OUT_OF_RANGE 0x21
67#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#define POWERON_RESET 0x29
70#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050071#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040072#define THRESHOLD_EXCEEDED 0x5d
73#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050075/* Additional Sense Code Qualifier (ASCQ) */
76#define ACK_NAK_TO 0x3
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
79
80/* Default values for driver parameters */
81#define DEF_NUM_HOST 1
82#define DEF_NUM_TGTS 1
83#define DEF_MAX_LUNS 1
84/* With these defaults, this driver will make 1 host with 1 target
85 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
86 */
87#define DEF_DELAY 1
88#define DEF_DEV_SIZE_MB 8
89#define DEF_EVERY_NTH 0
90#define DEF_NUM_PARTS 0
91#define DEF_OPTS 0
92#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
93#define DEF_PTYPE 0
94#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040095#define DEF_NO_LUN_0 0
96#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040097#define DEF_FAKE_RW 0
98#define DEF_VPD_USE_HOSTNO 1
Martin K. Petersen597136a2008-06-05 00:12:59 -040099#define DEF_SECTOR_SIZE 512
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500100#define DEF_DIX 0
101#define DEF_DIF 0
102#define DEF_GUARD 0
103#define DEF_ATO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
105/* bit mask values for scsi_debug_opts */
106#define SCSI_DEBUG_OPT_NOISE 1
107#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
108#define SCSI_DEBUG_OPT_TIMEOUT 4
109#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500110#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500111#define SCSI_DEBUG_OPT_DIF_ERR 32
112#define SCSI_DEBUG_OPT_DIX_ERR 64
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/* When "every_nth" > 0 then modulo "every_nth" commands:
114 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
115 * - a RECOVERED_ERROR is simulated on successful read and write
116 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500117 * - a TRANSPORT_ERROR is simulated on successful read and write
118 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 *
120 * When "every_nth" < 0 then after "- every_nth" commands:
121 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
122 * - a RECOVERED_ERROR is simulated on successful read and write
123 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500124 * - a TRANSPORT_ERROR is simulated on successful read and write
125 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 * This will continue until some other action occurs (e.g. the user
127 * writing a new value (other than -1 or 1) to every_nth via sysfs).
128 */
129
130/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
131 * sector on read commands: */
132#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
133
134/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
135 * or "peripheral device" addressing (value 0) */
136#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400137#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139static int scsi_debug_add_host = DEF_NUM_HOST;
140static int scsi_debug_delay = DEF_DELAY;
141static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
142static int scsi_debug_every_nth = DEF_EVERY_NTH;
143static int scsi_debug_max_luns = DEF_MAX_LUNS;
144static int scsi_debug_num_parts = DEF_NUM_PARTS;
145static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
146static int scsi_debug_opts = DEF_OPTS;
147static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
148static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
149static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400150static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
151static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400152static int scsi_debug_fake_rw = DEF_FAKE_RW;
153static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400154static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500155static int scsi_debug_dix = DEF_DIX;
156static int scsi_debug_dif = DEF_DIF;
157static int scsi_debug_guard = DEF_GUARD;
158static int scsi_debug_ato = DEF_ATO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
160static int scsi_debug_cmnd_count = 0;
161
162#define DEV_READONLY(TGT) (0)
163#define DEV_REMOVEABLE(TGT) (0)
164
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400165static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166static sector_t sdebug_capacity; /* in sectors */
167
168/* old BIOS stuff, kernel may get rid of them but some mode sense pages
169 may still need them */
170static int sdebug_heads; /* heads per disk */
171static int sdebug_cylinders_per; /* cylinders per surface */
172static int sdebug_sectors_per; /* sectors per cylinder */
173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174#define SDEBUG_MAX_PARTS 4
175
176#define SDEBUG_SENSE_LEN 32
177
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900178#define SCSI_DEBUG_CANQUEUE 255
179#define SCSI_DEBUG_MAX_CMD_LEN 16
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181struct sdebug_dev_info {
182 struct list_head dev_list;
183 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
184 unsigned int channel;
185 unsigned int target;
186 unsigned int lun;
187 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400188 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400190 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 char used;
192};
193
194struct sdebug_host_info {
195 struct list_head host_list;
196 struct Scsi_Host *shost;
197 struct device dev;
198 struct list_head dev_info_list;
199};
200
201#define to_sdebug_host(d) \
202 container_of(d, struct sdebug_host_info, dev)
203
204static LIST_HEAD(sdebug_host_list);
205static DEFINE_SPINLOCK(sdebug_host_list_lock);
206
207typedef void (* done_funct_t) (struct scsi_cmnd *);
208
209struct sdebug_queued_cmd {
210 int in_use;
211 struct timer_list cmnd_timer;
212 done_funct_t done_funct;
213 struct scsi_cmnd * a_cmnd;
214 int scsi_result;
215};
216static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218static unsigned char * fake_storep; /* ramdisk storage */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500219static unsigned char *dif_storep; /* protection info */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221static int num_aborts = 0;
222static int num_dev_resets = 0;
223static int num_bus_resets = 0;
224static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500225static int dix_writes;
226static int dix_reads;
227static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229static DEFINE_SPINLOCK(queued_arr_lock);
230static DEFINE_RWLOCK(atomic_rw);
231
232static char sdebug_proc_name[] = "scsi_debug";
233
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234static struct bus_type pseudo_lld_bus;
235
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500236static inline sector_t dif_offset(sector_t sector)
237{
238 return sector << 3;
239}
240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241static struct device_driver sdebug_driverfs_driver = {
242 .name = sdebug_proc_name,
243 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244};
245
246static const int check_condition_result =
247 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
248
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500249static const int illegal_condition_result =
250 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
251
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400252static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
253 0, 0, 0x2, 0x4b};
254static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
255 0, 0, 0x0, 0x0};
256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257static int sdebug_add_adapter(void);
258static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900260static void sdebug_max_tgts_luns(void)
261{
262 struct sdebug_host_info *sdbg_host;
263 struct Scsi_Host *hpnt;
264
265 spin_lock(&sdebug_host_list_lock);
266 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
267 hpnt = sdbg_host->shost;
268 if ((hpnt->this_id >= 0) &&
269 (scsi_debug_num_tgts > hpnt->this_id))
270 hpnt->max_id = scsi_debug_num_tgts + 1;
271 else
272 hpnt->max_id = scsi_debug_num_tgts;
273 /* scsi_debug_max_luns; */
274 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
275 }
276 spin_unlock(&sdebug_host_list_lock);
277}
278
279static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
280 int asc, int asq)
281{
282 unsigned char *sbuff;
283
284 sbuff = devip->sense_buff;
285 memset(sbuff, 0, SDEBUG_SENSE_LEN);
286
287 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
288
289 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
290 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
291 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
292}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900294static void get_data_transfer_info(unsigned char *cmd,
295 unsigned long long *lba, unsigned int *num)
296{
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900297 switch (*cmd) {
298 case WRITE_16:
299 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900300 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
301 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
302 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
303 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
304
305 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
306 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900307 break;
308 case WRITE_12:
309 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900310 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
311 (u32)cmd[2] << 24;
312
313 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
314 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900315 break;
316 case WRITE_10:
317 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900318 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900319 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
320 (u32)cmd[2] << 24;
321
322 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900323 break;
324 case WRITE_6:
325 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900326 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
327 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900328 *num = (0 == cmd[4]) ? 256 : cmd[4];
329 break;
330 default:
331 break;
332 }
333}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
336{
337 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
338 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
339 }
340 return -EINVAL;
341 /* return -ENOTTY; // correct return but upsets fdisk */
342}
343
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400344static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
345 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
347 if (devip->reset) {
348 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
349 printk(KERN_INFO "scsi_debug: Reporting Unit "
350 "attention: power on reset\n");
351 devip->reset = 0;
352 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
353 return check_condition_result;
354 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400355 if ((0 == reset_only) && devip->stopped) {
356 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
357 printk(KERN_INFO "scsi_debug: Reporting Not "
358 "ready: initializing command required\n");
359 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
360 0x2);
361 return check_condition_result;
362 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 return 0;
364}
365
366/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900367static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 int arr_len)
369{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900370 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900371 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900373 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900375 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900377
378 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
379 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900380 if (sdb->resid)
381 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400382 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900383 sdb->resid = scsi_bufflen(scp) - act_len;
384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 return 0;
386}
387
388/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900389static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
390 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900392 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900394 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900396
397 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398}
399
400
401static const char * inq_vendor_id = "Linux ";
402static const char * inq_product_id = "scsi_debug ";
403static const char * inq_product_rev = "0004";
404
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200405static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
406 int target_dev_id, int dev_id_num,
407 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400408 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400410 int num, port_a;
411 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400413 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 /* T10 vendor identifier field format (faked) */
415 arr[0] = 0x2; /* ASCII */
416 arr[1] = 0x1;
417 arr[2] = 0x0;
418 memcpy(&arr[4], inq_vendor_id, 8);
419 memcpy(&arr[12], inq_product_id, 16);
420 memcpy(&arr[28], dev_id_str, dev_id_str_len);
421 num = 8 + 16 + dev_id_str_len;
422 arr[3] = num;
423 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 if (dev_id_num >= 0) {
425 /* NAA-5, Logical unit identifier (binary) */
426 arr[num++] = 0x1; /* binary (not necessarily sas) */
427 arr[num++] = 0x3; /* PIV=0, lu, naa */
428 arr[num++] = 0x0;
429 arr[num++] = 0x8;
430 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
431 arr[num++] = 0x33;
432 arr[num++] = 0x33;
433 arr[num++] = 0x30;
434 arr[num++] = (dev_id_num >> 24);
435 arr[num++] = (dev_id_num >> 16) & 0xff;
436 arr[num++] = (dev_id_num >> 8) & 0xff;
437 arr[num++] = dev_id_num & 0xff;
438 /* Target relative port number */
439 arr[num++] = 0x61; /* proto=sas, binary */
440 arr[num++] = 0x94; /* PIV=1, target port, rel port */
441 arr[num++] = 0x0; /* reserved */
442 arr[num++] = 0x4; /* length */
443 arr[num++] = 0x0; /* reserved */
444 arr[num++] = 0x0; /* reserved */
445 arr[num++] = 0x0;
446 arr[num++] = 0x1; /* relative port A */
447 }
448 /* NAA-5, Target port identifier */
449 arr[num++] = 0x61; /* proto=sas, binary */
450 arr[num++] = 0x93; /* piv=1, target port, naa */
451 arr[num++] = 0x0;
452 arr[num++] = 0x8;
453 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
454 arr[num++] = 0x22;
455 arr[num++] = 0x22;
456 arr[num++] = 0x20;
457 arr[num++] = (port_a >> 24);
458 arr[num++] = (port_a >> 16) & 0xff;
459 arr[num++] = (port_a >> 8) & 0xff;
460 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200461 /* NAA-5, Target port group identifier */
462 arr[num++] = 0x61; /* proto=sas, binary */
463 arr[num++] = 0x95; /* piv=1, target port group id */
464 arr[num++] = 0x0;
465 arr[num++] = 0x4;
466 arr[num++] = 0;
467 arr[num++] = 0;
468 arr[num++] = (port_group_id >> 8) & 0xff;
469 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400470 /* NAA-5, Target device identifier */
471 arr[num++] = 0x61; /* proto=sas, binary */
472 arr[num++] = 0xa3; /* piv=1, target device, naa */
473 arr[num++] = 0x0;
474 arr[num++] = 0x8;
475 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
476 arr[num++] = 0x22;
477 arr[num++] = 0x22;
478 arr[num++] = 0x20;
479 arr[num++] = (target_dev_id >> 24);
480 arr[num++] = (target_dev_id >> 16) & 0xff;
481 arr[num++] = (target_dev_id >> 8) & 0xff;
482 arr[num++] = target_dev_id & 0xff;
483 /* SCSI name string: Target device identifier */
484 arr[num++] = 0x63; /* proto=sas, UTF-8 */
485 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
486 arr[num++] = 0x0;
487 arr[num++] = 24;
488 memcpy(arr + num, "naa.52222220", 12);
489 num += 12;
490 snprintf(b, sizeof(b), "%08X", target_dev_id);
491 memcpy(arr + num, b, 8);
492 num += 8;
493 memset(arr + num, 0, 4);
494 num += 4;
495 return num;
496}
497
498
499static unsigned char vpd84_data[] = {
500/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
501 0x22,0x22,0x22,0x0,0xbb,0x1,
502 0x22,0x22,0x22,0x0,0xbb,0x2,
503};
504
505static int inquiry_evpd_84(unsigned char * arr)
506{
507 memcpy(arr, vpd84_data, sizeof(vpd84_data));
508 return sizeof(vpd84_data);
509}
510
511static int inquiry_evpd_85(unsigned char * arr)
512{
513 int num = 0;
514 const char * na1 = "https://www.kernel.org/config";
515 const char * na2 = "http://www.kernel.org/log";
516 int plen, olen;
517
518 arr[num++] = 0x1; /* lu, storage config */
519 arr[num++] = 0x0; /* reserved */
520 arr[num++] = 0x0;
521 olen = strlen(na1);
522 plen = olen + 1;
523 if (plen % 4)
524 plen = ((plen / 4) + 1) * 4;
525 arr[num++] = plen; /* length, null termianted, padded */
526 memcpy(arr + num, na1, olen);
527 memset(arr + num + olen, 0, plen - olen);
528 num += plen;
529
530 arr[num++] = 0x4; /* lu, logging */
531 arr[num++] = 0x0; /* reserved */
532 arr[num++] = 0x0;
533 olen = strlen(na2);
534 plen = olen + 1;
535 if (plen % 4)
536 plen = ((plen / 4) + 1) * 4;
537 arr[num++] = plen; /* length, null terminated, padded */
538 memcpy(arr + num, na2, olen);
539 memset(arr + num + olen, 0, plen - olen);
540 num += plen;
541
542 return num;
543}
544
545/* SCSI ports VPD page */
546static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
547{
548 int num = 0;
549 int port_a, port_b;
550
551 port_a = target_dev_id + 1;
552 port_b = port_a + 1;
553 arr[num++] = 0x0; /* reserved */
554 arr[num++] = 0x0; /* reserved */
555 arr[num++] = 0x0;
556 arr[num++] = 0x1; /* relative port 1 (primary) */
557 memset(arr + num, 0, 6);
558 num += 6;
559 arr[num++] = 0x0;
560 arr[num++] = 12; /* length tp descriptor */
561 /* naa-5 target port identifier (A) */
562 arr[num++] = 0x61; /* proto=sas, binary */
563 arr[num++] = 0x93; /* PIV=1, target port, NAA */
564 arr[num++] = 0x0; /* reserved */
565 arr[num++] = 0x8; /* length */
566 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
567 arr[num++] = 0x22;
568 arr[num++] = 0x22;
569 arr[num++] = 0x20;
570 arr[num++] = (port_a >> 24);
571 arr[num++] = (port_a >> 16) & 0xff;
572 arr[num++] = (port_a >> 8) & 0xff;
573 arr[num++] = port_a & 0xff;
574
575 arr[num++] = 0x0; /* reserved */
576 arr[num++] = 0x0; /* reserved */
577 arr[num++] = 0x0;
578 arr[num++] = 0x2; /* relative port 2 (secondary) */
579 memset(arr + num, 0, 6);
580 num += 6;
581 arr[num++] = 0x0;
582 arr[num++] = 12; /* length tp descriptor */
583 /* naa-5 target port identifier (B) */
584 arr[num++] = 0x61; /* proto=sas, binary */
585 arr[num++] = 0x93; /* PIV=1, target port, NAA */
586 arr[num++] = 0x0; /* reserved */
587 arr[num++] = 0x8; /* length */
588 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
589 arr[num++] = 0x22;
590 arr[num++] = 0x22;
591 arr[num++] = 0x20;
592 arr[num++] = (port_b >> 24);
593 arr[num++] = (port_b >> 16) & 0xff;
594 arr[num++] = (port_b >> 8) & 0xff;
595 arr[num++] = port_b & 0xff;
596
597 return num;
598}
599
600
601static unsigned char vpd89_data[] = {
602/* from 4th byte */ 0,0,0,0,
603'l','i','n','u','x',' ',' ',' ',
604'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
605'1','2','3','4',
6060x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6070xec,0,0,0,
6080x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6090,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6100x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6110x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6120x53,0x41,
6130x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6140x20,0x20,
6150x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6160x10,0x80,
6170,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6180x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6190x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6200,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6210x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6220x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6230,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6250,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6260,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6270x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6280,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6290xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6300,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6310,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6320,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6330,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6370,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6380,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6390,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6420,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
643};
644
645static int inquiry_evpd_89(unsigned char * arr)
646{
647 memcpy(arr, vpd89_data, sizeof(vpd89_data));
648 return sizeof(vpd89_data);
649}
650
651
652static unsigned char vpdb0_data[] = {
653 /* from 4th byte */ 0,0,0,4,
654 0,0,0x4,0,
655 0,0,0,64,
656};
657
658static int inquiry_evpd_b0(unsigned char * arr)
659{
660 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
661 if (sdebug_store_sectors > 0x400) {
662 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
663 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
664 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
665 arr[7] = sdebug_store_sectors & 0xff;
666 }
667 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668}
669
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600670static int inquiry_evpd_b1(unsigned char *arr)
671{
672 memset(arr, 0, 0x3c);
673 arr[0] = 0;
674 arr[1] = 1;
675
676 return 0x3c;
677}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400680#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
682static int resp_inquiry(struct scsi_cmnd * scp, int target,
683 struct sdebug_dev_info * devip)
684{
685 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200686 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200688 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500691 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
692 if (! arr)
693 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400694 if (devip->wlun)
695 pq_pdt = 0x1e; /* present, wlun */
696 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
697 pq_pdt = 0x7f; /* not present, no device type */
698 else
699 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 arr[0] = pq_pdt;
701 if (0x2 & cmd[1]) { /* CMDDT bit set */
702 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
703 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200704 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return check_condition_result;
706 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200707 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400708 char lu_id_str[6];
709 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200711 port_group_id = (((host_no + 1) & 0x7f) << 8) +
712 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400713 if (0 == scsi_debug_vpd_use_hostno)
714 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400715 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
716 (devip->target * 1000) + devip->lun);
717 target_dev_id = ((host_no + 1) * 2000) +
718 (devip->target * 1000) - 3;
719 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400721 arr[1] = cmd[2]; /*sanity */
722 n = 4;
723 arr[n++] = 0x0; /* this page */
724 arr[n++] = 0x80; /* unit serial number */
725 arr[n++] = 0x83; /* device identification */
726 arr[n++] = 0x84; /* software interface ident. */
727 arr[n++] = 0x85; /* management network addresses */
728 arr[n++] = 0x86; /* extended inquiry */
729 arr[n++] = 0x87; /* mode page policy */
730 arr[n++] = 0x88; /* SCSI ports */
731 arr[n++] = 0x89; /* ATA information */
732 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600733 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400734 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400736 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400738 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400740 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200741 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
742 target_dev_id, lu_id_num,
743 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400744 } else if (0x84 == cmd[2]) { /* Software interface ident. */
745 arr[1] = cmd[2]; /*sanity */
746 arr[3] = inquiry_evpd_84(&arr[4]);
747 } else if (0x85 == cmd[2]) { /* Management network addresses */
748 arr[1] = cmd[2]; /*sanity */
749 arr[3] = inquiry_evpd_85(&arr[4]);
750 } else if (0x86 == cmd[2]) { /* extended inquiry */
751 arr[1] = cmd[2]; /*sanity */
752 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500753 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
754 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
755 else if (scsi_debug_dif)
756 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
757 else
758 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400759 arr[5] = 0x7; /* head of q, ordered + simple q's */
760 } else if (0x87 == cmd[2]) { /* mode page policy */
761 arr[1] = cmd[2]; /*sanity */
762 arr[3] = 0x8; /* number of following entries */
763 arr[4] = 0x2; /* disconnect-reconnect mp */
764 arr[6] = 0x80; /* mlus, shared */
765 arr[8] = 0x18; /* protocol specific lu */
766 arr[10] = 0x82; /* mlus, per initiator port */
767 } else if (0x88 == cmd[2]) { /* SCSI Ports */
768 arr[1] = cmd[2]; /*sanity */
769 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
770 } else if (0x89 == cmd[2]) { /* ATA information */
771 arr[1] = cmd[2]; /*sanity */
772 n = inquiry_evpd_89(&arr[4]);
773 arr[2] = (n >> 8);
774 arr[3] = (n & 0xff);
775 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
776 arr[1] = cmd[2]; /*sanity */
777 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600778 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
779 arr[1] = cmd[2]; /*sanity */
780 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 } else {
782 /* Illegal request, invalid field in cdb */
783 mk_sense_buffer(devip, ILLEGAL_REQUEST,
784 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200785 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return check_condition_result;
787 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400788 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200789 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400790 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200791 kfree(arr);
792 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794 /* drops through here for a standard inquiry */
795 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
796 arr[2] = scsi_debug_scsi_level;
797 arr[3] = 2; /* response_data_format==2 */
798 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500799 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200800 if (0 == scsi_debug_vpd_use_hostno)
801 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400802 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400804 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 memcpy(&arr[8], inq_vendor_id, 8);
806 memcpy(&arr[16], inq_product_id, 16);
807 memcpy(&arr[32], inq_product_rev, 4);
808 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400809 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
810 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
811 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400813 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400815 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400817 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200818 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200820 kfree(arr);
821 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822}
823
824static int resp_requests(struct scsi_cmnd * scp,
825 struct sdebug_dev_info * devip)
826{
827 unsigned char * sbuff;
828 unsigned char *cmd = (unsigned char *)scp->cmnd;
829 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400830 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 int len = 18;
832
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400833 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400835 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
836 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400838 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
839 if (want_dsense) {
840 arr[0] = 0x72;
841 arr[1] = 0x0; /* NO_SENSE in sense_key */
842 arr[2] = THRESHOLD_EXCEEDED;
843 arr[3] = 0xff; /* TEST set and MRIE==6 */
844 } else {
845 arr[0] = 0x70;
846 arr[2] = 0x0; /* NO_SENSE in sense_key */
847 arr[7] = 0xa; /* 18 byte sense buffer */
848 arr[12] = THRESHOLD_EXCEEDED;
849 arr[13] = 0xff; /* TEST set and MRIE==6 */
850 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400851 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400853 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
854 /* DESC bit set and sense_buff in fixed format */
855 memset(arr, 0, sizeof(arr));
856 arr[0] = 0x72;
857 arr[1] = sbuff[2]; /* sense key */
858 arr[2] = sbuff[12]; /* asc */
859 arr[3] = sbuff[13]; /* ascq */
860 len = 8;
861 }
862 }
863 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 return fill_from_dev_buffer(scp, arr, len);
865}
866
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400867static int resp_start_stop(struct scsi_cmnd * scp,
868 struct sdebug_dev_info * devip)
869{
870 unsigned char *cmd = (unsigned char *)scp->cmnd;
871 int power_cond, errsts, start;
872
873 if ((errsts = check_readiness(scp, 1, devip)))
874 return errsts;
875 power_cond = (cmd[4] & 0xf0) >> 4;
876 if (power_cond) {
877 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
878 0);
879 return check_condition_result;
880 }
881 start = cmd[4] & 1;
882 if (start == devip->stopped)
883 devip->stopped = !start;
884 return 0;
885}
886
FUJITA Tomonori28898872008-03-30 00:59:55 +0900887static sector_t get_sdebug_capacity(void)
888{
889 if (scsi_debug_virtual_gb > 0)
FUJITA Tomonori73da9c12009-04-22 17:42:25 -0700890 return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
FUJITA Tomonori28898872008-03-30 00:59:55 +0900891 else
892 return sdebug_store_sectors;
893}
894
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895#define SDEBUG_READCAP_ARR_SZ 8
896static int resp_readcap(struct scsi_cmnd * scp,
897 struct sdebug_dev_info * devip)
898{
899 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400900 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 int errsts;
902
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400903 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400905 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900906 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400908 if (sdebug_capacity < 0xffffffff) {
909 capac = (unsigned int)sdebug_capacity - 1;
910 arr[0] = (capac >> 24);
911 arr[1] = (capac >> 16) & 0xff;
912 arr[2] = (capac >> 8) & 0xff;
913 arr[3] = capac & 0xff;
914 } else {
915 arr[0] = 0xff;
916 arr[1] = 0xff;
917 arr[2] = 0xff;
918 arr[3] = 0xff;
919 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400920 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
921 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
923}
924
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400925#define SDEBUG_READCAP16_ARR_SZ 32
926static int resp_readcap16(struct scsi_cmnd * scp,
927 struct sdebug_dev_info * devip)
928{
929 unsigned char *cmd = (unsigned char *)scp->cmnd;
930 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
931 unsigned long long capac;
932 int errsts, k, alloc_len;
933
934 if ((errsts = check_readiness(scp, 1, devip)))
935 return errsts;
936 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
937 + cmd[13]);
938 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900939 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400940 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
941 capac = sdebug_capacity - 1;
942 for (k = 0; k < 8; ++k, capac >>= 8)
943 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400944 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
945 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
946 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
947 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500948
949 if (scsi_debug_dif) {
950 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
951 arr[12] |= 1; /* PROT_EN */
952 }
953
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400954 return fill_from_dev_buffer(scp, arr,
955 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
956}
957
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200958#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
959
960static int resp_report_tgtpgs(struct scsi_cmnd * scp,
961 struct sdebug_dev_info * devip)
962{
963 unsigned char *cmd = (unsigned char *)scp->cmnd;
964 unsigned char * arr;
965 int host_no = devip->sdbg_host->shost->host_no;
966 int n, ret, alen, rlen;
967 int port_group_a, port_group_b, port_a, port_b;
968
969 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
970 + cmd[9]);
971
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500972 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
973 if (! arr)
974 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200975 /*
976 * EVPD page 0x88 states we have two ports, one
977 * real and a fake port with no device connected.
978 * So we create two port groups with one port each
979 * and set the group with port B to unavailable.
980 */
981 port_a = 0x1; /* relative port A */
982 port_b = 0x2; /* relative port B */
983 port_group_a = (((host_no + 1) & 0x7f) << 8) +
984 (devip->channel & 0x7f);
985 port_group_b = (((host_no + 1) & 0x7f) << 8) +
986 (devip->channel & 0x7f) + 0x80;
987
988 /*
989 * The asymmetric access state is cycled according to the host_id.
990 */
991 n = 4;
992 if (0 == scsi_debug_vpd_use_hostno) {
993 arr[n++] = host_no % 3; /* Asymm access state */
994 arr[n++] = 0x0F; /* claim: all states are supported */
995 } else {
996 arr[n++] = 0x0; /* Active/Optimized path */
997 arr[n++] = 0x01; /* claim: only support active/optimized paths */
998 }
999 arr[n++] = (port_group_a >> 8) & 0xff;
1000 arr[n++] = port_group_a & 0xff;
1001 arr[n++] = 0; /* Reserved */
1002 arr[n++] = 0; /* Status code */
1003 arr[n++] = 0; /* Vendor unique */
1004 arr[n++] = 0x1; /* One port per group */
1005 arr[n++] = 0; /* Reserved */
1006 arr[n++] = 0; /* Reserved */
1007 arr[n++] = (port_a >> 8) & 0xff;
1008 arr[n++] = port_a & 0xff;
1009 arr[n++] = 3; /* Port unavailable */
1010 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1011 arr[n++] = (port_group_b >> 8) & 0xff;
1012 arr[n++] = port_group_b & 0xff;
1013 arr[n++] = 0; /* Reserved */
1014 arr[n++] = 0; /* Status code */
1015 arr[n++] = 0; /* Vendor unique */
1016 arr[n++] = 0x1; /* One port per group */
1017 arr[n++] = 0; /* Reserved */
1018 arr[n++] = 0; /* Reserved */
1019 arr[n++] = (port_b >> 8) & 0xff;
1020 arr[n++] = port_b & 0xff;
1021
1022 rlen = n - 4;
1023 arr[0] = (rlen >> 24) & 0xff;
1024 arr[1] = (rlen >> 16) & 0xff;
1025 arr[2] = (rlen >> 8) & 0xff;
1026 arr[3] = rlen & 0xff;
1027
1028 /*
1029 * Return the smallest value of either
1030 * - The allocated length
1031 * - The constructed command length
1032 * - The maximum array size
1033 */
1034 rlen = min(alen,n);
1035 ret = fill_from_dev_buffer(scp, arr,
1036 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1037 kfree(arr);
1038 return ret;
1039}
1040
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041/* <<Following mode page info copied from ST318451LW>> */
1042
1043static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1044{ /* Read-Write Error Recovery page for mode_sense */
1045 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1046 5, 0, 0xff, 0xff};
1047
1048 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1049 if (1 == pcontrol)
1050 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1051 return sizeof(err_recov_pg);
1052}
1053
1054static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1055{ /* Disconnect-Reconnect page for mode_sense */
1056 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1057 0, 0, 0, 0, 0, 0, 0, 0};
1058
1059 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1060 if (1 == pcontrol)
1061 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1062 return sizeof(disconnect_pg);
1063}
1064
1065static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1066{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001067 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1068 0, 0, 0, 0, 0, 0, 0, 0,
1069 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Martin K. Petersen597136a2008-06-05 00:12:59 -04001071 memcpy(p, format_pg, sizeof(format_pg));
1072 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1073 p[11] = sdebug_sectors_per & 0xff;
1074 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1075 p[13] = scsi_debug_sector_size & 0xff;
1076 if (DEV_REMOVEABLE(target))
1077 p[20] |= 0x20; /* should agree with INQUIRY */
1078 if (1 == pcontrol)
1079 memset(p + 2, 0, sizeof(format_pg) - 2);
1080 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081}
1082
1083static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1084{ /* Caching page for mode_sense */
1085 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1086 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1087
1088 memcpy(p, caching_pg, sizeof(caching_pg));
1089 if (1 == pcontrol)
1090 memset(p + 2, 0, sizeof(caching_pg) - 2);
1091 return sizeof(caching_pg);
1092}
1093
1094static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1095{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001096 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1097 0, 0, 0, 0};
1098 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 0, 0, 0x2, 0x4b};
1100
1101 if (scsi_debug_dsense)
1102 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001103 else
1104 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001105
1106 if (scsi_debug_ato)
1107 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1110 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001111 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1112 else if (2 == pcontrol)
1113 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 return sizeof(ctrl_m_pg);
1115}
1116
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1119{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001120 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1121 0, 0, 0x0, 0x0};
1122 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1123 0, 0, 0x0, 0x0};
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1126 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001127 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1128 else if (2 == pcontrol)
1129 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 return sizeof(iec_m_pg);
1131}
1132
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001133static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1134{ /* SAS SSP mode page - short format for mode_sense */
1135 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1136 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1137
1138 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1139 if (1 == pcontrol)
1140 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1141 return sizeof(sas_sf_m_pg);
1142}
1143
1144
1145static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1146 int target_dev_id)
1147{ /* SAS phy control and discover mode page for mode_sense */
1148 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1149 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1150 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1151 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1152 0x2, 0, 0, 0, 0, 0, 0, 0,
1153 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1154 0, 0, 0, 0, 0, 0, 0, 0,
1155 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1156 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1157 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1158 0x3, 0, 0, 0, 0, 0, 0, 0,
1159 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1160 0, 0, 0, 0, 0, 0, 0, 0,
1161 };
1162 int port_a, port_b;
1163
1164 port_a = target_dev_id + 1;
1165 port_b = port_a + 1;
1166 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1167 p[20] = (port_a >> 24);
1168 p[21] = (port_a >> 16) & 0xff;
1169 p[22] = (port_a >> 8) & 0xff;
1170 p[23] = port_a & 0xff;
1171 p[48 + 20] = (port_b >> 24);
1172 p[48 + 21] = (port_b >> 16) & 0xff;
1173 p[48 + 22] = (port_b >> 8) & 0xff;
1174 p[48 + 23] = port_b & 0xff;
1175 if (1 == pcontrol)
1176 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1177 return sizeof(sas_pcd_m_pg);
1178}
1179
1180static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1181{ /* SAS SSP shared protocol specific port mode subpage */
1182 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1183 0, 0, 0, 0, 0, 0, 0, 0,
1184 };
1185
1186 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1187 if (1 == pcontrol)
1188 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1189 return sizeof(sas_sha_m_pg);
1190}
1191
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192#define SDEBUG_MAX_MSENSE_SZ 256
1193
1194static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1195 struct sdebug_dev_info * devip)
1196{
Douglas Gilbert23183912006-09-16 20:30:47 -04001197 unsigned char dbd, llbaa;
1198 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001200 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 unsigned char * ap;
1202 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1203 unsigned char *cmd = (unsigned char *)scp->cmnd;
1204
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001205 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001207 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 pcontrol = (cmd[2] & 0xc0) >> 6;
1209 pcode = cmd[2] & 0x3f;
1210 subpcode = cmd[3];
1211 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001212 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1213 if ((0 == scsi_debug_ptype) && (0 == dbd))
1214 bd_len = llbaa ? 16 : 8;
1215 else
1216 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1218 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1219 if (0x3 == pcontrol) { /* Saving values not supported */
1220 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1221 0);
1222 return check_condition_result;
1223 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001224 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1225 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001226 /* set DPOFUA bit for disks */
1227 if (0 == scsi_debug_ptype)
1228 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1229 else
1230 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 if (msense_6) {
1232 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001233 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 offset = 4;
1235 } else {
1236 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001237 if (16 == bd_len)
1238 arr[4] = 0x1; /* set LONGLBA bit */
1239 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 offset = 8;
1241 }
1242 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001243 if ((bd_len > 0) && (!sdebug_capacity))
1244 sdebug_capacity = get_sdebug_capacity();
1245
Douglas Gilbert23183912006-09-16 20:30:47 -04001246 if (8 == bd_len) {
1247 if (sdebug_capacity > 0xfffffffe) {
1248 ap[0] = 0xff;
1249 ap[1] = 0xff;
1250 ap[2] = 0xff;
1251 ap[3] = 0xff;
1252 } else {
1253 ap[0] = (sdebug_capacity >> 24) & 0xff;
1254 ap[1] = (sdebug_capacity >> 16) & 0xff;
1255 ap[2] = (sdebug_capacity >> 8) & 0xff;
1256 ap[3] = sdebug_capacity & 0xff;
1257 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001258 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1259 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001260 offset += bd_len;
1261 ap = arr + offset;
1262 } else if (16 == bd_len) {
1263 unsigned long long capac = sdebug_capacity;
1264
1265 for (k = 0; k < 8; ++k, capac >>= 8)
1266 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001267 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1268 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1269 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1270 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001271 offset += bd_len;
1272 ap = arr + offset;
1273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001275 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1276 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1278 0);
1279 return check_condition_result;
1280 }
1281 switch (pcode) {
1282 case 0x1: /* Read-Write error recovery page, direct access */
1283 len = resp_err_recov_pg(ap, pcontrol, target);
1284 offset += len;
1285 break;
1286 case 0x2: /* Disconnect-Reconnect page, all devices */
1287 len = resp_disconnect_pg(ap, pcontrol, target);
1288 offset += len;
1289 break;
1290 case 0x3: /* Format device page, direct access */
1291 len = resp_format_pg(ap, pcontrol, target);
1292 offset += len;
1293 break;
1294 case 0x8: /* Caching page, direct access */
1295 len = resp_caching_pg(ap, pcontrol, target);
1296 offset += len;
1297 break;
1298 case 0xa: /* Control Mode page, all devices */
1299 len = resp_ctrl_m_pg(ap, pcontrol, target);
1300 offset += len;
1301 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001302 case 0x19: /* if spc==1 then sas phy, control+discover */
1303 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1304 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1305 INVALID_FIELD_IN_CDB, 0);
1306 return check_condition_result;
1307 }
1308 len = 0;
1309 if ((0x0 == subpcode) || (0xff == subpcode))
1310 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1311 if ((0x1 == subpcode) || (0xff == subpcode))
1312 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1313 target_dev_id);
1314 if ((0x2 == subpcode) || (0xff == subpcode))
1315 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1316 offset += len;
1317 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 case 0x1c: /* Informational Exceptions Mode page, all devices */
1319 len = resp_iec_m_pg(ap, pcontrol, target);
1320 offset += len;
1321 break;
1322 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001323 if ((0 == subpcode) || (0xff == subpcode)) {
1324 len = resp_err_recov_pg(ap, pcontrol, target);
1325 len += resp_disconnect_pg(ap + len, pcontrol, target);
1326 len += resp_format_pg(ap + len, pcontrol, target);
1327 len += resp_caching_pg(ap + len, pcontrol, target);
1328 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1329 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1330 if (0xff == subpcode) {
1331 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1332 target, target_dev_id);
1333 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1334 }
1335 len += resp_iec_m_pg(ap + len, pcontrol, target);
1336 } else {
1337 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1338 INVALID_FIELD_IN_CDB, 0);
1339 return check_condition_result;
1340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 offset += len;
1342 break;
1343 default:
1344 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1345 0);
1346 return check_condition_result;
1347 }
1348 if (msense_6)
1349 arr[0] = offset - 1;
1350 else {
1351 arr[0] = ((offset - 2) >> 8) & 0xff;
1352 arr[1] = (offset - 2) & 0xff;
1353 }
1354 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1355}
1356
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001357#define SDEBUG_MAX_MSELECT_SZ 512
1358
1359static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1360 struct sdebug_dev_info * devip)
1361{
1362 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1363 int param_len, res, errsts, mpage;
1364 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1365 unsigned char *cmd = (unsigned char *)scp->cmnd;
1366
1367 if ((errsts = check_readiness(scp, 1, devip)))
1368 return errsts;
1369 memset(arr, 0, sizeof(arr));
1370 pf = cmd[1] & 0x10;
1371 sp = cmd[1] & 0x1;
1372 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1373 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1374 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1375 INVALID_FIELD_IN_CDB, 0);
1376 return check_condition_result;
1377 }
1378 res = fetch_to_dev_buffer(scp, arr, param_len);
1379 if (-1 == res)
1380 return (DID_ERROR << 16);
1381 else if ((res < param_len) &&
1382 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1383 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1384 " IO sent=%d bytes\n", param_len, res);
1385 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1386 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001387 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001388 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1389 INVALID_FIELD_IN_PARAM_LIST, 0);
1390 return check_condition_result;
1391 }
1392 off = bd_len + (mselect6 ? 4 : 8);
1393 mpage = arr[off] & 0x3f;
1394 ps = !!(arr[off] & 0x80);
1395 if (ps) {
1396 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1397 INVALID_FIELD_IN_PARAM_LIST, 0);
1398 return check_condition_result;
1399 }
1400 spf = !!(arr[off] & 0x40);
1401 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1402 (arr[off + 1] + 2);
1403 if ((pg_len + off) > param_len) {
1404 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1405 PARAMETER_LIST_LENGTH_ERR, 0);
1406 return check_condition_result;
1407 }
1408 switch (mpage) {
1409 case 0xa: /* Control Mode page */
1410 if (ctrl_m_pg[1] == arr[off + 1]) {
1411 memcpy(ctrl_m_pg + 2, arr + off + 2,
1412 sizeof(ctrl_m_pg) - 2);
1413 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1414 return 0;
1415 }
1416 break;
1417 case 0x1c: /* Informational Exceptions Mode page */
1418 if (iec_m_pg[1] == arr[off + 1]) {
1419 memcpy(iec_m_pg + 2, arr + off + 2,
1420 sizeof(iec_m_pg) - 2);
1421 return 0;
1422 }
1423 break;
1424 default:
1425 break;
1426 }
1427 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1428 INVALID_FIELD_IN_PARAM_LIST, 0);
1429 return check_condition_result;
1430}
1431
1432static int resp_temp_l_pg(unsigned char * arr)
1433{
1434 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1435 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1436 };
1437
1438 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1439 return sizeof(temp_l_pg);
1440}
1441
1442static int resp_ie_l_pg(unsigned char * arr)
1443{
1444 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1445 };
1446
1447 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1448 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1449 arr[4] = THRESHOLD_EXCEEDED;
1450 arr[5] = 0xff;
1451 }
1452 return sizeof(ie_l_pg);
1453}
1454
1455#define SDEBUG_MAX_LSENSE_SZ 512
1456
1457static int resp_log_sense(struct scsi_cmnd * scp,
1458 struct sdebug_dev_info * devip)
1459{
Douglas Gilbert23183912006-09-16 20:30:47 -04001460 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001461 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1462 unsigned char *cmd = (unsigned char *)scp->cmnd;
1463
1464 if ((errsts = check_readiness(scp, 1, devip)))
1465 return errsts;
1466 memset(arr, 0, sizeof(arr));
1467 ppc = cmd[1] & 0x2;
1468 sp = cmd[1] & 0x1;
1469 if (ppc || sp) {
1470 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1471 INVALID_FIELD_IN_CDB, 0);
1472 return check_condition_result;
1473 }
1474 pcontrol = (cmd[2] & 0xc0) >> 6;
1475 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001476 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001477 alloc_len = (cmd[7] << 8) + cmd[8];
1478 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001479 if (0 == subpcode) {
1480 switch (pcode) {
1481 case 0x0: /* Supported log pages log page */
1482 n = 4;
1483 arr[n++] = 0x0; /* this page */
1484 arr[n++] = 0xd; /* Temperature */
1485 arr[n++] = 0x2f; /* Informational exceptions */
1486 arr[3] = n - 4;
1487 break;
1488 case 0xd: /* Temperature log page */
1489 arr[3] = resp_temp_l_pg(arr + 4);
1490 break;
1491 case 0x2f: /* Informational exceptions log page */
1492 arr[3] = resp_ie_l_pg(arr + 4);
1493 break;
1494 default:
1495 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1496 INVALID_FIELD_IN_CDB, 0);
1497 return check_condition_result;
1498 }
1499 } else if (0xff == subpcode) {
1500 arr[0] |= 0x40;
1501 arr[1] = subpcode;
1502 switch (pcode) {
1503 case 0x0: /* Supported log pages and subpages log page */
1504 n = 4;
1505 arr[n++] = 0x0;
1506 arr[n++] = 0x0; /* 0,0 page */
1507 arr[n++] = 0x0;
1508 arr[n++] = 0xff; /* this page */
1509 arr[n++] = 0xd;
1510 arr[n++] = 0x0; /* Temperature */
1511 arr[n++] = 0x2f;
1512 arr[n++] = 0x0; /* Informational exceptions */
1513 arr[3] = n - 4;
1514 break;
1515 case 0xd: /* Temperature subpages */
1516 n = 4;
1517 arr[n++] = 0xd;
1518 arr[n++] = 0x0; /* Temperature */
1519 arr[3] = n - 4;
1520 break;
1521 case 0x2f: /* Informational exceptions subpages */
1522 n = 4;
1523 arr[n++] = 0x2f;
1524 arr[n++] = 0x0; /* Informational exceptions */
1525 arr[3] = n - 4;
1526 break;
1527 default:
1528 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1529 INVALID_FIELD_IN_CDB, 0);
1530 return check_condition_result;
1531 }
1532 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001533 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1534 INVALID_FIELD_IN_CDB, 0);
1535 return check_condition_result;
1536 }
1537 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1538 return fill_from_dev_buffer(scp, arr,
1539 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1540}
1541
FUJITA Tomonori19789102008-03-30 00:59:56 +09001542static int check_device_access_params(struct sdebug_dev_info *devi,
1543 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001545 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001546 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 return check_condition_result;
1548 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001549 /* transfer length excessive (tie in to block limits VPD page) */
1550 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001551 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001552 return check_condition_result;
1553 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001554 return 0;
1555}
1556
1557static int do_device_access(struct scsi_cmnd *scmd,
1558 struct sdebug_dev_info *devi,
1559 unsigned long long lba, unsigned int num, int write)
1560{
1561 int ret;
1562 unsigned int block, rest = 0;
1563 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1564
1565 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1566
1567 block = do_div(lba, sdebug_store_sectors);
1568 if (block + num > sdebug_store_sectors)
1569 rest = block + num - sdebug_store_sectors;
1570
Martin K. Petersen597136a2008-06-05 00:12:59 -04001571 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1572 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001573 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001574 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001575
1576 return ret;
1577}
1578
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001579static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1580 unsigned int sectors)
1581{
1582 unsigned int i, resid;
1583 struct scatterlist *psgl;
1584 struct sd_dif_tuple *sdt;
1585 sector_t sector;
1586 sector_t tmp_sec = start_sec;
1587 void *paddr;
1588
1589 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1590
1591 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1592
1593 for (i = 0 ; i < sectors ; i++) {
1594 u16 csum;
1595
1596 if (sdt[i].app_tag == 0xffff)
1597 continue;
1598
1599 sector = start_sec + i;
1600
1601 switch (scsi_debug_guard) {
1602 case 1:
1603 csum = ip_compute_csum(fake_storep +
1604 sector * scsi_debug_sector_size,
1605 scsi_debug_sector_size);
1606 break;
1607 case 0:
1608 csum = crc_t10dif(fake_storep +
1609 sector * scsi_debug_sector_size,
1610 scsi_debug_sector_size);
1611 csum = cpu_to_be16(csum);
1612 break;
1613 default:
1614 BUG();
1615 }
1616
1617 if (sdt[i].guard_tag != csum) {
1618 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1619 " rcvd 0x%04x, data 0x%04x\n", __func__,
1620 (unsigned long)sector,
1621 be16_to_cpu(sdt[i].guard_tag),
1622 be16_to_cpu(csum));
1623 dif_errors++;
1624 return 0x01;
1625 }
1626
1627 if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
1628 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1629 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1630 __func__, (unsigned long)sector);
1631 dif_errors++;
1632 return 0x03;
1633 }
1634 }
1635
1636 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1637 sector = start_sec;
1638
1639 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1640 int len = min(psgl->length, resid);
1641
1642 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1643 memcpy(paddr, dif_storep + dif_offset(sector), len);
1644
1645 sector += len >> 3;
1646 if (sector >= sdebug_store_sectors) {
1647 /* Force wrap */
1648 tmp_sec = sector;
1649 sector = do_div(tmp_sec, sdebug_store_sectors);
1650 }
1651 resid -= len;
1652 kunmap_atomic(paddr, KM_IRQ0);
1653 }
1654
1655 dix_reads++;
1656
1657 return 0;
1658}
1659
FUJITA Tomonori19789102008-03-30 00:59:56 +09001660static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1661 unsigned int num, struct sdebug_dev_info *devip)
1662{
1663 unsigned long iflags;
1664 int ret;
1665
1666 ret = check_device_access_params(devip, lba, num);
1667 if (ret)
1668 return ret;
1669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001671 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1672 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1673 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1675 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001676 /* set info field and valid bit for fixed descriptor */
1677 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1678 devip->sense_buff[0] |= 0x80; /* Valid bit */
1679 ret = OPT_MEDIUM_ERR_ADDR;
1680 devip->sense_buff[3] = (ret >> 24) & 0xff;
1681 devip->sense_buff[4] = (ret >> 16) & 0xff;
1682 devip->sense_buff[5] = (ret >> 8) & 0xff;
1683 devip->sense_buff[6] = ret & 0xff;
1684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 return check_condition_result;
1686 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001687
1688 /* DIX + T10 DIF */
1689 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1690 int prot_ret = prot_verify_read(SCpnt, lba, num);
1691
1692 if (prot_ret) {
1693 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1694 return illegal_condition_result;
1695 }
1696 }
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001699 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 read_unlock_irqrestore(&atomic_rw, iflags);
1701 return ret;
1702}
1703
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001704void dump_sector(unsigned char *buf, int len)
1705{
1706 int i, j;
1707
1708 printk(KERN_ERR ">>> Sector Dump <<<\n");
1709
1710 for (i = 0 ; i < len ; i += 16) {
1711 printk(KERN_ERR "%04d: ", i);
1712
1713 for (j = 0 ; j < 16 ; j++) {
1714 unsigned char c = buf[i+j];
1715 if (c >= 0x20 && c < 0x7e)
1716 printk(" %c ", buf[i+j]);
1717 else
1718 printk("%02x ", buf[i+j]);
1719 }
1720
1721 printk("\n");
1722 }
1723}
1724
1725static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1726 unsigned int sectors)
1727{
1728 int i, j, ret;
1729 struct sd_dif_tuple *sdt;
1730 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1731 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1732 void *daddr, *paddr;
1733 sector_t tmp_sec = start_sec;
1734 sector_t sector;
1735 int ppage_offset;
1736 unsigned short csum;
1737
1738 sector = do_div(tmp_sec, sdebug_store_sectors);
1739
1740 if (((SCpnt->cmnd[1] >> 5) & 7) != 1) {
1741 printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n");
1742 return 0;
1743 }
1744
1745 BUG_ON(scsi_sg_count(SCpnt) == 0);
1746 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1747
1748 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1749 ppage_offset = 0;
1750
1751 /* For each data page */
1752 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1753 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1754
1755 /* For each sector-sized chunk in data page */
1756 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1757
1758 /* If we're at the end of the current
1759 * protection page advance to the next one
1760 */
1761 if (ppage_offset >= psgl->length) {
1762 kunmap_atomic(paddr, KM_IRQ1);
1763 psgl = sg_next(psgl);
1764 BUG_ON(psgl == NULL);
1765 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1766 + psgl->offset;
1767 ppage_offset = 0;
1768 }
1769
1770 sdt = paddr + ppage_offset;
1771
1772 switch (scsi_debug_guard) {
1773 case 1:
1774 csum = ip_compute_csum(daddr,
1775 scsi_debug_sector_size);
1776 break;
1777 case 0:
1778 csum = cpu_to_be16(crc_t10dif(daddr,
1779 scsi_debug_sector_size));
1780 break;
1781 default:
1782 BUG();
1783 ret = 0;
1784 goto out;
1785 }
1786
1787 if (sdt->guard_tag != csum) {
1788 printk(KERN_ERR
1789 "%s: GUARD check failed on sector %lu " \
1790 "rcvd 0x%04x, calculated 0x%04x\n",
1791 __func__, (unsigned long)sector,
1792 be16_to_cpu(sdt->guard_tag),
1793 be16_to_cpu(csum));
1794 ret = 0x01;
1795 dump_sector(daddr, scsi_debug_sector_size);
1796 goto out;
1797 }
1798
1799 if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
1800 be32_to_cpu(sdt->ref_tag)
1801 != (start_sec & 0xffffffff)) {
1802 printk(KERN_ERR
1803 "%s: REF check failed on sector %lu\n",
1804 __func__, (unsigned long)sector);
1805 ret = 0x03;
1806 dump_sector(daddr, scsi_debug_sector_size);
1807 goto out;
1808 }
1809
1810 /* Would be great to copy this in bigger
1811 * chunks. However, for the sake of
1812 * correctness we need to verify each sector
1813 * before writing it to "stable" storage
1814 */
1815 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1816
1817 sector++;
1818
1819 if (sector == sdebug_store_sectors)
1820 sector = 0; /* Force wrap */
1821
1822 start_sec++;
1823 daddr += scsi_debug_sector_size;
1824 ppage_offset += sizeof(struct sd_dif_tuple);
1825 }
1826
1827 kunmap_atomic(daddr, KM_IRQ0);
1828 }
1829
1830 kunmap_atomic(paddr, KM_IRQ1);
1831
1832 dix_writes++;
1833
1834 return 0;
1835
1836out:
1837 dif_errors++;
1838 kunmap_atomic(daddr, KM_IRQ0);
1839 kunmap_atomic(paddr, KM_IRQ1);
1840 return ret;
1841}
1842
FUJITA Tomonori19789102008-03-30 00:59:56 +09001843static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
1844 unsigned int num, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845{
1846 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001847 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
FUJITA Tomonori19789102008-03-30 00:59:56 +09001849 ret = check_device_access_params(devip, lba, num);
1850 if (ret)
1851 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001853 /* DIX + T10 DIF */
1854 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1855 int prot_ret = prot_verify_write(SCpnt, lba, num);
1856
1857 if (prot_ret) {
1858 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
1859 return illegal_condition_result;
1860 }
1861 }
1862
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001864 ret = do_device_access(SCpnt, devip, lba, num, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001866 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04001868 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001870 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04001871 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 return 0;
1873}
1874
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001875#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
1877static int resp_report_luns(struct scsi_cmnd * scp,
1878 struct sdebug_dev_info * devip)
1879{
1880 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001881 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 unsigned char *cmd = (unsigned char *)scp->cmnd;
1883 int select_report = (int)cmd[2];
1884 struct scsi_lun *one_lun;
1885 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001886 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
1888 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001889 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1891 0);
1892 return check_condition_result;
1893 }
1894 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1895 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1896 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001897 if (1 == select_report)
1898 lun_cnt = 0;
1899 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1900 --lun_cnt;
1901 wlun = (select_report > 0) ? 1 : 0;
1902 num = lun_cnt + wlun;
1903 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1904 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1905 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1906 sizeof(struct scsi_lun)), num);
1907 if (n < num) {
1908 wlun = 0;
1909 lun_cnt = n;
1910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001912 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1913 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1914 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1915 i++, lun++) {
1916 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 if (upper)
1918 one_lun[i].scsi_lun[0] =
1919 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001920 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001922 if (wlun) {
1923 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1924 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1925 i++;
1926 }
1927 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 return fill_from_dev_buffer(scp, arr,
1929 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1930}
1931
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001932static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1933 unsigned int num, struct sdebug_dev_info *devip)
1934{
1935 int i, j, ret = -1;
1936 unsigned char *kaddr, *buf;
1937 unsigned int offset;
1938 struct scatterlist *sg;
1939 struct scsi_data_buffer *sdb = scsi_in(scp);
1940
1941 /* better not to use temporary buffer. */
1942 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1943 if (!buf)
1944 return ret;
1945
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001946 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001947
1948 offset = 0;
1949 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1950 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1951 if (!kaddr)
1952 goto out;
1953
1954 for (j = 0; j < sg->length; j++)
1955 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1956
1957 offset += sg->length;
1958 kunmap_atomic(kaddr, KM_USER0);
1959 }
1960 ret = 0;
1961out:
1962 kfree(buf);
1963
1964 return ret;
1965}
1966
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967/* When timer goes off this function is called. */
1968static void timer_intr_handler(unsigned long indx)
1969{
1970 struct sdebug_queued_cmd * sqcp;
1971 unsigned long iflags;
1972
1973 if (indx >= SCSI_DEBUG_CANQUEUE) {
1974 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1975 "large\n");
1976 return;
1977 }
1978 spin_lock_irqsave(&queued_arr_lock, iflags);
1979 sqcp = &queued_arr[(int)indx];
1980 if (! sqcp->in_use) {
1981 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1982 "interrupt\n");
1983 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1984 return;
1985 }
1986 sqcp->in_use = 0;
1987 if (sqcp->done_funct) {
1988 sqcp->a_cmnd->result = sqcp->scsi_result;
1989 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1990 }
1991 sqcp->done_funct = NULL;
1992 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1993}
1994
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001996static struct sdebug_dev_info *
1997sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001998{
1999 struct sdebug_dev_info *devip;
2000
2001 devip = kzalloc(sizeof(*devip), flags);
2002 if (devip) {
2003 devip->sdbg_host = sdbg_host;
2004 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2005 }
2006 return devip;
2007}
2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2010{
2011 struct sdebug_host_info * sdbg_host;
2012 struct sdebug_dev_info * open_devip = NULL;
2013 struct sdebug_dev_info * devip =
2014 (struct sdebug_dev_info *)sdev->hostdata;
2015
2016 if (devip)
2017 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002018 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2019 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 printk(KERN_ERR "Host info NULL\n");
2021 return NULL;
2022 }
2023 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2024 if ((devip->used) && (devip->channel == sdev->channel) &&
2025 (devip->target == sdev->id) &&
2026 (devip->lun == sdev->lun))
2027 return devip;
2028 else {
2029 if ((!devip->used) && (!open_devip))
2030 open_devip = devip;
2031 }
2032 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002033 if (!open_devip) { /* try and make a new one */
2034 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2035 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002037 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 return NULL;
2039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002041
2042 open_devip->channel = sdev->channel;
2043 open_devip->target = sdev->id;
2044 open_devip->lun = sdev->lun;
2045 open_devip->sdbg_host = sdbg_host;
2046 open_devip->reset = 1;
2047 open_devip->used = 1;
2048 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2049 if (scsi_debug_dsense)
2050 open_devip->sense_buff[0] = 0x72;
2051 else {
2052 open_devip->sense_buff[0] = 0x70;
2053 open_devip->sense_buff[7] = 0xa;
2054 }
2055 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2056 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2057
2058 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059}
2060
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002061static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002063 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2064 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2065 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002066 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002067 return 0;
2068}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002070static int scsi_debug_slave_configure(struct scsi_device *sdp)
2071{
2072 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002073
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002075 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2076 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2077 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2078 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2079 devip = devInfoReg(sdp);
2080 if (NULL == devip)
2081 return 1; /* no resources, will be marked offline */
2082 sdp->hostdata = devip;
2083 if (sdp->host->cmd_per_lun)
2084 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2085 sdp->host->cmd_per_lun);
2086 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
2087 return 0;
2088}
2089
2090static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2091{
2092 struct sdebug_dev_info *devip =
2093 (struct sdebug_dev_info *)sdp->hostdata;
2094
2095 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2096 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2097 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2098 if (devip) {
2099 /* make this slot avaliable for re-use */
2100 devip->used = 0;
2101 sdp->hostdata = NULL;
2102 }
2103}
2104
2105/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2106static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2107{
2108 unsigned long iflags;
2109 int k;
2110 struct sdebug_queued_cmd *sqcp;
2111
2112 spin_lock_irqsave(&queued_arr_lock, iflags);
2113 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2114 sqcp = &queued_arr[k];
2115 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2116 del_timer_sync(&sqcp->cmnd_timer);
2117 sqcp->in_use = 0;
2118 sqcp->a_cmnd = NULL;
2119 break;
2120 }
2121 }
2122 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2123 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2124}
2125
2126/* Deletes (stops) timers of all queued commands */
2127static void stop_all_queued(void)
2128{
2129 unsigned long iflags;
2130 int k;
2131 struct sdebug_queued_cmd *sqcp;
2132
2133 spin_lock_irqsave(&queued_arr_lock, iflags);
2134 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2135 sqcp = &queued_arr[k];
2136 if (sqcp->in_use && sqcp->a_cmnd) {
2137 del_timer_sync(&sqcp->cmnd_timer);
2138 sqcp->in_use = 0;
2139 sqcp->a_cmnd = NULL;
2140 }
2141 }
2142 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143}
2144
2145static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2146{
2147 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2148 printk(KERN_INFO "scsi_debug: abort\n");
2149 ++num_aborts;
2150 stop_queued_cmnd(SCpnt);
2151 return SUCCESS;
2152}
2153
2154static int scsi_debug_biosparam(struct scsi_device *sdev,
2155 struct block_device * bdev, sector_t capacity, int *info)
2156{
2157 int res;
2158 unsigned char *buf;
2159
2160 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2161 printk(KERN_INFO "scsi_debug: biosparam\n");
2162 buf = scsi_bios_ptable(bdev);
2163 if (buf) {
2164 res = scsi_partsize(buf, capacity,
2165 &info[2], &info[0], &info[1]);
2166 kfree(buf);
2167 if (! res)
2168 return res;
2169 }
2170 info[0] = sdebug_heads;
2171 info[1] = sdebug_sectors_per;
2172 info[2] = sdebug_cylinders_per;
2173 return 0;
2174}
2175
2176static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2177{
2178 struct sdebug_dev_info * devip;
2179
2180 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2181 printk(KERN_INFO "scsi_debug: device_reset\n");
2182 ++num_dev_resets;
2183 if (SCpnt) {
2184 devip = devInfoReg(SCpnt->device);
2185 if (devip)
2186 devip->reset = 1;
2187 }
2188 return SUCCESS;
2189}
2190
2191static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2192{
2193 struct sdebug_host_info *sdbg_host;
2194 struct sdebug_dev_info * dev_info;
2195 struct scsi_device * sdp;
2196 struct Scsi_Host * hp;
2197
2198 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2199 printk(KERN_INFO "scsi_debug: bus_reset\n");
2200 ++num_bus_resets;
2201 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002202 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 if (sdbg_host) {
2204 list_for_each_entry(dev_info,
2205 &sdbg_host->dev_info_list,
2206 dev_list)
2207 dev_info->reset = 1;
2208 }
2209 }
2210 return SUCCESS;
2211}
2212
2213static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2214{
2215 struct sdebug_host_info * sdbg_host;
2216 struct sdebug_dev_info * dev_info;
2217
2218 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2219 printk(KERN_INFO "scsi_debug: host_reset\n");
2220 ++num_host_resets;
2221 spin_lock(&sdebug_host_list_lock);
2222 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2223 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2224 dev_list)
2225 dev_info->reset = 1;
2226 }
2227 spin_unlock(&sdebug_host_list_lock);
2228 stop_all_queued();
2229 return SUCCESS;
2230}
2231
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232/* Initializes timers in queued array */
2233static void __init init_all_queued(void)
2234{
2235 unsigned long iflags;
2236 int k;
2237 struct sdebug_queued_cmd * sqcp;
2238
2239 spin_lock_irqsave(&queued_arr_lock, iflags);
2240 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2241 sqcp = &queued_arr[k];
2242 init_timer(&sqcp->cmnd_timer);
2243 sqcp->in_use = 0;
2244 sqcp->a_cmnd = NULL;
2245 }
2246 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2247}
2248
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002249static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002250 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251{
2252 struct partition * pp;
2253 int starts[SDEBUG_MAX_PARTS + 2];
2254 int sectors_per_part, num_sectors, k;
2255 int heads_by_sects, start_sec, end_sec;
2256
2257 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002258 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 return;
2260 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2261 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2262 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2263 "partitions to %d\n", SDEBUG_MAX_PARTS);
2264 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002265 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 sectors_per_part = (num_sectors - sdebug_sectors_per)
2267 / scsi_debug_num_parts;
2268 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2269 starts[0] = sdebug_sectors_per;
2270 for (k = 1; k < scsi_debug_num_parts; ++k)
2271 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2272 * heads_by_sects;
2273 starts[scsi_debug_num_parts] = num_sectors;
2274 starts[scsi_debug_num_parts + 1] = 0;
2275
2276 ramp[510] = 0x55; /* magic partition markings */
2277 ramp[511] = 0xAA;
2278 pp = (struct partition *)(ramp + 0x1be);
2279 for (k = 0; starts[k + 1]; ++k, ++pp) {
2280 start_sec = starts[k];
2281 end_sec = starts[k + 1] - 1;
2282 pp->boot_ind = 0;
2283
2284 pp->cyl = start_sec / heads_by_sects;
2285 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2286 / sdebug_sectors_per;
2287 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2288
2289 pp->end_cyl = end_sec / heads_by_sects;
2290 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2291 / sdebug_sectors_per;
2292 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2293
2294 pp->start_sect = start_sec;
2295 pp->nr_sects = end_sec - start_sec + 1;
2296 pp->sys_ind = 0x83; /* plain Linux partition */
2297 }
2298}
2299
2300static int schedule_resp(struct scsi_cmnd * cmnd,
2301 struct sdebug_dev_info * devip,
2302 done_funct_t done, int scsi_result, int delta_jiff)
2303{
2304 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2305 if (scsi_result) {
2306 struct scsi_device * sdp = cmnd->device;
2307
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002308 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2309 "non-zero result=0x%x\n", sdp->host->host_no,
2310 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 }
2312 }
2313 if (cmnd && devip) {
2314 /* simulate autosense by this driver */
2315 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2316 memcpy(cmnd->sense_buffer, devip->sense_buff,
2317 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2318 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2319 }
2320 if (delta_jiff <= 0) {
2321 if (cmnd)
2322 cmnd->result = scsi_result;
2323 if (done)
2324 done(cmnd);
2325 return 0;
2326 } else {
2327 unsigned long iflags;
2328 int k;
2329 struct sdebug_queued_cmd * sqcp = NULL;
2330
2331 spin_lock_irqsave(&queued_arr_lock, iflags);
2332 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2333 sqcp = &queued_arr[k];
2334 if (! sqcp->in_use)
2335 break;
2336 }
2337 if (k >= SCSI_DEBUG_CANQUEUE) {
2338 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2339 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2340 return 1; /* report busy to mid level */
2341 }
2342 sqcp->in_use = 1;
2343 sqcp->a_cmnd = cmnd;
2344 sqcp->scsi_result = scsi_result;
2345 sqcp->done_funct = done;
2346 sqcp->cmnd_timer.function = timer_intr_handler;
2347 sqcp->cmnd_timer.data = k;
2348 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2349 add_timer(&sqcp->cmnd_timer);
2350 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2351 if (cmnd)
2352 cmnd->result = 0;
2353 return 0;
2354 }
2355}
Douglas Gilbert23183912006-09-16 20:30:47 -04002356/* Note: The following macros create attribute files in the
2357 /sys/module/scsi_debug/parameters directory. Unfortunately this
2358 driver is unaware of a change and cannot trigger auxiliary actions
2359 as it can when the corresponding attribute in the
2360 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2361 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002362module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2363module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2364module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2365module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2366module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002367module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002368module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2369module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2370module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2371module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2372module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2373module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2374module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2375module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002376module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2377 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002378module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002379module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2380module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2381module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2382module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
2384MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2385MODULE_DESCRIPTION("SCSI debug adapter driver");
2386MODULE_LICENSE("GPL");
2387MODULE_VERSION(SCSI_DEBUG_VERSION);
2388
2389MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2390MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002391MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2392MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002393MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002394MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002395MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2396MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002398MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002399MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2401MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002402MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002403MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersen597136a2008-06-05 00:12:59 -04002404MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002405MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2406MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2407MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2408MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
2410static char sdebug_info[256];
2411
2412static const char * scsi_debug_info(struct Scsi_Host * shp)
2413{
2414 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2415 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2416 scsi_debug_version_date, scsi_debug_dev_size_mb,
2417 scsi_debug_opts);
2418 return sdebug_info;
2419}
2420
2421/* scsi_debug_proc_info
2422 * Used if the driver currently has no own support for /proc/scsi
2423 */
2424static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2425 int length, int inout)
2426{
2427 int len, pos, begin;
2428 int orig_length;
2429
2430 orig_length = length;
2431
2432 if (inout == 1) {
2433 char arr[16];
2434 int minLen = length > 15 ? 15 : length;
2435
2436 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2437 return -EACCES;
2438 memcpy(arr, buffer, minLen);
2439 arr[minLen] = '\0';
2440 if (1 != sscanf(arr, "%d", &pos))
2441 return -EINVAL;
2442 scsi_debug_opts = pos;
2443 if (scsi_debug_every_nth != 0)
2444 scsi_debug_cmnd_count = 0;
2445 return length;
2446 }
2447 begin = 0;
2448 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2449 "%s [%s]\n"
2450 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2451 "every_nth=%d(curr:%d)\n"
2452 "delay=%d, max_luns=%d, scsi_level=%d\n"
2453 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2454 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002455 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2457 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2458 scsi_debug_cmnd_count, scsi_debug_delay,
2459 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002460 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2461 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002462 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 if (pos < offset) {
2464 len = 0;
2465 begin = pos;
2466 }
2467 *start = buffer + (offset - begin); /* Start of wanted data */
2468 len -= (offset - begin);
2469 if (len > length)
2470 len = length;
2471 return len;
2472}
2473
2474static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2475{
2476 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2477}
2478
2479static ssize_t sdebug_delay_store(struct device_driver * ddp,
2480 const char * buf, size_t count)
2481{
2482 int delay;
2483 char work[20];
2484
2485 if (1 == sscanf(buf, "%10s", work)) {
2486 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2487 scsi_debug_delay = delay;
2488 return count;
2489 }
2490 }
2491 return -EINVAL;
2492}
2493DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2494 sdebug_delay_store);
2495
2496static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2497{
2498 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2499}
2500
2501static ssize_t sdebug_opts_store(struct device_driver * ddp,
2502 const char * buf, size_t count)
2503{
2504 int opts;
2505 char work[20];
2506
2507 if (1 == sscanf(buf, "%10s", work)) {
2508 if (0 == strnicmp(work,"0x", 2)) {
2509 if (1 == sscanf(&work[2], "%x", &opts))
2510 goto opts_done;
2511 } else {
2512 if (1 == sscanf(work, "%d", &opts))
2513 goto opts_done;
2514 }
2515 }
2516 return -EINVAL;
2517opts_done:
2518 scsi_debug_opts = opts;
2519 scsi_debug_cmnd_count = 0;
2520 return count;
2521}
2522DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2523 sdebug_opts_store);
2524
2525static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2526{
2527 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2528}
2529static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2530 const char * buf, size_t count)
2531{
2532 int n;
2533
2534 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2535 scsi_debug_ptype = n;
2536 return count;
2537 }
2538 return -EINVAL;
2539}
2540DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2541
2542static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2543{
2544 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2545}
2546static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2547 const char * buf, size_t count)
2548{
2549 int n;
2550
2551 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2552 scsi_debug_dsense = n;
2553 return count;
2554 }
2555 return -EINVAL;
2556}
2557DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2558 sdebug_dsense_store);
2559
Douglas Gilbert23183912006-09-16 20:30:47 -04002560static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2561{
2562 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2563}
2564static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2565 const char * buf, size_t count)
2566{
2567 int n;
2568
2569 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2570 scsi_debug_fake_rw = n;
2571 return count;
2572 }
2573 return -EINVAL;
2574}
2575DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2576 sdebug_fake_rw_store);
2577
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002578static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2579{
2580 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2581}
2582static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2583 const char * buf, size_t count)
2584{
2585 int n;
2586
2587 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2588 scsi_debug_no_lun_0 = n;
2589 return count;
2590 }
2591 return -EINVAL;
2592}
2593DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2594 sdebug_no_lun_0_store);
2595
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2597{
2598 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2599}
2600static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2601 const char * buf, size_t count)
2602{
2603 int n;
2604
2605 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2606 scsi_debug_num_tgts = n;
2607 sdebug_max_tgts_luns();
2608 return count;
2609 }
2610 return -EINVAL;
2611}
2612DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2613 sdebug_num_tgts_store);
2614
2615static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2616{
2617 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2618}
2619DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2620
2621static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2622{
2623 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2624}
2625DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2626
2627static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2628{
2629 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2630}
2631static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2632 const char * buf, size_t count)
2633{
2634 int nth;
2635
2636 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2637 scsi_debug_every_nth = nth;
2638 scsi_debug_cmnd_count = 0;
2639 return count;
2640 }
2641 return -EINVAL;
2642}
2643DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2644 sdebug_every_nth_store);
2645
2646static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2647{
2648 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2649}
2650static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2651 const char * buf, size_t count)
2652{
2653 int n;
2654
2655 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2656 scsi_debug_max_luns = n;
2657 sdebug_max_tgts_luns();
2658 return count;
2659 }
2660 return -EINVAL;
2661}
2662DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2663 sdebug_max_luns_store);
2664
2665static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2666{
2667 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2668}
2669DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2670
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002671static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2672{
2673 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2674}
2675static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2676 const char * buf, size_t count)
2677{
2678 int n;
2679
2680 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2681 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002682
2683 sdebug_capacity = get_sdebug_capacity();
2684
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002685 return count;
2686 }
2687 return -EINVAL;
2688}
2689DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2690 sdebug_virtual_gb_store);
2691
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2693{
2694 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2695}
2696
2697static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2698 const char * buf, size_t count)
2699{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002700 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002702 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 if (delta_hosts > 0) {
2705 do {
2706 sdebug_add_adapter();
2707 } while (--delta_hosts);
2708 } else if (delta_hosts < 0) {
2709 do {
2710 sdebug_remove_adapter();
2711 } while (++delta_hosts);
2712 }
2713 return count;
2714}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002715DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 sdebug_add_host_store);
2717
Douglas Gilbert23183912006-09-16 20:30:47 -04002718static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2719 char * buf)
2720{
2721 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2722}
2723static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2724 const char * buf, size_t count)
2725{
2726 int n;
2727
2728 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2729 scsi_debug_vpd_use_hostno = n;
2730 return count;
2731 }
2732 return -EINVAL;
2733}
2734DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2735 sdebug_vpd_use_hostno_store);
2736
Martin K. Petersen597136a2008-06-05 00:12:59 -04002737static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
2738{
2739 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
2740}
2741DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
2742
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002743static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
2744{
2745 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
2746}
2747DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
2748
2749static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
2750{
2751 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
2752}
2753DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
2754
2755static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
2756{
2757 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
2758}
2759DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
2760
2761static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
2762{
2763 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
2764}
2765DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
2766
2767
Douglas Gilbert23183912006-09-16 20:30:47 -04002768/* Note: The following function creates attribute files in the
2769 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2770 files (over those found in the /sys/module/scsi_debug/parameters
2771 directory) is that auxiliary actions can be triggered when an attribute
2772 is changed. For example see: sdebug_add_host_store() above.
2773 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002774static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002776 int ret;
2777
2778 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2779 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2780 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2781 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2782 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002783 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002784 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002785 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002786 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002787 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002788 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2789 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2790 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002791 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2792 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002793 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002794 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
2795 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
2796 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
2797 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002798 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799}
2800
2801static void do_remove_driverfs_files(void)
2802{
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002803 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
2804 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
2805 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
2806 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002807 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04002808 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2809 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2811 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2812 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002814 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2815 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002817 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2819 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2820 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2821 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2822 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2823}
2824
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002825static void pseudo_0_release(struct device *dev)
2826{
2827 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2828 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2829}
2830
2831static struct device pseudo_primary = {
Kay Sievers71610f52008-12-03 22:41:36 +01002832 .init_name = "pseudo_0",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002833 .release = pseudo_0_release,
2834};
2835
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836static int __init scsi_debug_init(void)
2837{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002838 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 int host_to_add;
2840 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002841 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842
Martin K. Petersen597136a2008-06-05 00:12:59 -04002843 switch (scsi_debug_sector_size) {
2844 case 512:
2845 case 1024:
2846 case 2048:
2847 case 4096:
2848 break;
2849 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002850 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04002851 scsi_debug_sector_size);
2852 return -EINVAL;
2853 }
2854
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002855 switch (scsi_debug_dif) {
2856
2857 case SD_DIF_TYPE0_PROTECTION:
2858 case SD_DIF_TYPE1_PROTECTION:
2859 case SD_DIF_TYPE3_PROTECTION:
2860 break;
2861
2862 default:
2863 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n");
2864 return -EINVAL;
2865 }
2866
2867 if (scsi_debug_guard > 1) {
2868 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
2869 return -EINVAL;
2870 }
2871
2872 if (scsi_debug_ato > 1) {
2873 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
2874 return -EINVAL;
2875 }
2876
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 if (scsi_debug_dev_size_mb < 1)
2878 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002879 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04002880 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002881 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882
2883 /* play around with geometry, don't waste too much on track 0 */
2884 sdebug_heads = 8;
2885 sdebug_sectors_per = 32;
2886 if (scsi_debug_dev_size_mb >= 16)
2887 sdebug_heads = 32;
2888 else if (scsi_debug_dev_size_mb >= 256)
2889 sdebug_heads = 64;
2890 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2891 (sdebug_sectors_per * sdebug_heads);
2892 if (sdebug_cylinders_per >= 1024) {
2893 /* other LLDs do this; implies >= 1GB ram disk ... */
2894 sdebug_heads = 255;
2895 sdebug_sectors_per = 63;
2896 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2897 (sdebug_sectors_per * sdebug_heads);
2898 }
2899
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 fake_storep = vmalloc(sz);
2901 if (NULL == fake_storep) {
2902 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2903 return -ENOMEM;
2904 }
2905 memset(fake_storep, 0, sz);
2906 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002907 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002909 if (scsi_debug_dif) {
2910 int dif_size;
2911
2912 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
2913 dif_storep = vmalloc(dif_size);
2914
2915 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
2916 dif_size, dif_storep);
2917
2918 if (dif_storep == NULL) {
2919 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
2920 ret = -ENOMEM;
2921 goto free_vm;
2922 }
2923
2924 memset(dif_storep, 0xff, dif_size);
2925 }
2926
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002927 ret = device_register(&pseudo_primary);
2928 if (ret < 0) {
2929 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2930 ret);
2931 goto free_vm;
2932 }
2933 ret = bus_register(&pseudo_lld_bus);
2934 if (ret < 0) {
2935 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2936 ret);
2937 goto dev_unreg;
2938 }
2939 ret = driver_register(&sdebug_driverfs_driver);
2940 if (ret < 0) {
2941 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2942 ret);
2943 goto bus_unreg;
2944 }
2945 ret = do_create_driverfs_files();
2946 if (ret < 0) {
2947 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2948 ret);
2949 goto del_files;
2950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002952 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 host_to_add = scsi_debug_add_host;
2955 scsi_debug_add_host = 0;
2956
2957 for (k = 0; k < host_to_add; k++) {
2958 if (sdebug_add_adapter()) {
2959 printk(KERN_ERR "scsi_debug_init: "
2960 "sdebug_add_adapter failed k=%d\n", k);
2961 break;
2962 }
2963 }
2964
2965 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2966 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2967 scsi_debug_add_host);
2968 }
2969 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002970
2971del_files:
2972 do_remove_driverfs_files();
2973 driver_unregister(&sdebug_driverfs_driver);
2974bus_unreg:
2975 bus_unregister(&pseudo_lld_bus);
2976dev_unreg:
2977 device_unregister(&pseudo_primary);
2978free_vm:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002979 if (dif_storep)
2980 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002981 vfree(fake_storep);
2982
2983 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984}
2985
2986static void __exit scsi_debug_exit(void)
2987{
2988 int k = scsi_debug_add_host;
2989
2990 stop_all_queued();
2991 for (; k; k--)
2992 sdebug_remove_adapter();
2993 do_remove_driverfs_files();
2994 driver_unregister(&sdebug_driverfs_driver);
2995 bus_unregister(&pseudo_lld_bus);
2996 device_unregister(&pseudo_primary);
2997
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002998 if (dif_storep)
2999 vfree(dif_storep);
3000
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 vfree(fake_storep);
3002}
3003
3004device_initcall(scsi_debug_init);
3005module_exit(scsi_debug_exit);
3006
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007static void sdebug_release_adapter(struct device * dev)
3008{
3009 struct sdebug_host_info *sdbg_host;
3010
3011 sdbg_host = to_sdebug_host(dev);
3012 kfree(sdbg_host);
3013}
3014
3015static int sdebug_add_adapter(void)
3016{
3017 int k, devs_per_host;
3018 int error = 0;
3019 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003020 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003022 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 if (NULL == sdbg_host) {
3024 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003025 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 return -ENOMEM;
3027 }
3028
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3030
3031 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3032 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003033 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3034 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003036 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 error = -ENOMEM;
3038 goto clean;
3039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 }
3041
3042 spin_lock(&sdebug_host_list_lock);
3043 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3044 spin_unlock(&sdebug_host_list_lock);
3045
3046 sdbg_host->dev.bus = &pseudo_lld_bus;
3047 sdbg_host->dev.parent = &pseudo_primary;
3048 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003049 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050
3051 error = device_register(&sdbg_host->dev);
3052
3053 if (error)
3054 goto clean;
3055
3056 ++scsi_debug_add_host;
3057 return error;
3058
3059clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003060 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3061 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 list_del(&sdbg_devinfo->dev_list);
3063 kfree(sdbg_devinfo);
3064 }
3065
3066 kfree(sdbg_host);
3067 return error;
3068}
3069
3070static void sdebug_remove_adapter(void)
3071{
3072 struct sdebug_host_info * sdbg_host = NULL;
3073
3074 spin_lock(&sdebug_host_list_lock);
3075 if (!list_empty(&sdebug_host_list)) {
3076 sdbg_host = list_entry(sdebug_host_list.prev,
3077 struct sdebug_host_info, host_list);
3078 list_del(&sdbg_host->host_list);
3079 }
3080 spin_unlock(&sdebug_host_list_lock);
3081
3082 if (!sdbg_host)
3083 return;
3084
3085 device_unregister(&sdbg_host->dev);
3086 --scsi_debug_add_host;
3087}
3088
FUJITA Tomonori639db472008-03-20 11:09:19 +09003089static
3090int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
3091{
3092 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3093 int len, k;
3094 unsigned int num;
3095 unsigned long long lba;
3096 int errsts = 0;
3097 int target = SCpnt->device->id;
3098 struct sdebug_dev_info *devip = NULL;
3099 int inj_recovered = 0;
3100 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003101 int inj_dif = 0;
3102 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003103 int delay_override = 0;
3104
3105 scsi_set_resid(SCpnt, 0);
3106 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3107 printk(KERN_INFO "scsi_debug: cmd ");
3108 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3109 printk("%02x ", (int)cmd[k]);
3110 printk("\n");
3111 }
3112
3113 if (target == SCpnt->device->host->hostt->this_id) {
3114 printk(KERN_INFO "scsi_debug: initiator's id used as "
3115 "target!\n");
3116 return schedule_resp(SCpnt, NULL, done,
3117 DID_NO_CONNECT << 16, 0);
3118 }
3119
3120 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3121 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3122 return schedule_resp(SCpnt, NULL, done,
3123 DID_NO_CONNECT << 16, 0);
3124 devip = devInfoReg(SCpnt->device);
3125 if (NULL == devip)
3126 return schedule_resp(SCpnt, NULL, done,
3127 DID_NO_CONNECT << 16, 0);
3128
3129 if ((scsi_debug_every_nth != 0) &&
3130 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3131 scsi_debug_cmnd_count = 0;
3132 if (scsi_debug_every_nth < -1)
3133 scsi_debug_every_nth = -1;
3134 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3135 return 0; /* ignore command causing timeout */
3136 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3137 inj_recovered = 1; /* to reads and writes below */
3138 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3139 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003140 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3141 inj_dif = 1; /* to reads and writes below */
3142 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3143 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003144 }
3145
3146 if (devip->wlun) {
3147 switch (*cmd) {
3148 case INQUIRY:
3149 case REQUEST_SENSE:
3150 case TEST_UNIT_READY:
3151 case REPORT_LUNS:
3152 break; /* only allowable wlun commands */
3153 default:
3154 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3155 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3156 "not supported for wlun\n", *cmd);
3157 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3158 INVALID_OPCODE, 0);
3159 errsts = check_condition_result;
3160 return schedule_resp(SCpnt, devip, done, errsts,
3161 0);
3162 }
3163 }
3164
3165 switch (*cmd) {
3166 case INQUIRY: /* mandatory, ignore unit attention */
3167 delay_override = 1;
3168 errsts = resp_inquiry(SCpnt, target, devip);
3169 break;
3170 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3171 delay_override = 1;
3172 errsts = resp_requests(SCpnt, devip);
3173 break;
3174 case REZERO_UNIT: /* actually this is REWIND for SSC */
3175 case START_STOP:
3176 errsts = resp_start_stop(SCpnt, devip);
3177 break;
3178 case ALLOW_MEDIUM_REMOVAL:
3179 errsts = check_readiness(SCpnt, 1, devip);
3180 if (errsts)
3181 break;
3182 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3183 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3184 cmd[4] ? "inhibited" : "enabled");
3185 break;
3186 case SEND_DIAGNOSTIC: /* mandatory */
3187 errsts = check_readiness(SCpnt, 1, devip);
3188 break;
3189 case TEST_UNIT_READY: /* mandatory */
3190 delay_override = 1;
3191 errsts = check_readiness(SCpnt, 0, devip);
3192 break;
3193 case RESERVE:
3194 errsts = check_readiness(SCpnt, 1, devip);
3195 break;
3196 case RESERVE_10:
3197 errsts = check_readiness(SCpnt, 1, devip);
3198 break;
3199 case RELEASE:
3200 errsts = check_readiness(SCpnt, 1, devip);
3201 break;
3202 case RELEASE_10:
3203 errsts = check_readiness(SCpnt, 1, devip);
3204 break;
3205 case READ_CAPACITY:
3206 errsts = resp_readcap(SCpnt, devip);
3207 break;
3208 case SERVICE_ACTION_IN:
3209 if (SAI_READ_CAPACITY_16 != cmd[1]) {
3210 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3211 INVALID_OPCODE, 0);
3212 errsts = check_condition_result;
3213 break;
3214 }
3215 errsts = resp_readcap16(SCpnt, devip);
3216 break;
3217 case MAINTENANCE_IN:
3218 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3219 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3220 INVALID_OPCODE, 0);
3221 errsts = check_condition_result;
3222 break;
3223 }
3224 errsts = resp_report_tgtpgs(SCpnt, devip);
3225 break;
3226 case READ_16:
3227 case READ_12:
3228 case READ_10:
3229 case READ_6:
3230 errsts = check_readiness(SCpnt, 0, devip);
3231 if (errsts)
3232 break;
3233 if (scsi_debug_fake_rw)
3234 break;
3235 get_data_transfer_info(cmd, &lba, &num);
3236 errsts = resp_read(SCpnt, lba, num, devip);
3237 if (inj_recovered && (0 == errsts)) {
3238 mk_sense_buffer(devip, RECOVERED_ERROR,
3239 THRESHOLD_EXCEEDED, 0);
3240 errsts = check_condition_result;
3241 } else if (inj_transport && (0 == errsts)) {
3242 mk_sense_buffer(devip, ABORTED_COMMAND,
3243 TRANSPORT_PROBLEM, ACK_NAK_TO);
3244 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003245 } else if (inj_dif && (0 == errsts)) {
3246 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3247 errsts = illegal_condition_result;
3248 } else if (inj_dix && (0 == errsts)) {
3249 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3250 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003251 }
3252 break;
3253 case REPORT_LUNS: /* mandatory, ignore unit attention */
3254 delay_override = 1;
3255 errsts = resp_report_luns(SCpnt, devip);
3256 break;
3257 case VERIFY: /* 10 byte SBC-2 command */
3258 errsts = check_readiness(SCpnt, 0, devip);
3259 break;
3260 case WRITE_16:
3261 case WRITE_12:
3262 case WRITE_10:
3263 case WRITE_6:
3264 errsts = check_readiness(SCpnt, 0, devip);
3265 if (errsts)
3266 break;
3267 if (scsi_debug_fake_rw)
3268 break;
3269 get_data_transfer_info(cmd, &lba, &num);
3270 errsts = resp_write(SCpnt, lba, num, devip);
3271 if (inj_recovered && (0 == errsts)) {
3272 mk_sense_buffer(devip, RECOVERED_ERROR,
3273 THRESHOLD_EXCEEDED, 0);
3274 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003275 } else if (inj_dif && (0 == errsts)) {
3276 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3277 errsts = illegal_condition_result;
3278 } else if (inj_dix && (0 == errsts)) {
3279 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3280 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003281 }
3282 break;
3283 case MODE_SENSE:
3284 case MODE_SENSE_10:
3285 errsts = resp_mode_sense(SCpnt, target, devip);
3286 break;
3287 case MODE_SELECT:
3288 errsts = resp_mode_select(SCpnt, 1, devip);
3289 break;
3290 case MODE_SELECT_10:
3291 errsts = resp_mode_select(SCpnt, 0, devip);
3292 break;
3293 case LOG_SENSE:
3294 errsts = resp_log_sense(SCpnt, devip);
3295 break;
3296 case SYNCHRONIZE_CACHE:
3297 delay_override = 1;
3298 errsts = check_readiness(SCpnt, 0, devip);
3299 break;
3300 case WRITE_BUFFER:
3301 errsts = check_readiness(SCpnt, 1, devip);
3302 break;
3303 case XDWRITEREAD_10:
3304 if (!scsi_bidi_cmnd(SCpnt)) {
3305 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3306 INVALID_FIELD_IN_CDB, 0);
3307 errsts = check_condition_result;
3308 break;
3309 }
3310
3311 errsts = check_readiness(SCpnt, 0, devip);
3312 if (errsts)
3313 break;
3314 if (scsi_debug_fake_rw)
3315 break;
3316 get_data_transfer_info(cmd, &lba, &num);
3317 errsts = resp_read(SCpnt, lba, num, devip);
3318 if (errsts)
3319 break;
3320 errsts = resp_write(SCpnt, lba, num, devip);
3321 if (errsts)
3322 break;
3323 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3324 break;
3325 default:
3326 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3327 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3328 "supported\n", *cmd);
3329 errsts = check_readiness(SCpnt, 1, devip);
3330 if (errsts)
3331 break; /* Unit attention takes precedence */
3332 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3333 errsts = check_condition_result;
3334 break;
3335 }
3336 return schedule_resp(SCpnt, devip, done, errsts,
3337 (delay_override ? 0 : scsi_debug_delay));
3338}
3339
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003340static struct scsi_host_template sdebug_driver_template = {
3341 .proc_info = scsi_debug_proc_info,
3342 .proc_name = sdebug_proc_name,
3343 .name = "SCSI DEBUG",
3344 .info = scsi_debug_info,
3345 .slave_alloc = scsi_debug_slave_alloc,
3346 .slave_configure = scsi_debug_slave_configure,
3347 .slave_destroy = scsi_debug_slave_destroy,
3348 .ioctl = scsi_debug_ioctl,
3349 .queuecommand = scsi_debug_queuecommand,
3350 .eh_abort_handler = scsi_debug_abort,
3351 .eh_bus_reset_handler = scsi_debug_bus_reset,
3352 .eh_device_reset_handler = scsi_debug_device_reset,
3353 .eh_host_reset_handler = scsi_debug_host_reset,
3354 .bios_param = scsi_debug_biosparam,
3355 .can_queue = SCSI_DEBUG_CANQUEUE,
3356 .this_id = 7,
3357 .sg_tablesize = 256,
3358 .cmd_per_lun = 16,
3359 .max_sectors = 0xffff,
3360 .use_clustering = DISABLE_CLUSTERING,
3361 .module = THIS_MODULE,
3362};
3363
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364static int sdebug_driver_probe(struct device * dev)
3365{
3366 int error = 0;
3367 struct sdebug_host_info *sdbg_host;
3368 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003369 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
3371 sdbg_host = to_sdebug_host(dev);
3372
3373 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3374 if (NULL == hpnt) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003375 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 error = -ENODEV;
3377 return error;
3378 }
3379
3380 sdbg_host->shost = hpnt;
3381 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3382 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3383 hpnt->max_id = scsi_debug_num_tgts + 1;
3384 else
3385 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003386 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003388 host_prot = 0;
3389
3390 switch (scsi_debug_dif) {
3391
3392 case SD_DIF_TYPE1_PROTECTION:
3393 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3394 if (scsi_debug_dix)
3395 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3396 break;
3397
3398 case SD_DIF_TYPE2_PROTECTION:
3399 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3400 if (scsi_debug_dix)
3401 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3402 break;
3403
3404 case SD_DIF_TYPE3_PROTECTION:
3405 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3406 if (scsi_debug_dix)
3407 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3408 break;
3409
3410 default:
3411 if (scsi_debug_dix)
3412 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3413 break;
3414 }
3415
3416 scsi_host_set_prot(hpnt, host_prot);
3417
3418 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3419 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3420 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3421 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3422 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3423 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3424 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3425 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3426
3427 if (scsi_debug_guard == 1)
3428 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3429 else
3430 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3431
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 error = scsi_add_host(hpnt, &sdbg_host->dev);
3433 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003434 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 error = -ENODEV;
3436 scsi_host_put(hpnt);
3437 } else
3438 scsi_scan_host(hpnt);
3439
3440
3441 return error;
3442}
3443
3444static int sdebug_driver_remove(struct device * dev)
3445{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003447 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448
3449 sdbg_host = to_sdebug_host(dev);
3450
3451 if (!sdbg_host) {
3452 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003453 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 return -ENODEV;
3455 }
3456
3457 scsi_remove_host(sdbg_host->shost);
3458
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003459 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3460 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 list_del(&sdbg_devinfo->dev_list);
3462 kfree(sdbg_devinfo);
3463 }
3464
3465 scsi_host_put(sdbg_host->shost);
3466 return 0;
3467}
3468
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003469static int pseudo_lld_bus_match(struct device *dev,
3470 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003472 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003474
3475static struct bus_type pseudo_lld_bus = {
3476 .name = "pseudo",
3477 .match = pseudo_lld_bus_match,
3478 .probe = sdebug_driver_probe,
3479 .remove = sdebug_driver_remove,
3480};