blob: fb9af207d61dea365d3c3128809ada1da7258258 [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
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400104#define DEF_PHYSBLK_EXP 0
105#define DEF_LOWEST_ALIGNED 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107/* bit mask values for scsi_debug_opts */
108#define SCSI_DEBUG_OPT_NOISE 1
109#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
110#define SCSI_DEBUG_OPT_TIMEOUT 4
111#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500112#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500113#define SCSI_DEBUG_OPT_DIF_ERR 32
114#define SCSI_DEBUG_OPT_DIX_ERR 64
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115/* When "every_nth" > 0 then modulo "every_nth" commands:
116 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
117 * - a RECOVERED_ERROR is simulated on successful read and write
118 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500119 * - a TRANSPORT_ERROR is simulated on successful read and write
120 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 *
122 * When "every_nth" < 0 then after "- every_nth" commands:
123 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
124 * - a RECOVERED_ERROR is simulated on successful read and write
125 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500126 * - a TRANSPORT_ERROR is simulated on successful read and write
127 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 * This will continue until some other action occurs (e.g. the user
129 * writing a new value (other than -1 or 1) to every_nth via sysfs).
130 */
131
132/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
133 * sector on read commands: */
134#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
135
136/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
137 * or "peripheral device" addressing (value 0) */
138#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400139#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141static int scsi_debug_add_host = DEF_NUM_HOST;
142static int scsi_debug_delay = DEF_DELAY;
143static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
144static int scsi_debug_every_nth = DEF_EVERY_NTH;
145static int scsi_debug_max_luns = DEF_MAX_LUNS;
146static int scsi_debug_num_parts = DEF_NUM_PARTS;
147static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
148static int scsi_debug_opts = DEF_OPTS;
149static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
150static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
151static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400152static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
153static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400154static int scsi_debug_fake_rw = DEF_FAKE_RW;
155static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400156static int scsi_debug_sector_size = DEF_SECTOR_SIZE;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500157static int scsi_debug_dix = DEF_DIX;
158static int scsi_debug_dif = DEF_DIF;
159static int scsi_debug_guard = DEF_GUARD;
160static int scsi_debug_ato = DEF_ATO;
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400161static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;
162static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164static int scsi_debug_cmnd_count = 0;
165
166#define DEV_READONLY(TGT) (0)
167#define DEV_REMOVEABLE(TGT) (0)
168
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400169static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170static sector_t sdebug_capacity; /* in sectors */
171
172/* old BIOS stuff, kernel may get rid of them but some mode sense pages
173 may still need them */
174static int sdebug_heads; /* heads per disk */
175static int sdebug_cylinders_per; /* cylinders per surface */
176static int sdebug_sectors_per; /* sectors per cylinder */
177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178#define SDEBUG_MAX_PARTS 4
179
180#define SDEBUG_SENSE_LEN 32
181
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900182#define SCSI_DEBUG_CANQUEUE 255
183#define SCSI_DEBUG_MAX_CMD_LEN 16
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185struct sdebug_dev_info {
186 struct list_head dev_list;
187 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
188 unsigned int channel;
189 unsigned int target;
190 unsigned int lun;
191 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400192 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400194 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 char used;
196};
197
198struct sdebug_host_info {
199 struct list_head host_list;
200 struct Scsi_Host *shost;
201 struct device dev;
202 struct list_head dev_info_list;
203};
204
205#define to_sdebug_host(d) \
206 container_of(d, struct sdebug_host_info, dev)
207
208static LIST_HEAD(sdebug_host_list);
209static DEFINE_SPINLOCK(sdebug_host_list_lock);
210
211typedef void (* done_funct_t) (struct scsi_cmnd *);
212
213struct sdebug_queued_cmd {
214 int in_use;
215 struct timer_list cmnd_timer;
216 done_funct_t done_funct;
217 struct scsi_cmnd * a_cmnd;
218 int scsi_result;
219};
220static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222static unsigned char * fake_storep; /* ramdisk storage */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500223static unsigned char *dif_storep; /* protection info */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225static int num_aborts = 0;
226static int num_dev_resets = 0;
227static int num_bus_resets = 0;
228static int num_host_resets = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500229static int dix_writes;
230static int dix_reads;
231static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233static DEFINE_SPINLOCK(queued_arr_lock);
234static DEFINE_RWLOCK(atomic_rw);
235
236static char sdebug_proc_name[] = "scsi_debug";
237
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238static struct bus_type pseudo_lld_bus;
239
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500240static inline sector_t dif_offset(sector_t sector)
241{
242 return sector << 3;
243}
244
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245static struct device_driver sdebug_driverfs_driver = {
246 .name = sdebug_proc_name,
247 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248};
249
250static const int check_condition_result =
251 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
252
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500253static const int illegal_condition_result =
254 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
255
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400256static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
257 0, 0, 0x2, 0x4b};
258static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
259 0, 0, 0x0, 0x0};
260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261static int sdebug_add_adapter(void);
262static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900264static void sdebug_max_tgts_luns(void)
265{
266 struct sdebug_host_info *sdbg_host;
267 struct Scsi_Host *hpnt;
268
269 spin_lock(&sdebug_host_list_lock);
270 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
271 hpnt = sdbg_host->shost;
272 if ((hpnt->this_id >= 0) &&
273 (scsi_debug_num_tgts > hpnt->this_id))
274 hpnt->max_id = scsi_debug_num_tgts + 1;
275 else
276 hpnt->max_id = scsi_debug_num_tgts;
277 /* scsi_debug_max_luns; */
278 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
279 }
280 spin_unlock(&sdebug_host_list_lock);
281}
282
283static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
284 int asc, int asq)
285{
286 unsigned char *sbuff;
287
288 sbuff = devip->sense_buff;
289 memset(sbuff, 0, SDEBUG_SENSE_LEN);
290
291 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
292
293 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
294 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
295 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
296}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900298static void get_data_transfer_info(unsigned char *cmd,
299 unsigned long long *lba, unsigned int *num)
300{
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900301 switch (*cmd) {
302 case WRITE_16:
303 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900304 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
305 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
306 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
307 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
308
309 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
310 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900311 break;
312 case WRITE_12:
313 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900314 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
315 (u32)cmd[2] << 24;
316
317 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
318 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900319 break;
320 case WRITE_10:
321 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900322 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900323 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
324 (u32)cmd[2] << 24;
325
326 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900327 break;
328 case WRITE_6:
329 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900330 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
331 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900332 *num = (0 == cmd[4]) ? 256 : cmd[4];
333 break;
334 default:
335 break;
336 }
337}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
340{
341 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
342 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
343 }
344 return -EINVAL;
345 /* return -ENOTTY; // correct return but upsets fdisk */
346}
347
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400348static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
349 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 if (devip->reset) {
352 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
353 printk(KERN_INFO "scsi_debug: Reporting Unit "
354 "attention: power on reset\n");
355 devip->reset = 0;
356 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
357 return check_condition_result;
358 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400359 if ((0 == reset_only) && devip->stopped) {
360 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
361 printk(KERN_INFO "scsi_debug: Reporting Not "
362 "ready: initializing command required\n");
363 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
364 0x2);
365 return check_condition_result;
366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return 0;
368}
369
370/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900371static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 int arr_len)
373{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900374 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900375 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900377 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900379 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900381
382 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
383 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900384 if (sdb->resid)
385 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400386 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900387 sdb->resid = scsi_bufflen(scp) - act_len;
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return 0;
390}
391
392/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900393static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
394 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900396 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900398 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900400
401 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402}
403
404
405static const char * inq_vendor_id = "Linux ";
406static const char * inq_product_id = "scsi_debug ";
407static const char * inq_product_rev = "0004";
408
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200409static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
410 int target_dev_id, int dev_id_num,
411 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400412 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400414 int num, port_a;
415 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400417 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 /* T10 vendor identifier field format (faked) */
419 arr[0] = 0x2; /* ASCII */
420 arr[1] = 0x1;
421 arr[2] = 0x0;
422 memcpy(&arr[4], inq_vendor_id, 8);
423 memcpy(&arr[12], inq_product_id, 16);
424 memcpy(&arr[28], dev_id_str, dev_id_str_len);
425 num = 8 + 16 + dev_id_str_len;
426 arr[3] = num;
427 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400428 if (dev_id_num >= 0) {
429 /* NAA-5, Logical unit identifier (binary) */
430 arr[num++] = 0x1; /* binary (not necessarily sas) */
431 arr[num++] = 0x3; /* PIV=0, lu, naa */
432 arr[num++] = 0x0;
433 arr[num++] = 0x8;
434 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
435 arr[num++] = 0x33;
436 arr[num++] = 0x33;
437 arr[num++] = 0x30;
438 arr[num++] = (dev_id_num >> 24);
439 arr[num++] = (dev_id_num >> 16) & 0xff;
440 arr[num++] = (dev_id_num >> 8) & 0xff;
441 arr[num++] = dev_id_num & 0xff;
442 /* Target relative port number */
443 arr[num++] = 0x61; /* proto=sas, binary */
444 arr[num++] = 0x94; /* PIV=1, target port, rel port */
445 arr[num++] = 0x0; /* reserved */
446 arr[num++] = 0x4; /* length */
447 arr[num++] = 0x0; /* reserved */
448 arr[num++] = 0x0; /* reserved */
449 arr[num++] = 0x0;
450 arr[num++] = 0x1; /* relative port A */
451 }
452 /* NAA-5, Target port identifier */
453 arr[num++] = 0x61; /* proto=sas, binary */
454 arr[num++] = 0x93; /* piv=1, target port, naa */
455 arr[num++] = 0x0;
456 arr[num++] = 0x8;
457 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
458 arr[num++] = 0x22;
459 arr[num++] = 0x22;
460 arr[num++] = 0x20;
461 arr[num++] = (port_a >> 24);
462 arr[num++] = (port_a >> 16) & 0xff;
463 arr[num++] = (port_a >> 8) & 0xff;
464 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200465 /* NAA-5, Target port group identifier */
466 arr[num++] = 0x61; /* proto=sas, binary */
467 arr[num++] = 0x95; /* piv=1, target port group id */
468 arr[num++] = 0x0;
469 arr[num++] = 0x4;
470 arr[num++] = 0;
471 arr[num++] = 0;
472 arr[num++] = (port_group_id >> 8) & 0xff;
473 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400474 /* NAA-5, Target device identifier */
475 arr[num++] = 0x61; /* proto=sas, binary */
476 arr[num++] = 0xa3; /* piv=1, target device, naa */
477 arr[num++] = 0x0;
478 arr[num++] = 0x8;
479 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
480 arr[num++] = 0x22;
481 arr[num++] = 0x22;
482 arr[num++] = 0x20;
483 arr[num++] = (target_dev_id >> 24);
484 arr[num++] = (target_dev_id >> 16) & 0xff;
485 arr[num++] = (target_dev_id >> 8) & 0xff;
486 arr[num++] = target_dev_id & 0xff;
487 /* SCSI name string: Target device identifier */
488 arr[num++] = 0x63; /* proto=sas, UTF-8 */
489 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
490 arr[num++] = 0x0;
491 arr[num++] = 24;
492 memcpy(arr + num, "naa.52222220", 12);
493 num += 12;
494 snprintf(b, sizeof(b), "%08X", target_dev_id);
495 memcpy(arr + num, b, 8);
496 num += 8;
497 memset(arr + num, 0, 4);
498 num += 4;
499 return num;
500}
501
502
503static unsigned char vpd84_data[] = {
504/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
505 0x22,0x22,0x22,0x0,0xbb,0x1,
506 0x22,0x22,0x22,0x0,0xbb,0x2,
507};
508
509static int inquiry_evpd_84(unsigned char * arr)
510{
511 memcpy(arr, vpd84_data, sizeof(vpd84_data));
512 return sizeof(vpd84_data);
513}
514
515static int inquiry_evpd_85(unsigned char * arr)
516{
517 int num = 0;
518 const char * na1 = "https://www.kernel.org/config";
519 const char * na2 = "http://www.kernel.org/log";
520 int plen, olen;
521
522 arr[num++] = 0x1; /* lu, storage config */
523 arr[num++] = 0x0; /* reserved */
524 arr[num++] = 0x0;
525 olen = strlen(na1);
526 plen = olen + 1;
527 if (plen % 4)
528 plen = ((plen / 4) + 1) * 4;
529 arr[num++] = plen; /* length, null termianted, padded */
530 memcpy(arr + num, na1, olen);
531 memset(arr + num + olen, 0, plen - olen);
532 num += plen;
533
534 arr[num++] = 0x4; /* lu, logging */
535 arr[num++] = 0x0; /* reserved */
536 arr[num++] = 0x0;
537 olen = strlen(na2);
538 plen = olen + 1;
539 if (plen % 4)
540 plen = ((plen / 4) + 1) * 4;
541 arr[num++] = plen; /* length, null terminated, padded */
542 memcpy(arr + num, na2, olen);
543 memset(arr + num + olen, 0, plen - olen);
544 num += plen;
545
546 return num;
547}
548
549/* SCSI ports VPD page */
550static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
551{
552 int num = 0;
553 int port_a, port_b;
554
555 port_a = target_dev_id + 1;
556 port_b = port_a + 1;
557 arr[num++] = 0x0; /* reserved */
558 arr[num++] = 0x0; /* reserved */
559 arr[num++] = 0x0;
560 arr[num++] = 0x1; /* relative port 1 (primary) */
561 memset(arr + num, 0, 6);
562 num += 6;
563 arr[num++] = 0x0;
564 arr[num++] = 12; /* length tp descriptor */
565 /* naa-5 target port identifier (A) */
566 arr[num++] = 0x61; /* proto=sas, binary */
567 arr[num++] = 0x93; /* PIV=1, target port, NAA */
568 arr[num++] = 0x0; /* reserved */
569 arr[num++] = 0x8; /* length */
570 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
571 arr[num++] = 0x22;
572 arr[num++] = 0x22;
573 arr[num++] = 0x20;
574 arr[num++] = (port_a >> 24);
575 arr[num++] = (port_a >> 16) & 0xff;
576 arr[num++] = (port_a >> 8) & 0xff;
577 arr[num++] = port_a & 0xff;
578
579 arr[num++] = 0x0; /* reserved */
580 arr[num++] = 0x0; /* reserved */
581 arr[num++] = 0x0;
582 arr[num++] = 0x2; /* relative port 2 (secondary) */
583 memset(arr + num, 0, 6);
584 num += 6;
585 arr[num++] = 0x0;
586 arr[num++] = 12; /* length tp descriptor */
587 /* naa-5 target port identifier (B) */
588 arr[num++] = 0x61; /* proto=sas, binary */
589 arr[num++] = 0x93; /* PIV=1, target port, NAA */
590 arr[num++] = 0x0; /* reserved */
591 arr[num++] = 0x8; /* length */
592 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
593 arr[num++] = 0x22;
594 arr[num++] = 0x22;
595 arr[num++] = 0x20;
596 arr[num++] = (port_b >> 24);
597 arr[num++] = (port_b >> 16) & 0xff;
598 arr[num++] = (port_b >> 8) & 0xff;
599 arr[num++] = port_b & 0xff;
600
601 return num;
602}
603
604
605static unsigned char vpd89_data[] = {
606/* from 4th byte */ 0,0,0,0,
607'l','i','n','u','x',' ',' ',' ',
608'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
609'1','2','3','4',
6100x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
6110xec,0,0,0,
6120x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
6130,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
6140x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
6150x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
6160x53,0x41,
6170x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6180x20,0x20,
6190x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
6200x10,0x80,
6210,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
6220x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
6230x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
6240,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6250x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6260x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6270,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6290,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6300,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6310x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6320,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6330xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6340,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
6430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6450,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6460,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
647};
648
649static int inquiry_evpd_89(unsigned char * arr)
650{
651 memcpy(arr, vpd89_data, sizeof(vpd89_data));
652 return sizeof(vpd89_data);
653}
654
655
656static unsigned char vpdb0_data[] = {
657 /* from 4th byte */ 0,0,0,4,
658 0,0,0x4,0,
659 0,0,0,64,
660};
661
662static int inquiry_evpd_b0(unsigned char * arr)
663{
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400664 unsigned int gran;
665
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400666 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400667 gran = 1 << scsi_debug_physblk_exp;
668 arr[2] = (gran >> 8) & 0xff;
669 arr[3] = gran & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400670 if (sdebug_store_sectors > 0x400) {
671 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
672 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
673 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
674 arr[7] = sdebug_store_sectors & 0xff;
675 }
676 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600679static int inquiry_evpd_b1(unsigned char *arr)
680{
681 memset(arr, 0, 0x3c);
682 arr[0] = 0;
683 arr[1] = 1;
684
685 return 0x3c;
686}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400689#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691static int resp_inquiry(struct scsi_cmnd * scp, int target,
692 struct sdebug_dev_info * devip)
693{
694 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200695 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200697 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500700 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
701 if (! arr)
702 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400703 if (devip->wlun)
704 pq_pdt = 0x1e; /* present, wlun */
705 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
706 pq_pdt = 0x7f; /* not present, no device type */
707 else
708 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 arr[0] = pq_pdt;
710 if (0x2 & cmd[1]) { /* CMDDT bit set */
711 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
712 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200713 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 return check_condition_result;
715 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200716 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400717 char lu_id_str[6];
718 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200720 port_group_id = (((host_no + 1) & 0x7f) << 8) +
721 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400722 if (0 == scsi_debug_vpd_use_hostno)
723 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400724 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
725 (devip->target * 1000) + devip->lun);
726 target_dev_id = ((host_no + 1) * 2000) +
727 (devip->target * 1000) - 3;
728 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400730 arr[1] = cmd[2]; /*sanity */
731 n = 4;
732 arr[n++] = 0x0; /* this page */
733 arr[n++] = 0x80; /* unit serial number */
734 arr[n++] = 0x83; /* device identification */
735 arr[n++] = 0x84; /* software interface ident. */
736 arr[n++] = 0x85; /* management network addresses */
737 arr[n++] = 0x86; /* extended inquiry */
738 arr[n++] = 0x87; /* mode page policy */
739 arr[n++] = 0x88; /* SCSI ports */
740 arr[n++] = 0x89; /* ATA information */
741 arr[n++] = 0xb0; /* Block limits (SBC) */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600742 arr[n++] = 0xb1; /* Block characteristics (SBC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400743 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400745 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400747 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400749 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200750 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
751 target_dev_id, lu_id_num,
752 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400753 } else if (0x84 == cmd[2]) { /* Software interface ident. */
754 arr[1] = cmd[2]; /*sanity */
755 arr[3] = inquiry_evpd_84(&arr[4]);
756 } else if (0x85 == cmd[2]) { /* Management network addresses */
757 arr[1] = cmd[2]; /*sanity */
758 arr[3] = inquiry_evpd_85(&arr[4]);
759 } else if (0x86 == cmd[2]) { /* extended inquiry */
760 arr[1] = cmd[2]; /*sanity */
761 arr[3] = 0x3c; /* number of following entries */
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500762 if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION)
763 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
764 else if (scsi_debug_dif)
765 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
766 else
767 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400768 arr[5] = 0x7; /* head of q, ordered + simple q's */
769 } else if (0x87 == cmd[2]) { /* mode page policy */
770 arr[1] = cmd[2]; /*sanity */
771 arr[3] = 0x8; /* number of following entries */
772 arr[4] = 0x2; /* disconnect-reconnect mp */
773 arr[6] = 0x80; /* mlus, shared */
774 arr[8] = 0x18; /* protocol specific lu */
775 arr[10] = 0x82; /* mlus, per initiator port */
776 } else if (0x88 == cmd[2]) { /* SCSI Ports */
777 arr[1] = cmd[2]; /*sanity */
778 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
779 } else if (0x89 == cmd[2]) { /* ATA information */
780 arr[1] = cmd[2]; /*sanity */
781 n = inquiry_evpd_89(&arr[4]);
782 arr[2] = (n >> 8);
783 arr[3] = (n & 0xff);
784 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
785 arr[1] = cmd[2]; /*sanity */
786 arr[3] = inquiry_evpd_b0(&arr[4]);
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -0600787 } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */
788 arr[1] = cmd[2]; /*sanity */
789 arr[3] = inquiry_evpd_b1(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 } else {
791 /* Illegal request, invalid field in cdb */
792 mk_sense_buffer(devip, ILLEGAL_REQUEST,
793 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200794 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 return check_condition_result;
796 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400797 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200798 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400799 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200800 kfree(arr);
801 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 }
803 /* drops through here for a standard inquiry */
804 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
805 arr[2] = scsi_debug_scsi_level;
806 arr[3] = 2; /* response_data_format==2 */
807 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500808 arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200809 if (0 == scsi_debug_vpd_use_hostno)
810 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400811 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400813 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 memcpy(&arr[8], inq_vendor_id, 8);
815 memcpy(&arr[16], inq_product_id, 16);
816 memcpy(&arr[32], inq_product_rev, 4);
817 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400818 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
819 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
820 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400822 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400824 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400826 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200827 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200829 kfree(arr);
830 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831}
832
833static int resp_requests(struct scsi_cmnd * scp,
834 struct sdebug_dev_info * devip)
835{
836 unsigned char * sbuff;
837 unsigned char *cmd = (unsigned char *)scp->cmnd;
838 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400839 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 int len = 18;
841
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400842 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400844 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
845 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400847 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
848 if (want_dsense) {
849 arr[0] = 0x72;
850 arr[1] = 0x0; /* NO_SENSE in sense_key */
851 arr[2] = THRESHOLD_EXCEEDED;
852 arr[3] = 0xff; /* TEST set and MRIE==6 */
853 } else {
854 arr[0] = 0x70;
855 arr[2] = 0x0; /* NO_SENSE in sense_key */
856 arr[7] = 0xa; /* 18 byte sense buffer */
857 arr[12] = THRESHOLD_EXCEEDED;
858 arr[13] = 0xff; /* TEST set and MRIE==6 */
859 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400860 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400862 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
863 /* DESC bit set and sense_buff in fixed format */
864 memset(arr, 0, sizeof(arr));
865 arr[0] = 0x72;
866 arr[1] = sbuff[2]; /* sense key */
867 arr[2] = sbuff[12]; /* asc */
868 arr[3] = sbuff[13]; /* ascq */
869 len = 8;
870 }
871 }
872 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 return fill_from_dev_buffer(scp, arr, len);
874}
875
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400876static int resp_start_stop(struct scsi_cmnd * scp,
877 struct sdebug_dev_info * devip)
878{
879 unsigned char *cmd = (unsigned char *)scp->cmnd;
880 int power_cond, errsts, start;
881
882 if ((errsts = check_readiness(scp, 1, devip)))
883 return errsts;
884 power_cond = (cmd[4] & 0xf0) >> 4;
885 if (power_cond) {
886 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
887 0);
888 return check_condition_result;
889 }
890 start = cmd[4] & 1;
891 if (start == devip->stopped)
892 devip->stopped = !start;
893 return 0;
894}
895
FUJITA Tomonori28898872008-03-30 00:59:55 +0900896static sector_t get_sdebug_capacity(void)
897{
898 if (scsi_debug_virtual_gb > 0)
FUJITA Tomonori73da9c12009-04-22 17:42:25 -0700899 return 2048 * 1024 * (sector_t)scsi_debug_virtual_gb;
FUJITA Tomonori28898872008-03-30 00:59:55 +0900900 else
901 return sdebug_store_sectors;
902}
903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904#define SDEBUG_READCAP_ARR_SZ 8
905static int resp_readcap(struct scsi_cmnd * scp,
906 struct sdebug_dev_info * devip)
907{
908 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400909 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 int errsts;
911
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400912 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400914 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900915 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400917 if (sdebug_capacity < 0xffffffff) {
918 capac = (unsigned int)sdebug_capacity - 1;
919 arr[0] = (capac >> 24);
920 arr[1] = (capac >> 16) & 0xff;
921 arr[2] = (capac >> 8) & 0xff;
922 arr[3] = capac & 0xff;
923 } else {
924 arr[0] = 0xff;
925 arr[1] = 0xff;
926 arr[2] = 0xff;
927 arr[3] = 0xff;
928 }
Martin K. Petersen597136a2008-06-05 00:12:59 -0400929 arr[6] = (scsi_debug_sector_size >> 8) & 0xff;
930 arr[7] = scsi_debug_sector_size & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
932}
933
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400934#define SDEBUG_READCAP16_ARR_SZ 32
935static int resp_readcap16(struct scsi_cmnd * scp,
936 struct sdebug_dev_info * devip)
937{
938 unsigned char *cmd = (unsigned char *)scp->cmnd;
939 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
940 unsigned long long capac;
941 int errsts, k, alloc_len;
942
943 if ((errsts = check_readiness(scp, 1, devip)))
944 return errsts;
945 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
946 + cmd[13]);
947 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900948 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400949 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
950 capac = sdebug_capacity - 1;
951 for (k = 0; k < 8; ++k, capac >>= 8)
952 arr[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -0400953 arr[8] = (scsi_debug_sector_size >> 24) & 0xff;
954 arr[9] = (scsi_debug_sector_size >> 16) & 0xff;
955 arr[10] = (scsi_debug_sector_size >> 8) & 0xff;
956 arr[11] = scsi_debug_sector_size & 0xff;
Martin K. Petersenea61fca2009-05-15 00:40:33 -0400957 arr[13] = scsi_debug_physblk_exp & 0xf;
958 arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f;
959 arr[15] = scsi_debug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500960
961 if (scsi_debug_dif) {
962 arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */
963 arr[12] |= 1; /* PROT_EN */
964 }
965
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400966 return fill_from_dev_buffer(scp, arr,
967 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
968}
969
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200970#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
971
972static int resp_report_tgtpgs(struct scsi_cmnd * scp,
973 struct sdebug_dev_info * devip)
974{
975 unsigned char *cmd = (unsigned char *)scp->cmnd;
976 unsigned char * arr;
977 int host_no = devip->sdbg_host->shost->host_no;
978 int n, ret, alen, rlen;
979 int port_group_a, port_group_b, port_a, port_b;
980
981 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
982 + cmd[9]);
983
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500984 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
985 if (! arr)
986 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200987 /*
988 * EVPD page 0x88 states we have two ports, one
989 * real and a fake port with no device connected.
990 * So we create two port groups with one port each
991 * and set the group with port B to unavailable.
992 */
993 port_a = 0x1; /* relative port A */
994 port_b = 0x2; /* relative port B */
995 port_group_a = (((host_no + 1) & 0x7f) << 8) +
996 (devip->channel & 0x7f);
997 port_group_b = (((host_no + 1) & 0x7f) << 8) +
998 (devip->channel & 0x7f) + 0x80;
999
1000 /*
1001 * The asymmetric access state is cycled according to the host_id.
1002 */
1003 n = 4;
1004 if (0 == scsi_debug_vpd_use_hostno) {
1005 arr[n++] = host_no % 3; /* Asymm access state */
1006 arr[n++] = 0x0F; /* claim: all states are supported */
1007 } else {
1008 arr[n++] = 0x0; /* Active/Optimized path */
1009 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1010 }
1011 arr[n++] = (port_group_a >> 8) & 0xff;
1012 arr[n++] = port_group_a & 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_a >> 8) & 0xff;
1020 arr[n++] = port_a & 0xff;
1021 arr[n++] = 3; /* Port unavailable */
1022 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1023 arr[n++] = (port_group_b >> 8) & 0xff;
1024 arr[n++] = port_group_b & 0xff;
1025 arr[n++] = 0; /* Reserved */
1026 arr[n++] = 0; /* Status code */
1027 arr[n++] = 0; /* Vendor unique */
1028 arr[n++] = 0x1; /* One port per group */
1029 arr[n++] = 0; /* Reserved */
1030 arr[n++] = 0; /* Reserved */
1031 arr[n++] = (port_b >> 8) & 0xff;
1032 arr[n++] = port_b & 0xff;
1033
1034 rlen = n - 4;
1035 arr[0] = (rlen >> 24) & 0xff;
1036 arr[1] = (rlen >> 16) & 0xff;
1037 arr[2] = (rlen >> 8) & 0xff;
1038 arr[3] = rlen & 0xff;
1039
1040 /*
1041 * Return the smallest value of either
1042 * - The allocated length
1043 * - The constructed command length
1044 * - The maximum array size
1045 */
1046 rlen = min(alen,n);
1047 ret = fill_from_dev_buffer(scp, arr,
1048 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1049 kfree(arr);
1050 return ret;
1051}
1052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053/* <<Following mode page info copied from ST318451LW>> */
1054
1055static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1056{ /* Read-Write Error Recovery page for mode_sense */
1057 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1058 5, 0, 0xff, 0xff};
1059
1060 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1061 if (1 == pcontrol)
1062 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1063 return sizeof(err_recov_pg);
1064}
1065
1066static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1067{ /* Disconnect-Reconnect page for mode_sense */
1068 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1069 0, 0, 0, 0, 0, 0, 0, 0};
1070
1071 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1072 if (1 == pcontrol)
1073 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1074 return sizeof(disconnect_pg);
1075}
1076
1077static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1078{ /* Format device page for mode_sense */
Martin K. Petersen597136a2008-06-05 00:12:59 -04001079 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1080 0, 0, 0, 0, 0, 0, 0, 0,
1081 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Martin K. Petersen597136a2008-06-05 00:12:59 -04001083 memcpy(p, format_pg, sizeof(format_pg));
1084 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1085 p[11] = sdebug_sectors_per & 0xff;
1086 p[12] = (scsi_debug_sector_size >> 8) & 0xff;
1087 p[13] = scsi_debug_sector_size & 0xff;
1088 if (DEV_REMOVEABLE(target))
1089 p[20] |= 0x20; /* should agree with INQUIRY */
1090 if (1 == pcontrol)
1091 memset(p + 2, 0, sizeof(format_pg) - 2);
1092 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093}
1094
1095static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1096{ /* Caching page for mode_sense */
1097 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1098 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1099
1100 memcpy(p, caching_pg, sizeof(caching_pg));
1101 if (1 == pcontrol)
1102 memset(p + 2, 0, sizeof(caching_pg) - 2);
1103 return sizeof(caching_pg);
1104}
1105
1106static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1107{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001108 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1109 0, 0, 0, 0};
1110 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 0, 0, 0x2, 0x4b};
1112
1113 if (scsi_debug_dsense)
1114 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001115 else
1116 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001117
1118 if (scsi_debug_ato)
1119 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1122 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001123 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1124 else if (2 == pcontrol)
1125 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 return sizeof(ctrl_m_pg);
1127}
1128
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001129
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1131{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001132 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1133 0, 0, 0x0, 0x0};
1134 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1135 0, 0, 0x0, 0x0};
1136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1138 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001139 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1140 else if (2 == pcontrol)
1141 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 return sizeof(iec_m_pg);
1143}
1144
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001145static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1146{ /* SAS SSP mode page - short format for mode_sense */
1147 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1148 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1149
1150 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1151 if (1 == pcontrol)
1152 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1153 return sizeof(sas_sf_m_pg);
1154}
1155
1156
1157static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1158 int target_dev_id)
1159{ /* SAS phy control and discover mode page for mode_sense */
1160 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1161 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1162 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1163 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1164 0x2, 0, 0, 0, 0, 0, 0, 0,
1165 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1166 0, 0, 0, 0, 0, 0, 0, 0,
1167 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1168 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1169 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1170 0x3, 0, 0, 0, 0, 0, 0, 0,
1171 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1172 0, 0, 0, 0, 0, 0, 0, 0,
1173 };
1174 int port_a, port_b;
1175
1176 port_a = target_dev_id + 1;
1177 port_b = port_a + 1;
1178 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1179 p[20] = (port_a >> 24);
1180 p[21] = (port_a >> 16) & 0xff;
1181 p[22] = (port_a >> 8) & 0xff;
1182 p[23] = port_a & 0xff;
1183 p[48 + 20] = (port_b >> 24);
1184 p[48 + 21] = (port_b >> 16) & 0xff;
1185 p[48 + 22] = (port_b >> 8) & 0xff;
1186 p[48 + 23] = port_b & 0xff;
1187 if (1 == pcontrol)
1188 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1189 return sizeof(sas_pcd_m_pg);
1190}
1191
1192static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1193{ /* SAS SSP shared protocol specific port mode subpage */
1194 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1195 0, 0, 0, 0, 0, 0, 0, 0,
1196 };
1197
1198 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1199 if (1 == pcontrol)
1200 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1201 return sizeof(sas_sha_m_pg);
1202}
1203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204#define SDEBUG_MAX_MSENSE_SZ 256
1205
1206static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1207 struct sdebug_dev_info * devip)
1208{
Douglas Gilbert23183912006-09-16 20:30:47 -04001209 unsigned char dbd, llbaa;
1210 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001212 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 unsigned char * ap;
1214 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1215 unsigned char *cmd = (unsigned char *)scp->cmnd;
1216
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001217 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001219 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 pcontrol = (cmd[2] & 0xc0) >> 6;
1221 pcode = cmd[2] & 0x3f;
1222 subpcode = cmd[3];
1223 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001224 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1225 if ((0 == scsi_debug_ptype) && (0 == dbd))
1226 bd_len = llbaa ? 16 : 8;
1227 else
1228 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1230 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1231 if (0x3 == pcontrol) { /* Saving values not supported */
1232 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1233 0);
1234 return check_condition_result;
1235 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001236 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1237 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001238 /* set DPOFUA bit for disks */
1239 if (0 == scsi_debug_ptype)
1240 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1241 else
1242 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (msense_6) {
1244 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001245 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 offset = 4;
1247 } else {
1248 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001249 if (16 == bd_len)
1250 arr[4] = 0x1; /* set LONGLBA bit */
1251 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 offset = 8;
1253 }
1254 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001255 if ((bd_len > 0) && (!sdebug_capacity))
1256 sdebug_capacity = get_sdebug_capacity();
1257
Douglas Gilbert23183912006-09-16 20:30:47 -04001258 if (8 == bd_len) {
1259 if (sdebug_capacity > 0xfffffffe) {
1260 ap[0] = 0xff;
1261 ap[1] = 0xff;
1262 ap[2] = 0xff;
1263 ap[3] = 0xff;
1264 } else {
1265 ap[0] = (sdebug_capacity >> 24) & 0xff;
1266 ap[1] = (sdebug_capacity >> 16) & 0xff;
1267 ap[2] = (sdebug_capacity >> 8) & 0xff;
1268 ap[3] = sdebug_capacity & 0xff;
1269 }
Martin K. Petersen597136a2008-06-05 00:12:59 -04001270 ap[6] = (scsi_debug_sector_size >> 8) & 0xff;
1271 ap[7] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001272 offset += bd_len;
1273 ap = arr + offset;
1274 } else if (16 == bd_len) {
1275 unsigned long long capac = sdebug_capacity;
1276
1277 for (k = 0; k < 8; ++k, capac >>= 8)
1278 ap[7 - k] = capac & 0xff;
Martin K. Petersen597136a2008-06-05 00:12:59 -04001279 ap[12] = (scsi_debug_sector_size >> 24) & 0xff;
1280 ap[13] = (scsi_debug_sector_size >> 16) & 0xff;
1281 ap[14] = (scsi_debug_sector_size >> 8) & 0xff;
1282 ap[15] = scsi_debug_sector_size & 0xff;
Douglas Gilbert23183912006-09-16 20:30:47 -04001283 offset += bd_len;
1284 ap = arr + offset;
1285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001287 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1288 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1290 0);
1291 return check_condition_result;
1292 }
1293 switch (pcode) {
1294 case 0x1: /* Read-Write error recovery page, direct access */
1295 len = resp_err_recov_pg(ap, pcontrol, target);
1296 offset += len;
1297 break;
1298 case 0x2: /* Disconnect-Reconnect page, all devices */
1299 len = resp_disconnect_pg(ap, pcontrol, target);
1300 offset += len;
1301 break;
1302 case 0x3: /* Format device page, direct access */
1303 len = resp_format_pg(ap, pcontrol, target);
1304 offset += len;
1305 break;
1306 case 0x8: /* Caching page, direct access */
1307 len = resp_caching_pg(ap, pcontrol, target);
1308 offset += len;
1309 break;
1310 case 0xa: /* Control Mode page, all devices */
1311 len = resp_ctrl_m_pg(ap, pcontrol, target);
1312 offset += len;
1313 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001314 case 0x19: /* if spc==1 then sas phy, control+discover */
1315 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1316 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1317 INVALID_FIELD_IN_CDB, 0);
1318 return check_condition_result;
1319 }
1320 len = 0;
1321 if ((0x0 == subpcode) || (0xff == subpcode))
1322 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1323 if ((0x1 == subpcode) || (0xff == subpcode))
1324 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1325 target_dev_id);
1326 if ((0x2 == subpcode) || (0xff == subpcode))
1327 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1328 offset += len;
1329 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 case 0x1c: /* Informational Exceptions Mode page, all devices */
1331 len = resp_iec_m_pg(ap, pcontrol, target);
1332 offset += len;
1333 break;
1334 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001335 if ((0 == subpcode) || (0xff == subpcode)) {
1336 len = resp_err_recov_pg(ap, pcontrol, target);
1337 len += resp_disconnect_pg(ap + len, pcontrol, target);
1338 len += resp_format_pg(ap + len, pcontrol, target);
1339 len += resp_caching_pg(ap + len, pcontrol, target);
1340 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1341 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1342 if (0xff == subpcode) {
1343 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1344 target, target_dev_id);
1345 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1346 }
1347 len += resp_iec_m_pg(ap + len, pcontrol, target);
1348 } else {
1349 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1350 INVALID_FIELD_IN_CDB, 0);
1351 return check_condition_result;
1352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 offset += len;
1354 break;
1355 default:
1356 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1357 0);
1358 return check_condition_result;
1359 }
1360 if (msense_6)
1361 arr[0] = offset - 1;
1362 else {
1363 arr[0] = ((offset - 2) >> 8) & 0xff;
1364 arr[1] = (offset - 2) & 0xff;
1365 }
1366 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1367}
1368
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001369#define SDEBUG_MAX_MSELECT_SZ 512
1370
1371static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1372 struct sdebug_dev_info * devip)
1373{
1374 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1375 int param_len, res, errsts, mpage;
1376 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1377 unsigned char *cmd = (unsigned char *)scp->cmnd;
1378
1379 if ((errsts = check_readiness(scp, 1, devip)))
1380 return errsts;
1381 memset(arr, 0, sizeof(arr));
1382 pf = cmd[1] & 0x10;
1383 sp = cmd[1] & 0x1;
1384 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1385 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1386 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1387 INVALID_FIELD_IN_CDB, 0);
1388 return check_condition_result;
1389 }
1390 res = fetch_to_dev_buffer(scp, arr, param_len);
1391 if (-1 == res)
1392 return (DID_ERROR << 16);
1393 else if ((res < param_len) &&
1394 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1395 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1396 " IO sent=%d bytes\n", param_len, res);
1397 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1398 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001399 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001400 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1401 INVALID_FIELD_IN_PARAM_LIST, 0);
1402 return check_condition_result;
1403 }
1404 off = bd_len + (mselect6 ? 4 : 8);
1405 mpage = arr[off] & 0x3f;
1406 ps = !!(arr[off] & 0x80);
1407 if (ps) {
1408 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1409 INVALID_FIELD_IN_PARAM_LIST, 0);
1410 return check_condition_result;
1411 }
1412 spf = !!(arr[off] & 0x40);
1413 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1414 (arr[off + 1] + 2);
1415 if ((pg_len + off) > param_len) {
1416 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1417 PARAMETER_LIST_LENGTH_ERR, 0);
1418 return check_condition_result;
1419 }
1420 switch (mpage) {
1421 case 0xa: /* Control Mode page */
1422 if (ctrl_m_pg[1] == arr[off + 1]) {
1423 memcpy(ctrl_m_pg + 2, arr + off + 2,
1424 sizeof(ctrl_m_pg) - 2);
1425 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1426 return 0;
1427 }
1428 break;
1429 case 0x1c: /* Informational Exceptions Mode page */
1430 if (iec_m_pg[1] == arr[off + 1]) {
1431 memcpy(iec_m_pg + 2, arr + off + 2,
1432 sizeof(iec_m_pg) - 2);
1433 return 0;
1434 }
1435 break;
1436 default:
1437 break;
1438 }
1439 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1440 INVALID_FIELD_IN_PARAM_LIST, 0);
1441 return check_condition_result;
1442}
1443
1444static int resp_temp_l_pg(unsigned char * arr)
1445{
1446 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1447 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1448 };
1449
1450 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1451 return sizeof(temp_l_pg);
1452}
1453
1454static int resp_ie_l_pg(unsigned char * arr)
1455{
1456 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1457 };
1458
1459 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1460 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1461 arr[4] = THRESHOLD_EXCEEDED;
1462 arr[5] = 0xff;
1463 }
1464 return sizeof(ie_l_pg);
1465}
1466
1467#define SDEBUG_MAX_LSENSE_SZ 512
1468
1469static int resp_log_sense(struct scsi_cmnd * scp,
1470 struct sdebug_dev_info * devip)
1471{
Douglas Gilbert23183912006-09-16 20:30:47 -04001472 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001473 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1474 unsigned char *cmd = (unsigned char *)scp->cmnd;
1475
1476 if ((errsts = check_readiness(scp, 1, devip)))
1477 return errsts;
1478 memset(arr, 0, sizeof(arr));
1479 ppc = cmd[1] & 0x2;
1480 sp = cmd[1] & 0x1;
1481 if (ppc || sp) {
1482 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1483 INVALID_FIELD_IN_CDB, 0);
1484 return check_condition_result;
1485 }
1486 pcontrol = (cmd[2] & 0xc0) >> 6;
1487 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001488 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001489 alloc_len = (cmd[7] << 8) + cmd[8];
1490 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001491 if (0 == subpcode) {
1492 switch (pcode) {
1493 case 0x0: /* Supported log pages log page */
1494 n = 4;
1495 arr[n++] = 0x0; /* this page */
1496 arr[n++] = 0xd; /* Temperature */
1497 arr[n++] = 0x2f; /* Informational exceptions */
1498 arr[3] = n - 4;
1499 break;
1500 case 0xd: /* Temperature log page */
1501 arr[3] = resp_temp_l_pg(arr + 4);
1502 break;
1503 case 0x2f: /* Informational exceptions log page */
1504 arr[3] = resp_ie_l_pg(arr + 4);
1505 break;
1506 default:
1507 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1508 INVALID_FIELD_IN_CDB, 0);
1509 return check_condition_result;
1510 }
1511 } else if (0xff == subpcode) {
1512 arr[0] |= 0x40;
1513 arr[1] = subpcode;
1514 switch (pcode) {
1515 case 0x0: /* Supported log pages and subpages log page */
1516 n = 4;
1517 arr[n++] = 0x0;
1518 arr[n++] = 0x0; /* 0,0 page */
1519 arr[n++] = 0x0;
1520 arr[n++] = 0xff; /* this page */
1521 arr[n++] = 0xd;
1522 arr[n++] = 0x0; /* Temperature */
1523 arr[n++] = 0x2f;
1524 arr[n++] = 0x0; /* Informational exceptions */
1525 arr[3] = n - 4;
1526 break;
1527 case 0xd: /* Temperature subpages */
1528 n = 4;
1529 arr[n++] = 0xd;
1530 arr[n++] = 0x0; /* Temperature */
1531 arr[3] = n - 4;
1532 break;
1533 case 0x2f: /* Informational exceptions subpages */
1534 n = 4;
1535 arr[n++] = 0x2f;
1536 arr[n++] = 0x0; /* Informational exceptions */
1537 arr[3] = n - 4;
1538 break;
1539 default:
1540 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1541 INVALID_FIELD_IN_CDB, 0);
1542 return check_condition_result;
1543 }
1544 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001545 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1546 INVALID_FIELD_IN_CDB, 0);
1547 return check_condition_result;
1548 }
1549 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1550 return fill_from_dev_buffer(scp, arr,
1551 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1552}
1553
FUJITA Tomonori19789102008-03-30 00:59:56 +09001554static int check_device_access_params(struct sdebug_dev_info *devi,
1555 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001557 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001558 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 return check_condition_result;
1560 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001561 /* transfer length excessive (tie in to block limits VPD page) */
1562 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001563 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001564 return check_condition_result;
1565 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001566 return 0;
1567}
1568
1569static int do_device_access(struct scsi_cmnd *scmd,
1570 struct sdebug_dev_info *devi,
1571 unsigned long long lba, unsigned int num, int write)
1572{
1573 int ret;
1574 unsigned int block, rest = 0;
1575 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1576
1577 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1578
1579 block = do_div(lba, sdebug_store_sectors);
1580 if (block + num > sdebug_store_sectors)
1581 rest = block + num - sdebug_store_sectors;
1582
Martin K. Petersen597136a2008-06-05 00:12:59 -04001583 ret = func(scmd, fake_storep + (block * scsi_debug_sector_size),
1584 (num - rest) * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001585 if (!ret && rest)
Martin K. Petersen597136a2008-06-05 00:12:59 -04001586 ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001587
1588 return ret;
1589}
1590
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001591static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
1592 unsigned int sectors)
1593{
1594 unsigned int i, resid;
1595 struct scatterlist *psgl;
1596 struct sd_dif_tuple *sdt;
1597 sector_t sector;
1598 sector_t tmp_sec = start_sec;
1599 void *paddr;
1600
1601 start_sec = do_div(tmp_sec, sdebug_store_sectors);
1602
1603 sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
1604
1605 for (i = 0 ; i < sectors ; i++) {
1606 u16 csum;
1607
1608 if (sdt[i].app_tag == 0xffff)
1609 continue;
1610
1611 sector = start_sec + i;
1612
1613 switch (scsi_debug_guard) {
1614 case 1:
1615 csum = ip_compute_csum(fake_storep +
1616 sector * scsi_debug_sector_size,
1617 scsi_debug_sector_size);
1618 break;
1619 case 0:
1620 csum = crc_t10dif(fake_storep +
1621 sector * scsi_debug_sector_size,
1622 scsi_debug_sector_size);
1623 csum = cpu_to_be16(csum);
1624 break;
1625 default:
1626 BUG();
1627 }
1628
1629 if (sdt[i].guard_tag != csum) {
1630 printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
1631 " rcvd 0x%04x, data 0x%04x\n", __func__,
1632 (unsigned long)sector,
1633 be16_to_cpu(sdt[i].guard_tag),
1634 be16_to_cpu(csum));
1635 dif_errors++;
1636 return 0x01;
1637 }
1638
1639 if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
1640 be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
1641 printk(KERN_ERR "%s: REF check failed on sector %lu\n",
1642 __func__, (unsigned long)sector);
1643 dif_errors++;
1644 return 0x03;
1645 }
1646 }
1647
1648 resid = sectors * 8; /* Bytes of protection data to copy into sgl */
1649 sector = start_sec;
1650
1651 scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
1652 int len = min(psgl->length, resid);
1653
1654 paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset;
1655 memcpy(paddr, dif_storep + dif_offset(sector), len);
1656
1657 sector += len >> 3;
1658 if (sector >= sdebug_store_sectors) {
1659 /* Force wrap */
1660 tmp_sec = sector;
1661 sector = do_div(tmp_sec, sdebug_store_sectors);
1662 }
1663 resid -= len;
1664 kunmap_atomic(paddr, KM_IRQ0);
1665 }
1666
1667 dix_reads++;
1668
1669 return 0;
1670}
1671
FUJITA Tomonori19789102008-03-30 00:59:56 +09001672static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1673 unsigned int num, struct sdebug_dev_info *devip)
1674{
1675 unsigned long iflags;
1676 int ret;
1677
1678 ret = check_device_access_params(devip, lba, num);
1679 if (ret)
1680 return ret;
1681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001683 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1684 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1685 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1687 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001688 /* set info field and valid bit for fixed descriptor */
1689 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1690 devip->sense_buff[0] |= 0x80; /* Valid bit */
1691 ret = OPT_MEDIUM_ERR_ADDR;
1692 devip->sense_buff[3] = (ret >> 24) & 0xff;
1693 devip->sense_buff[4] = (ret >> 16) & 0xff;
1694 devip->sense_buff[5] = (ret >> 8) & 0xff;
1695 devip->sense_buff[6] = ret & 0xff;
1696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 return check_condition_result;
1698 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001699
1700 /* DIX + T10 DIF */
1701 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1702 int prot_ret = prot_verify_read(SCpnt, lba, num);
1703
1704 if (prot_ret) {
1705 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
1706 return illegal_condition_result;
1707 }
1708 }
1709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001711 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 read_unlock_irqrestore(&atomic_rw, iflags);
1713 return ret;
1714}
1715
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001716void dump_sector(unsigned char *buf, int len)
1717{
1718 int i, j;
1719
1720 printk(KERN_ERR ">>> Sector Dump <<<\n");
1721
1722 for (i = 0 ; i < len ; i += 16) {
1723 printk(KERN_ERR "%04d: ", i);
1724
1725 for (j = 0 ; j < 16 ; j++) {
1726 unsigned char c = buf[i+j];
1727 if (c >= 0x20 && c < 0x7e)
1728 printk(" %c ", buf[i+j]);
1729 else
1730 printk("%02x ", buf[i+j]);
1731 }
1732
1733 printk("\n");
1734 }
1735}
1736
1737static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
1738 unsigned int sectors)
1739{
1740 int i, j, ret;
1741 struct sd_dif_tuple *sdt;
1742 struct scatterlist *dsgl = scsi_sglist(SCpnt);
1743 struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
1744 void *daddr, *paddr;
1745 sector_t tmp_sec = start_sec;
1746 sector_t sector;
1747 int ppage_offset;
1748 unsigned short csum;
1749
1750 sector = do_div(tmp_sec, sdebug_store_sectors);
1751
1752 if (((SCpnt->cmnd[1] >> 5) & 7) != 1) {
1753 printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n");
1754 return 0;
1755 }
1756
1757 BUG_ON(scsi_sg_count(SCpnt) == 0);
1758 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
1759
1760 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset;
1761 ppage_offset = 0;
1762
1763 /* For each data page */
1764 scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
1765 daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset;
1766
1767 /* For each sector-sized chunk in data page */
1768 for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
1769
1770 /* If we're at the end of the current
1771 * protection page advance to the next one
1772 */
1773 if (ppage_offset >= psgl->length) {
1774 kunmap_atomic(paddr, KM_IRQ1);
1775 psgl = sg_next(psgl);
1776 BUG_ON(psgl == NULL);
1777 paddr = kmap_atomic(sg_page(psgl), KM_IRQ1)
1778 + psgl->offset;
1779 ppage_offset = 0;
1780 }
1781
1782 sdt = paddr + ppage_offset;
1783
1784 switch (scsi_debug_guard) {
1785 case 1:
1786 csum = ip_compute_csum(daddr,
1787 scsi_debug_sector_size);
1788 break;
1789 case 0:
1790 csum = cpu_to_be16(crc_t10dif(daddr,
1791 scsi_debug_sector_size));
1792 break;
1793 default:
1794 BUG();
1795 ret = 0;
1796 goto out;
1797 }
1798
1799 if (sdt->guard_tag != csum) {
1800 printk(KERN_ERR
1801 "%s: GUARD check failed on sector %lu " \
1802 "rcvd 0x%04x, calculated 0x%04x\n",
1803 __func__, (unsigned long)sector,
1804 be16_to_cpu(sdt->guard_tag),
1805 be16_to_cpu(csum));
1806 ret = 0x01;
1807 dump_sector(daddr, scsi_debug_sector_size);
1808 goto out;
1809 }
1810
1811 if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
1812 be32_to_cpu(sdt->ref_tag)
1813 != (start_sec & 0xffffffff)) {
1814 printk(KERN_ERR
1815 "%s: REF check failed on sector %lu\n",
1816 __func__, (unsigned long)sector);
1817 ret = 0x03;
1818 dump_sector(daddr, scsi_debug_sector_size);
1819 goto out;
1820 }
1821
1822 /* Would be great to copy this in bigger
1823 * chunks. However, for the sake of
1824 * correctness we need to verify each sector
1825 * before writing it to "stable" storage
1826 */
1827 memcpy(dif_storep + dif_offset(sector), sdt, 8);
1828
1829 sector++;
1830
1831 if (sector == sdebug_store_sectors)
1832 sector = 0; /* Force wrap */
1833
1834 start_sec++;
1835 daddr += scsi_debug_sector_size;
1836 ppage_offset += sizeof(struct sd_dif_tuple);
1837 }
1838
1839 kunmap_atomic(daddr, KM_IRQ0);
1840 }
1841
1842 kunmap_atomic(paddr, KM_IRQ1);
1843
1844 dix_writes++;
1845
1846 return 0;
1847
1848out:
1849 dif_errors++;
1850 kunmap_atomic(daddr, KM_IRQ0);
1851 kunmap_atomic(paddr, KM_IRQ1);
1852 return ret;
1853}
1854
FUJITA Tomonori19789102008-03-30 00:59:56 +09001855static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
1856 unsigned int num, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857{
1858 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001859 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
FUJITA Tomonori19789102008-03-30 00:59:56 +09001861 ret = check_device_access_params(devip, lba, num);
1862 if (ret)
1863 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001865 /* DIX + T10 DIF */
1866 if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
1867 int prot_ret = prot_verify_write(SCpnt, lba, num);
1868
1869 if (prot_ret) {
1870 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
1871 return illegal_condition_result;
1872 }
1873 }
1874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001876 ret = do_device_access(SCpnt, devip, lba, num, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001878 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 return (DID_ERROR << 16);
Martin K. Petersen597136a2008-06-05 00:12:59 -04001880 else if ((ret < (num * scsi_debug_sector_size)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001882 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Martin K. Petersen597136a2008-06-05 00:12:59 -04001883 " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 return 0;
1885}
1886
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001887#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888
1889static int resp_report_luns(struct scsi_cmnd * scp,
1890 struct sdebug_dev_info * devip)
1891{
1892 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001893 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 unsigned char *cmd = (unsigned char *)scp->cmnd;
1895 int select_report = (int)cmd[2];
1896 struct scsi_lun *one_lun;
1897 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001898 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001901 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1903 0);
1904 return check_condition_result;
1905 }
1906 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1907 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1908 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001909 if (1 == select_report)
1910 lun_cnt = 0;
1911 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1912 --lun_cnt;
1913 wlun = (select_report > 0) ? 1 : 0;
1914 num = lun_cnt + wlun;
1915 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1916 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1917 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1918 sizeof(struct scsi_lun)), num);
1919 if (n < num) {
1920 wlun = 0;
1921 lun_cnt = n;
1922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001924 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1925 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1926 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1927 i++, lun++) {
1928 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 if (upper)
1930 one_lun[i].scsi_lun[0] =
1931 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001932 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001934 if (wlun) {
1935 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1936 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1937 i++;
1938 }
1939 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 return fill_from_dev_buffer(scp, arr,
1941 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1942}
1943
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001944static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1945 unsigned int num, struct sdebug_dev_info *devip)
1946{
1947 int i, j, ret = -1;
1948 unsigned char *kaddr, *buf;
1949 unsigned int offset;
1950 struct scatterlist *sg;
1951 struct scsi_data_buffer *sdb = scsi_in(scp);
1952
1953 /* better not to use temporary buffer. */
1954 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1955 if (!buf)
1956 return ret;
1957
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001958 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001959
1960 offset = 0;
1961 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1962 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1963 if (!kaddr)
1964 goto out;
1965
1966 for (j = 0; j < sg->length; j++)
1967 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1968
1969 offset += sg->length;
1970 kunmap_atomic(kaddr, KM_USER0);
1971 }
1972 ret = 0;
1973out:
1974 kfree(buf);
1975
1976 return ret;
1977}
1978
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979/* When timer goes off this function is called. */
1980static void timer_intr_handler(unsigned long indx)
1981{
1982 struct sdebug_queued_cmd * sqcp;
1983 unsigned long iflags;
1984
1985 if (indx >= SCSI_DEBUG_CANQUEUE) {
1986 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1987 "large\n");
1988 return;
1989 }
1990 spin_lock_irqsave(&queued_arr_lock, iflags);
1991 sqcp = &queued_arr[(int)indx];
1992 if (! sqcp->in_use) {
1993 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1994 "interrupt\n");
1995 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1996 return;
1997 }
1998 sqcp->in_use = 0;
1999 if (sqcp->done_funct) {
2000 sqcp->a_cmnd->result = sqcp->scsi_result;
2001 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
2002 }
2003 sqcp->done_funct = NULL;
2004 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2005}
2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002008static struct sdebug_dev_info *
2009sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002010{
2011 struct sdebug_dev_info *devip;
2012
2013 devip = kzalloc(sizeof(*devip), flags);
2014 if (devip) {
2015 devip->sdbg_host = sdbg_host;
2016 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
2017 }
2018 return devip;
2019}
2020
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2022{
2023 struct sdebug_host_info * sdbg_host;
2024 struct sdebug_dev_info * open_devip = NULL;
2025 struct sdebug_dev_info * devip =
2026 (struct sdebug_dev_info *)sdev->hostdata;
2027
2028 if (devip)
2029 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002030 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
2031 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 printk(KERN_ERR "Host info NULL\n");
2033 return NULL;
2034 }
2035 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2036 if ((devip->used) && (devip->channel == sdev->channel) &&
2037 (devip->target == sdev->id) &&
2038 (devip->lun == sdev->lun))
2039 return devip;
2040 else {
2041 if ((!devip->used) && (!open_devip))
2042 open_devip = devip;
2043 }
2044 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002045 if (!open_devip) { /* try and make a new one */
2046 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
2047 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002049 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 return NULL;
2051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09002053
2054 open_devip->channel = sdev->channel;
2055 open_devip->target = sdev->id;
2056 open_devip->lun = sdev->lun;
2057 open_devip->sdbg_host = sdbg_host;
2058 open_devip->reset = 1;
2059 open_devip->used = 1;
2060 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2061 if (scsi_debug_dsense)
2062 open_devip->sense_buff[0] = 0x72;
2063 else {
2064 open_devip->sense_buff[0] = 0x70;
2065 open_devip->sense_buff[7] = 0xa;
2066 }
2067 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2068 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
2069
2070 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071}
2072
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002073static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002075 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2076 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
2077 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Nick Piggin75ad23b2008-04-29 14:48:33 +02002078 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002079 return 0;
2080}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002082static int scsi_debug_slave_configure(struct scsi_device *sdp)
2083{
2084 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09002085
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002087 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2088 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2089 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2090 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2091 devip = devInfoReg(sdp);
2092 if (NULL == devip)
2093 return 1; /* no resources, will be marked offline */
2094 sdp->hostdata = devip;
2095 if (sdp->host->cmd_per_lun)
2096 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2097 sdp->host->cmd_per_lun);
2098 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
2099 return 0;
2100}
2101
2102static void scsi_debug_slave_destroy(struct scsi_device *sdp)
2103{
2104 struct sdebug_dev_info *devip =
2105 (struct sdebug_dev_info *)sdp->hostdata;
2106
2107 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2108 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2109 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
2110 if (devip) {
2111 /* make this slot avaliable for re-use */
2112 devip->used = 0;
2113 sdp->hostdata = NULL;
2114 }
2115}
2116
2117/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2118static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
2119{
2120 unsigned long iflags;
2121 int k;
2122 struct sdebug_queued_cmd *sqcp;
2123
2124 spin_lock_irqsave(&queued_arr_lock, iflags);
2125 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2126 sqcp = &queued_arr[k];
2127 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2128 del_timer_sync(&sqcp->cmnd_timer);
2129 sqcp->in_use = 0;
2130 sqcp->a_cmnd = NULL;
2131 break;
2132 }
2133 }
2134 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2135 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2136}
2137
2138/* Deletes (stops) timers of all queued commands */
2139static void stop_all_queued(void)
2140{
2141 unsigned long iflags;
2142 int k;
2143 struct sdebug_queued_cmd *sqcp;
2144
2145 spin_lock_irqsave(&queued_arr_lock, iflags);
2146 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2147 sqcp = &queued_arr[k];
2148 if (sqcp->in_use && sqcp->a_cmnd) {
2149 del_timer_sync(&sqcp->cmnd_timer);
2150 sqcp->in_use = 0;
2151 sqcp->a_cmnd = NULL;
2152 }
2153 }
2154 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155}
2156
2157static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2158{
2159 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2160 printk(KERN_INFO "scsi_debug: abort\n");
2161 ++num_aborts;
2162 stop_queued_cmnd(SCpnt);
2163 return SUCCESS;
2164}
2165
2166static int scsi_debug_biosparam(struct scsi_device *sdev,
2167 struct block_device * bdev, sector_t capacity, int *info)
2168{
2169 int res;
2170 unsigned char *buf;
2171
2172 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2173 printk(KERN_INFO "scsi_debug: biosparam\n");
2174 buf = scsi_bios_ptable(bdev);
2175 if (buf) {
2176 res = scsi_partsize(buf, capacity,
2177 &info[2], &info[0], &info[1]);
2178 kfree(buf);
2179 if (! res)
2180 return res;
2181 }
2182 info[0] = sdebug_heads;
2183 info[1] = sdebug_sectors_per;
2184 info[2] = sdebug_cylinders_per;
2185 return 0;
2186}
2187
2188static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2189{
2190 struct sdebug_dev_info * devip;
2191
2192 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2193 printk(KERN_INFO "scsi_debug: device_reset\n");
2194 ++num_dev_resets;
2195 if (SCpnt) {
2196 devip = devInfoReg(SCpnt->device);
2197 if (devip)
2198 devip->reset = 1;
2199 }
2200 return SUCCESS;
2201}
2202
2203static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2204{
2205 struct sdebug_host_info *sdbg_host;
2206 struct sdebug_dev_info * dev_info;
2207 struct scsi_device * sdp;
2208 struct Scsi_Host * hp;
2209
2210 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2211 printk(KERN_INFO "scsi_debug: bus_reset\n");
2212 ++num_bus_resets;
2213 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09002214 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 if (sdbg_host) {
2216 list_for_each_entry(dev_info,
2217 &sdbg_host->dev_info_list,
2218 dev_list)
2219 dev_info->reset = 1;
2220 }
2221 }
2222 return SUCCESS;
2223}
2224
2225static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2226{
2227 struct sdebug_host_info * sdbg_host;
2228 struct sdebug_dev_info * dev_info;
2229
2230 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2231 printk(KERN_INFO "scsi_debug: host_reset\n");
2232 ++num_host_resets;
2233 spin_lock(&sdebug_host_list_lock);
2234 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2235 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2236 dev_list)
2237 dev_info->reset = 1;
2238 }
2239 spin_unlock(&sdebug_host_list_lock);
2240 stop_all_queued();
2241 return SUCCESS;
2242}
2243
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244/* Initializes timers in queued array */
2245static void __init init_all_queued(void)
2246{
2247 unsigned long iflags;
2248 int k;
2249 struct sdebug_queued_cmd * sqcp;
2250
2251 spin_lock_irqsave(&queued_arr_lock, iflags);
2252 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2253 sqcp = &queued_arr[k];
2254 init_timer(&sqcp->cmnd_timer);
2255 sqcp->in_use = 0;
2256 sqcp->a_cmnd = NULL;
2257 }
2258 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2259}
2260
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002261static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002262 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263{
2264 struct partition * pp;
2265 int starts[SDEBUG_MAX_PARTS + 2];
2266 int sectors_per_part, num_sectors, k;
2267 int heads_by_sects, start_sec, end_sec;
2268
2269 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002270 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 return;
2272 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2273 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2274 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2275 "partitions to %d\n", SDEBUG_MAX_PARTS);
2276 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002277 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 sectors_per_part = (num_sectors - sdebug_sectors_per)
2279 / scsi_debug_num_parts;
2280 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2281 starts[0] = sdebug_sectors_per;
2282 for (k = 1; k < scsi_debug_num_parts; ++k)
2283 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2284 * heads_by_sects;
2285 starts[scsi_debug_num_parts] = num_sectors;
2286 starts[scsi_debug_num_parts + 1] = 0;
2287
2288 ramp[510] = 0x55; /* magic partition markings */
2289 ramp[511] = 0xAA;
2290 pp = (struct partition *)(ramp + 0x1be);
2291 for (k = 0; starts[k + 1]; ++k, ++pp) {
2292 start_sec = starts[k];
2293 end_sec = starts[k + 1] - 1;
2294 pp->boot_ind = 0;
2295
2296 pp->cyl = start_sec / heads_by_sects;
2297 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2298 / sdebug_sectors_per;
2299 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2300
2301 pp->end_cyl = end_sec / heads_by_sects;
2302 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2303 / sdebug_sectors_per;
2304 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2305
2306 pp->start_sect = start_sec;
2307 pp->nr_sects = end_sec - start_sec + 1;
2308 pp->sys_ind = 0x83; /* plain Linux partition */
2309 }
2310}
2311
2312static int schedule_resp(struct scsi_cmnd * cmnd,
2313 struct sdebug_dev_info * devip,
2314 done_funct_t done, int scsi_result, int delta_jiff)
2315{
2316 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2317 if (scsi_result) {
2318 struct scsi_device * sdp = cmnd->device;
2319
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002320 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2321 "non-zero result=0x%x\n", sdp->host->host_no,
2322 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 }
2324 }
2325 if (cmnd && devip) {
2326 /* simulate autosense by this driver */
2327 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2328 memcpy(cmnd->sense_buffer, devip->sense_buff,
2329 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2330 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2331 }
2332 if (delta_jiff <= 0) {
2333 if (cmnd)
2334 cmnd->result = scsi_result;
2335 if (done)
2336 done(cmnd);
2337 return 0;
2338 } else {
2339 unsigned long iflags;
2340 int k;
2341 struct sdebug_queued_cmd * sqcp = NULL;
2342
2343 spin_lock_irqsave(&queued_arr_lock, iflags);
2344 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2345 sqcp = &queued_arr[k];
2346 if (! sqcp->in_use)
2347 break;
2348 }
2349 if (k >= SCSI_DEBUG_CANQUEUE) {
2350 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2351 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2352 return 1; /* report busy to mid level */
2353 }
2354 sqcp->in_use = 1;
2355 sqcp->a_cmnd = cmnd;
2356 sqcp->scsi_result = scsi_result;
2357 sqcp->done_funct = done;
2358 sqcp->cmnd_timer.function = timer_intr_handler;
2359 sqcp->cmnd_timer.data = k;
2360 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2361 add_timer(&sqcp->cmnd_timer);
2362 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2363 if (cmnd)
2364 cmnd->result = 0;
2365 return 0;
2366 }
2367}
Douglas Gilbert23183912006-09-16 20:30:47 -04002368/* Note: The following macros create attribute files in the
2369 /sys/module/scsi_debug/parameters directory. Unfortunately this
2370 driver is unaware of a change and cannot trigger auxiliary actions
2371 as it can when the corresponding attribute in the
2372 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2373 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002374module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2375module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2376module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2377module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2378module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002379module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002380module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2381module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2382module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2383module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2384module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2385module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2386module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2387module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002388module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2389 S_IRUGO | S_IWUSR);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002390module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002391module_param_named(dix, scsi_debug_dix, int, S_IRUGO);
2392module_param_named(dif, scsi_debug_dif, int, S_IRUGO);
2393module_param_named(guard, scsi_debug_guard, int, S_IRUGO);
2394module_param_named(ato, scsi_debug_ato, int, S_IRUGO);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002395module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);
2396module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2399MODULE_DESCRIPTION("SCSI debug adapter driver");
2400MODULE_LICENSE("GPL");
2401MODULE_VERSION(SCSI_DEBUG_VERSION);
2402
2403MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2404MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002405MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2406MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002407MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002408MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002409MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2410MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002412MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002413MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2415MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002416MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002417MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002418MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
2419MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
2420MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002421MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
2422MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
2423MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
2424MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
2426static char sdebug_info[256];
2427
2428static const char * scsi_debug_info(struct Scsi_Host * shp)
2429{
2430 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2431 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2432 scsi_debug_version_date, scsi_debug_dev_size_mb,
2433 scsi_debug_opts);
2434 return sdebug_info;
2435}
2436
2437/* scsi_debug_proc_info
2438 * Used if the driver currently has no own support for /proc/scsi
2439 */
2440static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2441 int length, int inout)
2442{
2443 int len, pos, begin;
2444 int orig_length;
2445
2446 orig_length = length;
2447
2448 if (inout == 1) {
2449 char arr[16];
2450 int minLen = length > 15 ? 15 : length;
2451
2452 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2453 return -EACCES;
2454 memcpy(arr, buffer, minLen);
2455 arr[minLen] = '\0';
2456 if (1 != sscanf(arr, "%d", &pos))
2457 return -EINVAL;
2458 scsi_debug_opts = pos;
2459 if (scsi_debug_every_nth != 0)
2460 scsi_debug_cmnd_count = 0;
2461 return length;
2462 }
2463 begin = 0;
2464 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2465 "%s [%s]\n"
2466 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2467 "every_nth=%d(curr:%d)\n"
2468 "delay=%d, max_luns=%d, scsi_level=%d\n"
2469 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2470 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002471 "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2473 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2474 scsi_debug_cmnd_count, scsi_debug_delay,
2475 scsi_debug_max_luns, scsi_debug_scsi_level,
Martin K. Petersen597136a2008-06-05 00:12:59 -04002476 scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,
2477 sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002478 num_host_resets, dix_reads, dix_writes, dif_errors);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 if (pos < offset) {
2480 len = 0;
2481 begin = pos;
2482 }
2483 *start = buffer + (offset - begin); /* Start of wanted data */
2484 len -= (offset - begin);
2485 if (len > length)
2486 len = length;
2487 return len;
2488}
2489
2490static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2491{
2492 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2493}
2494
2495static ssize_t sdebug_delay_store(struct device_driver * ddp,
2496 const char * buf, size_t count)
2497{
2498 int delay;
2499 char work[20];
2500
2501 if (1 == sscanf(buf, "%10s", work)) {
2502 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2503 scsi_debug_delay = delay;
2504 return count;
2505 }
2506 }
2507 return -EINVAL;
2508}
2509DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2510 sdebug_delay_store);
2511
2512static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2513{
2514 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2515}
2516
2517static ssize_t sdebug_opts_store(struct device_driver * ddp,
2518 const char * buf, size_t count)
2519{
2520 int opts;
2521 char work[20];
2522
2523 if (1 == sscanf(buf, "%10s", work)) {
2524 if (0 == strnicmp(work,"0x", 2)) {
2525 if (1 == sscanf(&work[2], "%x", &opts))
2526 goto opts_done;
2527 } else {
2528 if (1 == sscanf(work, "%d", &opts))
2529 goto opts_done;
2530 }
2531 }
2532 return -EINVAL;
2533opts_done:
2534 scsi_debug_opts = opts;
2535 scsi_debug_cmnd_count = 0;
2536 return count;
2537}
2538DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2539 sdebug_opts_store);
2540
2541static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2542{
2543 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2544}
2545static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2546 const char * buf, size_t count)
2547{
2548 int n;
2549
2550 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2551 scsi_debug_ptype = n;
2552 return count;
2553 }
2554 return -EINVAL;
2555}
2556DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2557
2558static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2559{
2560 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2561}
2562static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2563 const char * buf, size_t count)
2564{
2565 int n;
2566
2567 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2568 scsi_debug_dsense = n;
2569 return count;
2570 }
2571 return -EINVAL;
2572}
2573DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2574 sdebug_dsense_store);
2575
Douglas Gilbert23183912006-09-16 20:30:47 -04002576static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2577{
2578 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2579}
2580static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2581 const char * buf, size_t count)
2582{
2583 int n;
2584
2585 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2586 scsi_debug_fake_rw = n;
2587 return count;
2588 }
2589 return -EINVAL;
2590}
2591DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2592 sdebug_fake_rw_store);
2593
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002594static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2595{
2596 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2597}
2598static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2599 const char * buf, size_t count)
2600{
2601 int n;
2602
2603 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2604 scsi_debug_no_lun_0 = n;
2605 return count;
2606 }
2607 return -EINVAL;
2608}
2609DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2610 sdebug_no_lun_0_store);
2611
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2613{
2614 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2615}
2616static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2617 const char * buf, size_t count)
2618{
2619 int n;
2620
2621 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2622 scsi_debug_num_tgts = n;
2623 sdebug_max_tgts_luns();
2624 return count;
2625 }
2626 return -EINVAL;
2627}
2628DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2629 sdebug_num_tgts_store);
2630
2631static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2632{
2633 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2634}
2635DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2636
2637static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2638{
2639 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2640}
2641DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2642
2643static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2644{
2645 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2646}
2647static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2648 const char * buf, size_t count)
2649{
2650 int nth;
2651
2652 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2653 scsi_debug_every_nth = nth;
2654 scsi_debug_cmnd_count = 0;
2655 return count;
2656 }
2657 return -EINVAL;
2658}
2659DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2660 sdebug_every_nth_store);
2661
2662static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2663{
2664 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2665}
2666static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2667 const char * buf, size_t count)
2668{
2669 int n;
2670
2671 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2672 scsi_debug_max_luns = n;
2673 sdebug_max_tgts_luns();
2674 return count;
2675 }
2676 return -EINVAL;
2677}
2678DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2679 sdebug_max_luns_store);
2680
2681static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2682{
2683 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2684}
2685DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2686
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002687static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2688{
2689 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2690}
2691static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2692 const char * buf, size_t count)
2693{
2694 int n;
2695
2696 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2697 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002698
2699 sdebug_capacity = get_sdebug_capacity();
2700
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002701 return count;
2702 }
2703 return -EINVAL;
2704}
2705DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2706 sdebug_virtual_gb_store);
2707
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2709{
2710 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2711}
2712
2713static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2714 const char * buf, size_t count)
2715{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002716 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002718 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 if (delta_hosts > 0) {
2721 do {
2722 sdebug_add_adapter();
2723 } while (--delta_hosts);
2724 } else if (delta_hosts < 0) {
2725 do {
2726 sdebug_remove_adapter();
2727 } while (++delta_hosts);
2728 }
2729 return count;
2730}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002731DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 sdebug_add_host_store);
2733
Douglas Gilbert23183912006-09-16 20:30:47 -04002734static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2735 char * buf)
2736{
2737 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2738}
2739static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2740 const char * buf, size_t count)
2741{
2742 int n;
2743
2744 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2745 scsi_debug_vpd_use_hostno = n;
2746 return count;
2747 }
2748 return -EINVAL;
2749}
2750DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2751 sdebug_vpd_use_hostno_store);
2752
Martin K. Petersen597136a2008-06-05 00:12:59 -04002753static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf)
2754{
2755 return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);
2756}
2757DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL);
2758
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002759static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf)
2760{
2761 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);
2762}
2763DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL);
2764
2765static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf)
2766{
2767 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);
2768}
2769DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL);
2770
2771static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf)
2772{
2773 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard);
2774}
2775DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL);
2776
2777static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf)
2778{
2779 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);
2780}
2781DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL);
2782
2783
Douglas Gilbert23183912006-09-16 20:30:47 -04002784/* Note: The following function creates attribute files in the
2785 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2786 files (over those found in the /sys/module/scsi_debug/parameters
2787 directory) is that auxiliary actions can be triggered when an attribute
2788 is changed. For example see: sdebug_add_host_store() above.
2789 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002790static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002792 int ret;
2793
2794 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2795 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2796 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2797 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2798 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002799 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002800 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002801 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002802 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002803 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002804 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2805 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2806 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002807 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2808 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002809 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002810 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix);
2811 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif);
2812 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard);
2813 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002814 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815}
2816
2817static void do_remove_driverfs_files(void)
2818{
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002819 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato);
2820 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard);
2821 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif);
2822 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix);
Martin K. Petersen597136a2008-06-05 00:12:59 -04002823 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size);
Douglas Gilbert23183912006-09-16 20:30:47 -04002824 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2825 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2827 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2828 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002830 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2831 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002833 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2835 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2836 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2837 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2838 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2839}
2840
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002841static void pseudo_0_release(struct device *dev)
2842{
2843 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2844 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2845}
2846
2847static struct device pseudo_primary = {
Kay Sievers71610f52008-12-03 22:41:36 +01002848 .init_name = "pseudo_0",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002849 .release = pseudo_0_release,
2850};
2851
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852static int __init scsi_debug_init(void)
2853{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002854 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 int host_to_add;
2856 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002857 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
Martin K. Petersen597136a2008-06-05 00:12:59 -04002859 switch (scsi_debug_sector_size) {
2860 case 512:
2861 case 1024:
2862 case 2048:
2863 case 4096:
2864 break;
2865 default:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002866 printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n",
Martin K. Petersen597136a2008-06-05 00:12:59 -04002867 scsi_debug_sector_size);
2868 return -EINVAL;
2869 }
2870
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002871 switch (scsi_debug_dif) {
2872
2873 case SD_DIF_TYPE0_PROTECTION:
2874 case SD_DIF_TYPE1_PROTECTION:
2875 case SD_DIF_TYPE3_PROTECTION:
2876 break;
2877
2878 default:
2879 printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n");
2880 return -EINVAL;
2881 }
2882
2883 if (scsi_debug_guard > 1) {
2884 printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n");
2885 return -EINVAL;
2886 }
2887
2888 if (scsi_debug_ato > 1) {
2889 printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n");
2890 return -EINVAL;
2891 }
2892
Martin K. Petersenea61fca2009-05-15 00:40:33 -04002893 if (scsi_debug_physblk_exp > 15) {
2894 printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n",
2895 scsi_debug_physblk_exp);
2896 return -EINVAL;
2897 }
2898
2899 if (scsi_debug_lowest_aligned > 0x3fff) {
2900 printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n",
2901 scsi_debug_lowest_aligned);
2902 return -EINVAL;
2903 }
2904
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 if (scsi_debug_dev_size_mb < 1)
2906 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002907 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
Martin K. Petersen597136a2008-06-05 00:12:59 -04002908 sdebug_store_sectors = sz / scsi_debug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002909 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
2911 /* play around with geometry, don't waste too much on track 0 */
2912 sdebug_heads = 8;
2913 sdebug_sectors_per = 32;
2914 if (scsi_debug_dev_size_mb >= 16)
2915 sdebug_heads = 32;
2916 else if (scsi_debug_dev_size_mb >= 256)
2917 sdebug_heads = 64;
2918 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2919 (sdebug_sectors_per * sdebug_heads);
2920 if (sdebug_cylinders_per >= 1024) {
2921 /* other LLDs do this; implies >= 1GB ram disk ... */
2922 sdebug_heads = 255;
2923 sdebug_sectors_per = 63;
2924 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2925 (sdebug_sectors_per * sdebug_heads);
2926 }
2927
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 fake_storep = vmalloc(sz);
2929 if (NULL == fake_storep) {
2930 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2931 return -ENOMEM;
2932 }
2933 memset(fake_storep, 0, sz);
2934 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002935 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002937 if (scsi_debug_dif) {
2938 int dif_size;
2939
2940 dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
2941 dif_storep = vmalloc(dif_size);
2942
2943 printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n",
2944 dif_size, dif_storep);
2945
2946 if (dif_storep == NULL) {
2947 printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n");
2948 ret = -ENOMEM;
2949 goto free_vm;
2950 }
2951
2952 memset(dif_storep, 0xff, dif_size);
2953 }
2954
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002955 ret = device_register(&pseudo_primary);
2956 if (ret < 0) {
2957 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2958 ret);
2959 goto free_vm;
2960 }
2961 ret = bus_register(&pseudo_lld_bus);
2962 if (ret < 0) {
2963 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2964 ret);
2965 goto dev_unreg;
2966 }
2967 ret = driver_register(&sdebug_driverfs_driver);
2968 if (ret < 0) {
2969 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2970 ret);
2971 goto bus_unreg;
2972 }
2973 ret = do_create_driverfs_files();
2974 if (ret < 0) {
2975 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2976 ret);
2977 goto del_files;
2978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002980 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 host_to_add = scsi_debug_add_host;
2983 scsi_debug_add_host = 0;
2984
2985 for (k = 0; k < host_to_add; k++) {
2986 if (sdebug_add_adapter()) {
2987 printk(KERN_ERR "scsi_debug_init: "
2988 "sdebug_add_adapter failed k=%d\n", k);
2989 break;
2990 }
2991 }
2992
2993 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2994 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2995 scsi_debug_add_host);
2996 }
2997 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002998
2999del_files:
3000 do_remove_driverfs_files();
3001 driver_unregister(&sdebug_driverfs_driver);
3002bus_unreg:
3003 bus_unregister(&pseudo_lld_bus);
3004dev_unreg:
3005 device_unregister(&pseudo_primary);
3006free_vm:
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003007 if (dif_storep)
3008 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07003009 vfree(fake_storep);
3010
3011 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012}
3013
3014static void __exit scsi_debug_exit(void)
3015{
3016 int k = scsi_debug_add_host;
3017
3018 stop_all_queued();
3019 for (; k; k--)
3020 sdebug_remove_adapter();
3021 do_remove_driverfs_files();
3022 driver_unregister(&sdebug_driverfs_driver);
3023 bus_unregister(&pseudo_lld_bus);
3024 device_unregister(&pseudo_primary);
3025
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003026 if (dif_storep)
3027 vfree(dif_storep);
3028
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 vfree(fake_storep);
3030}
3031
3032device_initcall(scsi_debug_init);
3033module_exit(scsi_debug_exit);
3034
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035static void sdebug_release_adapter(struct device * dev)
3036{
3037 struct sdebug_host_info *sdbg_host;
3038
3039 sdbg_host = to_sdebug_host(dev);
3040 kfree(sdbg_host);
3041}
3042
3043static int sdebug_add_adapter(void)
3044{
3045 int k, devs_per_host;
3046 int error = 0;
3047 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003048 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003050 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 if (NULL == sdbg_host) {
3052 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003053 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 return -ENOMEM;
3055 }
3056
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
3058
3059 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
3060 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003061 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
3062 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 printk(KERN_ERR "%s: out of memory at line %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003064 __func__, __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 error = -ENOMEM;
3066 goto clean;
3067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 }
3069
3070 spin_lock(&sdebug_host_list_lock);
3071 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
3072 spin_unlock(&sdebug_host_list_lock);
3073
3074 sdbg_host->dev.bus = &pseudo_lld_bus;
3075 sdbg_host->dev.parent = &pseudo_primary;
3076 sdbg_host->dev.release = &sdebug_release_adapter;
Kay Sievers71610f52008-12-03 22:41:36 +01003077 dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078
3079 error = device_register(&sdbg_host->dev);
3080
3081 if (error)
3082 goto clean;
3083
3084 ++scsi_debug_add_host;
3085 return error;
3086
3087clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003088 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3089 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 list_del(&sdbg_devinfo->dev_list);
3091 kfree(sdbg_devinfo);
3092 }
3093
3094 kfree(sdbg_host);
3095 return error;
3096}
3097
3098static void sdebug_remove_adapter(void)
3099{
3100 struct sdebug_host_info * sdbg_host = NULL;
3101
3102 spin_lock(&sdebug_host_list_lock);
3103 if (!list_empty(&sdebug_host_list)) {
3104 sdbg_host = list_entry(sdebug_host_list.prev,
3105 struct sdebug_host_info, host_list);
3106 list_del(&sdbg_host->host_list);
3107 }
3108 spin_unlock(&sdebug_host_list_lock);
3109
3110 if (!sdbg_host)
3111 return;
3112
3113 device_unregister(&sdbg_host->dev);
3114 --scsi_debug_add_host;
3115}
3116
FUJITA Tomonori639db472008-03-20 11:09:19 +09003117static
3118int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
3119{
3120 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
3121 int len, k;
3122 unsigned int num;
3123 unsigned long long lba;
3124 int errsts = 0;
3125 int target = SCpnt->device->id;
3126 struct sdebug_dev_info *devip = NULL;
3127 int inj_recovered = 0;
3128 int inj_transport = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003129 int inj_dif = 0;
3130 int inj_dix = 0;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003131 int delay_override = 0;
3132
3133 scsi_set_resid(SCpnt, 0);
3134 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
3135 printk(KERN_INFO "scsi_debug: cmd ");
3136 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
3137 printk("%02x ", (int)cmd[k]);
3138 printk("\n");
3139 }
3140
3141 if (target == SCpnt->device->host->hostt->this_id) {
3142 printk(KERN_INFO "scsi_debug: initiator's id used as "
3143 "target!\n");
3144 return schedule_resp(SCpnt, NULL, done,
3145 DID_NO_CONNECT << 16, 0);
3146 }
3147
3148 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
3149 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
3150 return schedule_resp(SCpnt, NULL, done,
3151 DID_NO_CONNECT << 16, 0);
3152 devip = devInfoReg(SCpnt->device);
3153 if (NULL == devip)
3154 return schedule_resp(SCpnt, NULL, done,
3155 DID_NO_CONNECT << 16, 0);
3156
3157 if ((scsi_debug_every_nth != 0) &&
3158 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
3159 scsi_debug_cmnd_count = 0;
3160 if (scsi_debug_every_nth < -1)
3161 scsi_debug_every_nth = -1;
3162 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
3163 return 0; /* ignore command causing timeout */
3164 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
3165 inj_recovered = 1; /* to reads and writes below */
3166 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
3167 inj_transport = 1; /* to reads and writes below */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003168 else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
3169 inj_dif = 1; /* to reads and writes below */
3170 else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
3171 inj_dix = 1; /* to reads and writes below */
FUJITA Tomonori639db472008-03-20 11:09:19 +09003172 }
3173
3174 if (devip->wlun) {
3175 switch (*cmd) {
3176 case INQUIRY:
3177 case REQUEST_SENSE:
3178 case TEST_UNIT_READY:
3179 case REPORT_LUNS:
3180 break; /* only allowable wlun commands */
3181 default:
3182 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3183 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
3184 "not supported for wlun\n", *cmd);
3185 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3186 INVALID_OPCODE, 0);
3187 errsts = check_condition_result;
3188 return schedule_resp(SCpnt, devip, done, errsts,
3189 0);
3190 }
3191 }
3192
3193 switch (*cmd) {
3194 case INQUIRY: /* mandatory, ignore unit attention */
3195 delay_override = 1;
3196 errsts = resp_inquiry(SCpnt, target, devip);
3197 break;
3198 case REQUEST_SENSE: /* mandatory, ignore unit attention */
3199 delay_override = 1;
3200 errsts = resp_requests(SCpnt, devip);
3201 break;
3202 case REZERO_UNIT: /* actually this is REWIND for SSC */
3203 case START_STOP:
3204 errsts = resp_start_stop(SCpnt, devip);
3205 break;
3206 case ALLOW_MEDIUM_REMOVAL:
3207 errsts = check_readiness(SCpnt, 1, devip);
3208 if (errsts)
3209 break;
3210 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3211 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
3212 cmd[4] ? "inhibited" : "enabled");
3213 break;
3214 case SEND_DIAGNOSTIC: /* mandatory */
3215 errsts = check_readiness(SCpnt, 1, devip);
3216 break;
3217 case TEST_UNIT_READY: /* mandatory */
3218 delay_override = 1;
3219 errsts = check_readiness(SCpnt, 0, devip);
3220 break;
3221 case RESERVE:
3222 errsts = check_readiness(SCpnt, 1, devip);
3223 break;
3224 case RESERVE_10:
3225 errsts = check_readiness(SCpnt, 1, devip);
3226 break;
3227 case RELEASE:
3228 errsts = check_readiness(SCpnt, 1, devip);
3229 break;
3230 case RELEASE_10:
3231 errsts = check_readiness(SCpnt, 1, devip);
3232 break;
3233 case READ_CAPACITY:
3234 errsts = resp_readcap(SCpnt, devip);
3235 break;
3236 case SERVICE_ACTION_IN:
3237 if (SAI_READ_CAPACITY_16 != cmd[1]) {
3238 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3239 INVALID_OPCODE, 0);
3240 errsts = check_condition_result;
3241 break;
3242 }
3243 errsts = resp_readcap16(SCpnt, devip);
3244 break;
3245 case MAINTENANCE_IN:
3246 if (MI_REPORT_TARGET_PGS != cmd[1]) {
3247 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3248 INVALID_OPCODE, 0);
3249 errsts = check_condition_result;
3250 break;
3251 }
3252 errsts = resp_report_tgtpgs(SCpnt, devip);
3253 break;
3254 case READ_16:
3255 case READ_12:
3256 case READ_10:
3257 case READ_6:
3258 errsts = check_readiness(SCpnt, 0, devip);
3259 if (errsts)
3260 break;
3261 if (scsi_debug_fake_rw)
3262 break;
3263 get_data_transfer_info(cmd, &lba, &num);
3264 errsts = resp_read(SCpnt, lba, num, devip);
3265 if (inj_recovered && (0 == errsts)) {
3266 mk_sense_buffer(devip, RECOVERED_ERROR,
3267 THRESHOLD_EXCEEDED, 0);
3268 errsts = check_condition_result;
3269 } else if (inj_transport && (0 == errsts)) {
3270 mk_sense_buffer(devip, ABORTED_COMMAND,
3271 TRANSPORT_PROBLEM, ACK_NAK_TO);
3272 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003273 } else if (inj_dif && (0 == errsts)) {
3274 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3275 errsts = illegal_condition_result;
3276 } else if (inj_dix && (0 == errsts)) {
3277 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3278 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003279 }
3280 break;
3281 case REPORT_LUNS: /* mandatory, ignore unit attention */
3282 delay_override = 1;
3283 errsts = resp_report_luns(SCpnt, devip);
3284 break;
3285 case VERIFY: /* 10 byte SBC-2 command */
3286 errsts = check_readiness(SCpnt, 0, devip);
3287 break;
3288 case WRITE_16:
3289 case WRITE_12:
3290 case WRITE_10:
3291 case WRITE_6:
3292 errsts = check_readiness(SCpnt, 0, devip);
3293 if (errsts)
3294 break;
3295 if (scsi_debug_fake_rw)
3296 break;
3297 get_data_transfer_info(cmd, &lba, &num);
3298 errsts = resp_write(SCpnt, lba, num, devip);
3299 if (inj_recovered && (0 == errsts)) {
3300 mk_sense_buffer(devip, RECOVERED_ERROR,
3301 THRESHOLD_EXCEEDED, 0);
3302 errsts = check_condition_result;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003303 } else if (inj_dif && (0 == errsts)) {
3304 mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1);
3305 errsts = illegal_condition_result;
3306 } else if (inj_dix && (0 == errsts)) {
3307 mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1);
3308 errsts = illegal_condition_result;
FUJITA Tomonori639db472008-03-20 11:09:19 +09003309 }
3310 break;
3311 case MODE_SENSE:
3312 case MODE_SENSE_10:
3313 errsts = resp_mode_sense(SCpnt, target, devip);
3314 break;
3315 case MODE_SELECT:
3316 errsts = resp_mode_select(SCpnt, 1, devip);
3317 break;
3318 case MODE_SELECT_10:
3319 errsts = resp_mode_select(SCpnt, 0, devip);
3320 break;
3321 case LOG_SENSE:
3322 errsts = resp_log_sense(SCpnt, devip);
3323 break;
3324 case SYNCHRONIZE_CACHE:
3325 delay_override = 1;
3326 errsts = check_readiness(SCpnt, 0, devip);
3327 break;
3328 case WRITE_BUFFER:
3329 errsts = check_readiness(SCpnt, 1, devip);
3330 break;
3331 case XDWRITEREAD_10:
3332 if (!scsi_bidi_cmnd(SCpnt)) {
3333 mk_sense_buffer(devip, ILLEGAL_REQUEST,
3334 INVALID_FIELD_IN_CDB, 0);
3335 errsts = check_condition_result;
3336 break;
3337 }
3338
3339 errsts = check_readiness(SCpnt, 0, devip);
3340 if (errsts)
3341 break;
3342 if (scsi_debug_fake_rw)
3343 break;
3344 get_data_transfer_info(cmd, &lba, &num);
3345 errsts = resp_read(SCpnt, lba, num, devip);
3346 if (errsts)
3347 break;
3348 errsts = resp_write(SCpnt, lba, num, devip);
3349 if (errsts)
3350 break;
3351 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
3352 break;
3353 default:
3354 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
3355 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
3356 "supported\n", *cmd);
3357 errsts = check_readiness(SCpnt, 1, devip);
3358 if (errsts)
3359 break; /* Unit attention takes precedence */
3360 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
3361 errsts = check_condition_result;
3362 break;
3363 }
3364 return schedule_resp(SCpnt, devip, done, errsts,
3365 (delay_override ? 0 : scsi_debug_delay));
3366}
3367
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09003368static struct scsi_host_template sdebug_driver_template = {
3369 .proc_info = scsi_debug_proc_info,
3370 .proc_name = sdebug_proc_name,
3371 .name = "SCSI DEBUG",
3372 .info = scsi_debug_info,
3373 .slave_alloc = scsi_debug_slave_alloc,
3374 .slave_configure = scsi_debug_slave_configure,
3375 .slave_destroy = scsi_debug_slave_destroy,
3376 .ioctl = scsi_debug_ioctl,
3377 .queuecommand = scsi_debug_queuecommand,
3378 .eh_abort_handler = scsi_debug_abort,
3379 .eh_bus_reset_handler = scsi_debug_bus_reset,
3380 .eh_device_reset_handler = scsi_debug_device_reset,
3381 .eh_host_reset_handler = scsi_debug_host_reset,
3382 .bios_param = scsi_debug_biosparam,
3383 .can_queue = SCSI_DEBUG_CANQUEUE,
3384 .this_id = 7,
3385 .sg_tablesize = 256,
3386 .cmd_per_lun = 16,
3387 .max_sectors = 0xffff,
3388 .use_clustering = DISABLE_CLUSTERING,
3389 .module = THIS_MODULE,
3390};
3391
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392static int sdebug_driver_probe(struct device * dev)
3393{
3394 int error = 0;
3395 struct sdebug_host_info *sdbg_host;
3396 struct Scsi_Host *hpnt;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003397 int host_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398
3399 sdbg_host = to_sdebug_host(dev);
3400
3401 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3402 if (NULL == hpnt) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003403 printk(KERN_ERR "%s: scsi_register failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 error = -ENODEV;
3405 return error;
3406 }
3407
3408 sdbg_host->shost = hpnt;
3409 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3410 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3411 hpnt->max_id = scsi_debug_num_tgts + 1;
3412 else
3413 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003414 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003416 host_prot = 0;
3417
3418 switch (scsi_debug_dif) {
3419
3420 case SD_DIF_TYPE1_PROTECTION:
3421 host_prot = SHOST_DIF_TYPE1_PROTECTION;
3422 if (scsi_debug_dix)
3423 host_prot |= SHOST_DIX_TYPE1_PROTECTION;
3424 break;
3425
3426 case SD_DIF_TYPE2_PROTECTION:
3427 host_prot = SHOST_DIF_TYPE2_PROTECTION;
3428 if (scsi_debug_dix)
3429 host_prot |= SHOST_DIX_TYPE2_PROTECTION;
3430 break;
3431
3432 case SD_DIF_TYPE3_PROTECTION:
3433 host_prot = SHOST_DIF_TYPE3_PROTECTION;
3434 if (scsi_debug_dix)
3435 host_prot |= SHOST_DIX_TYPE3_PROTECTION;
3436 break;
3437
3438 default:
3439 if (scsi_debug_dix)
3440 host_prot |= SHOST_DIX_TYPE0_PROTECTION;
3441 break;
3442 }
3443
3444 scsi_host_set_prot(hpnt, host_prot);
3445
3446 printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n",
3447 (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
3448 (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
3449 (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
3450 (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
3451 (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
3452 (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
3453 (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
3454
3455 if (scsi_debug_guard == 1)
3456 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
3457 else
3458 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
3459
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 error = scsi_add_host(hpnt, &sdbg_host->dev);
3461 if (error) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003462 printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 error = -ENODEV;
3464 scsi_host_put(hpnt);
3465 } else
3466 scsi_scan_host(hpnt);
3467
3468
3469 return error;
3470}
3471
3472static int sdebug_driver_remove(struct device * dev)
3473{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003475 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476
3477 sdbg_host = to_sdebug_host(dev);
3478
3479 if (!sdbg_host) {
3480 printk(KERN_ERR "%s: Unable to locate host info\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003481 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 return -ENODEV;
3483 }
3484
3485 scsi_remove_host(sdbg_host->shost);
3486
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09003487 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
3488 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 list_del(&sdbg_devinfo->dev_list);
3490 kfree(sdbg_devinfo);
3491 }
3492
3493 scsi_host_put(sdbg_host->shost);
3494 return 0;
3495}
3496
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003497static int pseudo_lld_bus_match(struct device *dev,
3498 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003500 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003502
3503static struct bus_type pseudo_lld_bus = {
3504 .name = "pseudo",
3505 .match = pseudo_lld_bus_match,
3506 .probe = sdebug_driver_probe,
3507 .remove = sdebug_driver_remove,
3508};