blob: 07103c399fe0c2e7ce840fcdcb7d995bd277ca73 [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>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090043
44#include <scsi/scsi.h>
45#include <scsi/scsi_cmnd.h>
46#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <scsi/scsi_host.h>
48#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090049#include <scsi/scsi_eh.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51#include <linux/stat.h>
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050055#define SCSI_DEBUG_VERSION "1.81"
56static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050058/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040059#define NO_ADDITIONAL_SENSE 0x0
60#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040062#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#define INVALID_OPCODE 0x20
64#define ADDR_OUT_OF_RANGE 0x21
65#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040066#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#define POWERON_RESET 0x29
68#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define THRESHOLD_EXCEEDED 0x5d
71#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050073/* Additional Sense Code Qualifier (ASCQ) */
74#define ACK_NAK_TO 0x3
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
77
78/* Default values for driver parameters */
79#define DEF_NUM_HOST 1
80#define DEF_NUM_TGTS 1
81#define DEF_MAX_LUNS 1
82/* With these defaults, this driver will make 1 host with 1 target
83 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
84 */
85#define DEF_DELAY 1
86#define DEF_DEV_SIZE_MB 8
87#define DEF_EVERY_NTH 0
88#define DEF_NUM_PARTS 0
89#define DEF_OPTS 0
90#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
91#define DEF_PTYPE 0
92#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040093#define DEF_NO_LUN_0 0
94#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040095#define DEF_FAKE_RW 0
96#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98/* bit mask values for scsi_debug_opts */
99#define SCSI_DEBUG_OPT_NOISE 1
100#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
101#define SCSI_DEBUG_OPT_TIMEOUT 4
102#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500103#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104/* When "every_nth" > 0 then modulo "every_nth" commands:
105 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
106 * - a RECOVERED_ERROR is simulated on successful read and write
107 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500108 * - a TRANSPORT_ERROR is simulated on successful read and write
109 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 *
111 * When "every_nth" < 0 then after "- every_nth" commands:
112 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
113 * - a RECOVERED_ERROR is simulated on successful read and write
114 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500115 * - a TRANSPORT_ERROR is simulated on successful read and write
116 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 * This will continue until some other action occurs (e.g. the user
118 * writing a new value (other than -1 or 1) to every_nth via sysfs).
119 */
120
121/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
122 * sector on read commands: */
123#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
124
125/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
126 * or "peripheral device" addressing (value 0) */
127#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400128#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130static int scsi_debug_add_host = DEF_NUM_HOST;
131static int scsi_debug_delay = DEF_DELAY;
132static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
133static int scsi_debug_every_nth = DEF_EVERY_NTH;
134static int scsi_debug_max_luns = DEF_MAX_LUNS;
135static int scsi_debug_num_parts = DEF_NUM_PARTS;
136static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
137static int scsi_debug_opts = DEF_OPTS;
138static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
139static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
140static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400141static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
142static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400143static int scsi_debug_fake_rw = DEF_FAKE_RW;
144static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
146static int scsi_debug_cmnd_count = 0;
147
148#define DEV_READONLY(TGT) (0)
149#define DEV_REMOVEABLE(TGT) (0)
150
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400151static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static sector_t sdebug_capacity; /* in sectors */
153
154/* old BIOS stuff, kernel may get rid of them but some mode sense pages
155 may still need them */
156static int sdebug_heads; /* heads per disk */
157static int sdebug_cylinders_per; /* cylinders per surface */
158static int sdebug_sectors_per; /* sectors per cylinder */
159
160/* default sector size is 512 bytes, 2**9 bytes */
161#define POW2_SECT_SIZE 9
162#define SECT_SIZE (1 << POW2_SECT_SIZE)
163#define SECT_SIZE_PER(TGT) SECT_SIZE
164
165#define SDEBUG_MAX_PARTS 4
166
167#define SDEBUG_SENSE_LEN 32
168
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +0900169#define SCSI_DEBUG_CANQUEUE 255
170#define SCSI_DEBUG_MAX_CMD_LEN 16
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172struct sdebug_dev_info {
173 struct list_head dev_list;
174 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
175 unsigned int channel;
176 unsigned int target;
177 unsigned int lun;
178 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400179 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400181 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 char used;
183};
184
185struct sdebug_host_info {
186 struct list_head host_list;
187 struct Scsi_Host *shost;
188 struct device dev;
189 struct list_head dev_info_list;
190};
191
192#define to_sdebug_host(d) \
193 container_of(d, struct sdebug_host_info, dev)
194
195static LIST_HEAD(sdebug_host_list);
196static DEFINE_SPINLOCK(sdebug_host_list_lock);
197
198typedef void (* done_funct_t) (struct scsi_cmnd *);
199
200struct sdebug_queued_cmd {
201 int in_use;
202 struct timer_list cmnd_timer;
203 done_funct_t done_funct;
204 struct scsi_cmnd * a_cmnd;
205 int scsi_result;
206};
207static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209static unsigned char * fake_storep; /* ramdisk storage */
210
211static int num_aborts = 0;
212static int num_dev_resets = 0;
213static int num_bus_resets = 0;
214static int num_host_resets = 0;
215
216static DEFINE_SPINLOCK(queued_arr_lock);
217static DEFINE_RWLOCK(atomic_rw);
218
219static char sdebug_proc_name[] = "scsi_debug";
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221static struct bus_type pseudo_lld_bus;
222
223static struct device_driver sdebug_driverfs_driver = {
224 .name = sdebug_proc_name,
225 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226};
227
228static const int check_condition_result =
229 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
230
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400231static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
232 0, 0, 0x2, 0x4b};
233static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
234 0, 0, 0x0, 0x0};
235
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236static int sdebug_add_adapter(void);
237static void sdebug_remove_adapter(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900239static void sdebug_max_tgts_luns(void)
240{
241 struct sdebug_host_info *sdbg_host;
242 struct Scsi_Host *hpnt;
243
244 spin_lock(&sdebug_host_list_lock);
245 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
246 hpnt = sdbg_host->shost;
247 if ((hpnt->this_id >= 0) &&
248 (scsi_debug_num_tgts > hpnt->this_id))
249 hpnt->max_id = scsi_debug_num_tgts + 1;
250 else
251 hpnt->max_id = scsi_debug_num_tgts;
252 /* scsi_debug_max_luns; */
253 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;
254 }
255 spin_unlock(&sdebug_host_list_lock);
256}
257
258static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
259 int asc, int asq)
260{
261 unsigned char *sbuff;
262
263 sbuff = devip->sense_buff;
264 memset(sbuff, 0, SDEBUG_SENSE_LEN);
265
266 scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq);
267
268 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
269 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
270 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
271}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900273static void get_data_transfer_info(unsigned char *cmd,
274 unsigned long long *lba, unsigned int *num)
275{
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900276 switch (*cmd) {
277 case WRITE_16:
278 case READ_16:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900279 *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
280 (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
281 (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
282 (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
283
284 *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
285 (u32)cmd[10] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900286 break;
287 case WRITE_12:
288 case READ_12:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900289 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
290 (u32)cmd[2] << 24;
291
292 *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
293 (u32)cmd[6] << 24;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900294 break;
295 case WRITE_10:
296 case READ_10:
FUJITA Tomonoric639d142008-01-23 01:32:01 +0900297 case XDWRITEREAD_10:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900298 *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
299 (u32)cmd[2] << 24;
300
301 *num = (u32)cmd[8] | (u32)cmd[7] << 8;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900302 break;
303 case WRITE_6:
304 case READ_6:
FUJITA Tomonorid5cdc982008-03-25 17:04:46 +0900305 *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
306 (u32)(cmd[1] & 0x1f) << 16;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900307 *num = (0 == cmd[4]) ? 256 : cmd[4];
308 break;
309 default:
310 break;
311 }
312}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
315{
316 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
317 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
318 }
319 return -EINVAL;
320 /* return -ENOTTY; // correct return but upsets fdisk */
321}
322
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400323static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
324 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325{
326 if (devip->reset) {
327 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
328 printk(KERN_INFO "scsi_debug: Reporting Unit "
329 "attention: power on reset\n");
330 devip->reset = 0;
331 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
332 return check_condition_result;
333 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400334 if ((0 == reset_only) && devip->stopped) {
335 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
336 printk(KERN_INFO "scsi_debug: Reporting Not "
337 "ready: initializing command required\n");
338 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
339 0x2);
340 return check_condition_result;
341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return 0;
343}
344
345/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900346static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 int arr_len)
348{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900349 int act_len;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900350 struct scsi_data_buffer *sdb = scsi_in(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900352 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900354 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return (DID_ERROR << 16);
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900356
357 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
358 arr, arr_len);
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900359 if (sdb->resid)
360 sdb->resid -= act_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400361 else
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900362 sdb->resid = scsi_bufflen(scp) - act_len;
363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 return 0;
365}
366
367/* Returns number of bytes fetched into 'arr' or -1 if error. */
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900368static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
369 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370{
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900371 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 return 0;
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +0900373 if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +0900375
376 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
379
380static const char * inq_vendor_id = "Linux ";
381static const char * inq_product_id = "scsi_debug ";
382static const char * inq_product_rev = "0004";
383
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200384static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
385 int target_dev_id, int dev_id_num,
386 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400387 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400389 int num, port_a;
390 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400392 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 /* T10 vendor identifier field format (faked) */
394 arr[0] = 0x2; /* ASCII */
395 arr[1] = 0x1;
396 arr[2] = 0x0;
397 memcpy(&arr[4], inq_vendor_id, 8);
398 memcpy(&arr[12], inq_product_id, 16);
399 memcpy(&arr[28], dev_id_str, dev_id_str_len);
400 num = 8 + 16 + dev_id_str_len;
401 arr[3] = num;
402 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400403 if (dev_id_num >= 0) {
404 /* NAA-5, Logical unit identifier (binary) */
405 arr[num++] = 0x1; /* binary (not necessarily sas) */
406 arr[num++] = 0x3; /* PIV=0, lu, naa */
407 arr[num++] = 0x0;
408 arr[num++] = 0x8;
409 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
410 arr[num++] = 0x33;
411 arr[num++] = 0x33;
412 arr[num++] = 0x30;
413 arr[num++] = (dev_id_num >> 24);
414 arr[num++] = (dev_id_num >> 16) & 0xff;
415 arr[num++] = (dev_id_num >> 8) & 0xff;
416 arr[num++] = dev_id_num & 0xff;
417 /* Target relative port number */
418 arr[num++] = 0x61; /* proto=sas, binary */
419 arr[num++] = 0x94; /* PIV=1, target port, rel port */
420 arr[num++] = 0x0; /* reserved */
421 arr[num++] = 0x4; /* length */
422 arr[num++] = 0x0; /* reserved */
423 arr[num++] = 0x0; /* reserved */
424 arr[num++] = 0x0;
425 arr[num++] = 0x1; /* relative port A */
426 }
427 /* NAA-5, Target port identifier */
428 arr[num++] = 0x61; /* proto=sas, binary */
429 arr[num++] = 0x93; /* piv=1, target port, naa */
430 arr[num++] = 0x0;
431 arr[num++] = 0x8;
432 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
433 arr[num++] = 0x22;
434 arr[num++] = 0x22;
435 arr[num++] = 0x20;
436 arr[num++] = (port_a >> 24);
437 arr[num++] = (port_a >> 16) & 0xff;
438 arr[num++] = (port_a >> 8) & 0xff;
439 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200440 /* NAA-5, Target port group identifier */
441 arr[num++] = 0x61; /* proto=sas, binary */
442 arr[num++] = 0x95; /* piv=1, target port group id */
443 arr[num++] = 0x0;
444 arr[num++] = 0x4;
445 arr[num++] = 0;
446 arr[num++] = 0;
447 arr[num++] = (port_group_id >> 8) & 0xff;
448 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400449 /* NAA-5, Target device identifier */
450 arr[num++] = 0x61; /* proto=sas, binary */
451 arr[num++] = 0xa3; /* piv=1, target device, naa */
452 arr[num++] = 0x0;
453 arr[num++] = 0x8;
454 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
455 arr[num++] = 0x22;
456 arr[num++] = 0x22;
457 arr[num++] = 0x20;
458 arr[num++] = (target_dev_id >> 24);
459 arr[num++] = (target_dev_id >> 16) & 0xff;
460 arr[num++] = (target_dev_id >> 8) & 0xff;
461 arr[num++] = target_dev_id & 0xff;
462 /* SCSI name string: Target device identifier */
463 arr[num++] = 0x63; /* proto=sas, UTF-8 */
464 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
465 arr[num++] = 0x0;
466 arr[num++] = 24;
467 memcpy(arr + num, "naa.52222220", 12);
468 num += 12;
469 snprintf(b, sizeof(b), "%08X", target_dev_id);
470 memcpy(arr + num, b, 8);
471 num += 8;
472 memset(arr + num, 0, 4);
473 num += 4;
474 return num;
475}
476
477
478static unsigned char vpd84_data[] = {
479/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
480 0x22,0x22,0x22,0x0,0xbb,0x1,
481 0x22,0x22,0x22,0x0,0xbb,0x2,
482};
483
484static int inquiry_evpd_84(unsigned char * arr)
485{
486 memcpy(arr, vpd84_data, sizeof(vpd84_data));
487 return sizeof(vpd84_data);
488}
489
490static int inquiry_evpd_85(unsigned char * arr)
491{
492 int num = 0;
493 const char * na1 = "https://www.kernel.org/config";
494 const char * na2 = "http://www.kernel.org/log";
495 int plen, olen;
496
497 arr[num++] = 0x1; /* lu, storage config */
498 arr[num++] = 0x0; /* reserved */
499 arr[num++] = 0x0;
500 olen = strlen(na1);
501 plen = olen + 1;
502 if (plen % 4)
503 plen = ((plen / 4) + 1) * 4;
504 arr[num++] = plen; /* length, null termianted, padded */
505 memcpy(arr + num, na1, olen);
506 memset(arr + num + olen, 0, plen - olen);
507 num += plen;
508
509 arr[num++] = 0x4; /* lu, logging */
510 arr[num++] = 0x0; /* reserved */
511 arr[num++] = 0x0;
512 olen = strlen(na2);
513 plen = olen + 1;
514 if (plen % 4)
515 plen = ((plen / 4) + 1) * 4;
516 arr[num++] = plen; /* length, null terminated, padded */
517 memcpy(arr + num, na2, olen);
518 memset(arr + num + olen, 0, plen - olen);
519 num += plen;
520
521 return num;
522}
523
524/* SCSI ports VPD page */
525static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
526{
527 int num = 0;
528 int port_a, port_b;
529
530 port_a = target_dev_id + 1;
531 port_b = port_a + 1;
532 arr[num++] = 0x0; /* reserved */
533 arr[num++] = 0x0; /* reserved */
534 arr[num++] = 0x0;
535 arr[num++] = 0x1; /* relative port 1 (primary) */
536 memset(arr + num, 0, 6);
537 num += 6;
538 arr[num++] = 0x0;
539 arr[num++] = 12; /* length tp descriptor */
540 /* naa-5 target port identifier (A) */
541 arr[num++] = 0x61; /* proto=sas, binary */
542 arr[num++] = 0x93; /* PIV=1, target port, NAA */
543 arr[num++] = 0x0; /* reserved */
544 arr[num++] = 0x8; /* length */
545 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
546 arr[num++] = 0x22;
547 arr[num++] = 0x22;
548 arr[num++] = 0x20;
549 arr[num++] = (port_a >> 24);
550 arr[num++] = (port_a >> 16) & 0xff;
551 arr[num++] = (port_a >> 8) & 0xff;
552 arr[num++] = port_a & 0xff;
553
554 arr[num++] = 0x0; /* reserved */
555 arr[num++] = 0x0; /* reserved */
556 arr[num++] = 0x0;
557 arr[num++] = 0x2; /* relative port 2 (secondary) */
558 memset(arr + num, 0, 6);
559 num += 6;
560 arr[num++] = 0x0;
561 arr[num++] = 12; /* length tp descriptor */
562 /* naa-5 target port identifier (B) */
563 arr[num++] = 0x61; /* proto=sas, binary */
564 arr[num++] = 0x93; /* PIV=1, target port, NAA */
565 arr[num++] = 0x0; /* reserved */
566 arr[num++] = 0x8; /* length */
567 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
568 arr[num++] = 0x22;
569 arr[num++] = 0x22;
570 arr[num++] = 0x20;
571 arr[num++] = (port_b >> 24);
572 arr[num++] = (port_b >> 16) & 0xff;
573 arr[num++] = (port_b >> 8) & 0xff;
574 arr[num++] = port_b & 0xff;
575
576 return num;
577}
578
579
580static unsigned char vpd89_data[] = {
581/* from 4th byte */ 0,0,0,0,
582'l','i','n','u','x',' ',' ',' ',
583'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
584'1','2','3','4',
5850x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
5860xec,0,0,0,
5870x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
5880,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
5890x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
5900x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
5910x53,0x41,
5920x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5930x20,0x20,
5940x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
5950x10,0x80,
5960,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
5970x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
5980x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
5990,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
6000x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
6010x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
6020,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
6030,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6050,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6060x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
6070,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
6080xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
6090,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
6100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6190,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
6210,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
622};
623
624static int inquiry_evpd_89(unsigned char * arr)
625{
626 memcpy(arr, vpd89_data, sizeof(vpd89_data));
627 return sizeof(vpd89_data);
628}
629
630
631static unsigned char vpdb0_data[] = {
632 /* from 4th byte */ 0,0,0,4,
633 0,0,0x4,0,
634 0,0,0,64,
635};
636
637static int inquiry_evpd_b0(unsigned char * arr)
638{
639 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
640 if (sdebug_store_sectors > 0x400) {
641 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
642 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
643 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
644 arr[7] = sdebug_store_sectors & 0xff;
645 }
646 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
649
650#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400651#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653static int resp_inquiry(struct scsi_cmnd * scp, int target,
654 struct sdebug_dev_info * devip)
655{
656 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200657 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200659 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
661 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500662 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
663 if (! arr)
664 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400665 if (devip->wlun)
666 pq_pdt = 0x1e; /* present, wlun */
667 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
668 pq_pdt = 0x7f; /* not present, no device type */
669 else
670 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 arr[0] = pq_pdt;
672 if (0x2 & cmd[1]) { /* CMDDT bit set */
673 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
674 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200675 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 return check_condition_result;
677 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200678 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400679 char lu_id_str[6];
680 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200682 port_group_id = (((host_no + 1) & 0x7f) << 8) +
683 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400684 if (0 == scsi_debug_vpd_use_hostno)
685 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400686 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
687 (devip->target * 1000) + devip->lun);
688 target_dev_id = ((host_no + 1) * 2000) +
689 (devip->target * 1000) - 3;
690 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400692 arr[1] = cmd[2]; /*sanity */
693 n = 4;
694 arr[n++] = 0x0; /* this page */
695 arr[n++] = 0x80; /* unit serial number */
696 arr[n++] = 0x83; /* device identification */
697 arr[n++] = 0x84; /* software interface ident. */
698 arr[n++] = 0x85; /* management network addresses */
699 arr[n++] = 0x86; /* extended inquiry */
700 arr[n++] = 0x87; /* mode page policy */
701 arr[n++] = 0x88; /* SCSI ports */
702 arr[n++] = 0x89; /* ATA information */
703 arr[n++] = 0xb0; /* Block limits (SBC) */
704 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400706 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400708 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400710 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200711 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
712 target_dev_id, lu_id_num,
713 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400714 } else if (0x84 == cmd[2]) { /* Software interface ident. */
715 arr[1] = cmd[2]; /*sanity */
716 arr[3] = inquiry_evpd_84(&arr[4]);
717 } else if (0x85 == cmd[2]) { /* Management network addresses */
718 arr[1] = cmd[2]; /*sanity */
719 arr[3] = inquiry_evpd_85(&arr[4]);
720 } else if (0x86 == cmd[2]) { /* extended inquiry */
721 arr[1] = cmd[2]; /*sanity */
722 arr[3] = 0x3c; /* number of following entries */
723 arr[4] = 0x0; /* no protection stuff */
724 arr[5] = 0x7; /* head of q, ordered + simple q's */
725 } else if (0x87 == cmd[2]) { /* mode page policy */
726 arr[1] = cmd[2]; /*sanity */
727 arr[3] = 0x8; /* number of following entries */
728 arr[4] = 0x2; /* disconnect-reconnect mp */
729 arr[6] = 0x80; /* mlus, shared */
730 arr[8] = 0x18; /* protocol specific lu */
731 arr[10] = 0x82; /* mlus, per initiator port */
732 } else if (0x88 == cmd[2]) { /* SCSI Ports */
733 arr[1] = cmd[2]; /*sanity */
734 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
735 } else if (0x89 == cmd[2]) { /* ATA information */
736 arr[1] = cmd[2]; /*sanity */
737 n = inquiry_evpd_89(&arr[4]);
738 arr[2] = (n >> 8);
739 arr[3] = (n & 0xff);
740 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
741 arr[1] = cmd[2]; /*sanity */
742 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 } else {
744 /* Illegal request, invalid field in cdb */
745 mk_sense_buffer(devip, ILLEGAL_REQUEST,
746 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200747 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 return check_condition_result;
749 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400750 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200751 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400752 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200753 kfree(arr);
754 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 }
756 /* drops through here for a standard inquiry */
757 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
758 arr[2] = scsi_debug_scsi_level;
759 arr[3] = 2; /* response_data_format==2 */
760 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200761 if (0 == scsi_debug_vpd_use_hostno)
762 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400763 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400765 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 memcpy(&arr[8], inq_vendor_id, 8);
767 memcpy(&arr[16], inq_product_id, 16);
768 memcpy(&arr[32], inq_product_rev, 4);
769 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400770 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
771 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
772 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400774 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400776 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400778 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200779 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200781 kfree(arr);
782 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783}
784
785static int resp_requests(struct scsi_cmnd * scp,
786 struct sdebug_dev_info * devip)
787{
788 unsigned char * sbuff;
789 unsigned char *cmd = (unsigned char *)scp->cmnd;
790 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400791 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 int len = 18;
793
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400794 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400796 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
797 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400799 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
800 if (want_dsense) {
801 arr[0] = 0x72;
802 arr[1] = 0x0; /* NO_SENSE in sense_key */
803 arr[2] = THRESHOLD_EXCEEDED;
804 arr[3] = 0xff; /* TEST set and MRIE==6 */
805 } else {
806 arr[0] = 0x70;
807 arr[2] = 0x0; /* NO_SENSE in sense_key */
808 arr[7] = 0xa; /* 18 byte sense buffer */
809 arr[12] = THRESHOLD_EXCEEDED;
810 arr[13] = 0xff; /* TEST set and MRIE==6 */
811 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400812 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400814 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
815 /* DESC bit set and sense_buff in fixed format */
816 memset(arr, 0, sizeof(arr));
817 arr[0] = 0x72;
818 arr[1] = sbuff[2]; /* sense key */
819 arr[2] = sbuff[12]; /* asc */
820 arr[3] = sbuff[13]; /* ascq */
821 len = 8;
822 }
823 }
824 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 return fill_from_dev_buffer(scp, arr, len);
826}
827
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400828static int resp_start_stop(struct scsi_cmnd * scp,
829 struct sdebug_dev_info * devip)
830{
831 unsigned char *cmd = (unsigned char *)scp->cmnd;
832 int power_cond, errsts, start;
833
834 if ((errsts = check_readiness(scp, 1, devip)))
835 return errsts;
836 power_cond = (cmd[4] & 0xf0) >> 4;
837 if (power_cond) {
838 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
839 0);
840 return check_condition_result;
841 }
842 start = cmd[4] & 1;
843 if (start == devip->stopped)
844 devip->stopped = !start;
845 return 0;
846}
847
FUJITA Tomonori28898872008-03-30 00:59:55 +0900848static sector_t get_sdebug_capacity(void)
849{
850 if (scsi_debug_virtual_gb > 0)
851 return 2048 * 1024 * scsi_debug_virtual_gb;
852 else
853 return sdebug_store_sectors;
854}
855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856#define SDEBUG_READCAP_ARR_SZ 8
857static int resp_readcap(struct scsi_cmnd * scp,
858 struct sdebug_dev_info * devip)
859{
860 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400861 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 int errsts;
863
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400864 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400866 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900867 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400869 if (sdebug_capacity < 0xffffffff) {
870 capac = (unsigned int)sdebug_capacity - 1;
871 arr[0] = (capac >> 24);
872 arr[1] = (capac >> 16) & 0xff;
873 arr[2] = (capac >> 8) & 0xff;
874 arr[3] = capac & 0xff;
875 } else {
876 arr[0] = 0xff;
877 arr[1] = 0xff;
878 arr[2] = 0xff;
879 arr[3] = 0xff;
880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
882 arr[7] = SECT_SIZE_PER(target) & 0xff;
883 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
884}
885
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400886#define SDEBUG_READCAP16_ARR_SZ 32
887static int resp_readcap16(struct scsi_cmnd * scp,
888 struct sdebug_dev_info * devip)
889{
890 unsigned char *cmd = (unsigned char *)scp->cmnd;
891 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
892 unsigned long long capac;
893 int errsts, k, alloc_len;
894
895 if ((errsts = check_readiness(scp, 1, devip)))
896 return errsts;
897 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
898 + cmd[13]);
899 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +0900900 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400901 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
902 capac = sdebug_capacity - 1;
903 for (k = 0; k < 8; ++k, capac >>= 8)
904 arr[7 - k] = capac & 0xff;
905 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
906 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
907 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
908 arr[11] = SECT_SIZE_PER(target) & 0xff;
909 return fill_from_dev_buffer(scp, arr,
910 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
911}
912
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200913#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
914
915static int resp_report_tgtpgs(struct scsi_cmnd * scp,
916 struct sdebug_dev_info * devip)
917{
918 unsigned char *cmd = (unsigned char *)scp->cmnd;
919 unsigned char * arr;
920 int host_no = devip->sdbg_host->shost->host_no;
921 int n, ret, alen, rlen;
922 int port_group_a, port_group_b, port_a, port_b;
923
924 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
925 + cmd[9]);
926
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500927 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
928 if (! arr)
929 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200930 /*
931 * EVPD page 0x88 states we have two ports, one
932 * real and a fake port with no device connected.
933 * So we create two port groups with one port each
934 * and set the group with port B to unavailable.
935 */
936 port_a = 0x1; /* relative port A */
937 port_b = 0x2; /* relative port B */
938 port_group_a = (((host_no + 1) & 0x7f) << 8) +
939 (devip->channel & 0x7f);
940 port_group_b = (((host_no + 1) & 0x7f) << 8) +
941 (devip->channel & 0x7f) + 0x80;
942
943 /*
944 * The asymmetric access state is cycled according to the host_id.
945 */
946 n = 4;
947 if (0 == scsi_debug_vpd_use_hostno) {
948 arr[n++] = host_no % 3; /* Asymm access state */
949 arr[n++] = 0x0F; /* claim: all states are supported */
950 } else {
951 arr[n++] = 0x0; /* Active/Optimized path */
952 arr[n++] = 0x01; /* claim: only support active/optimized paths */
953 }
954 arr[n++] = (port_group_a >> 8) & 0xff;
955 arr[n++] = port_group_a & 0xff;
956 arr[n++] = 0; /* Reserved */
957 arr[n++] = 0; /* Status code */
958 arr[n++] = 0; /* Vendor unique */
959 arr[n++] = 0x1; /* One port per group */
960 arr[n++] = 0; /* Reserved */
961 arr[n++] = 0; /* Reserved */
962 arr[n++] = (port_a >> 8) & 0xff;
963 arr[n++] = port_a & 0xff;
964 arr[n++] = 3; /* Port unavailable */
965 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
966 arr[n++] = (port_group_b >> 8) & 0xff;
967 arr[n++] = port_group_b & 0xff;
968 arr[n++] = 0; /* Reserved */
969 arr[n++] = 0; /* Status code */
970 arr[n++] = 0; /* Vendor unique */
971 arr[n++] = 0x1; /* One port per group */
972 arr[n++] = 0; /* Reserved */
973 arr[n++] = 0; /* Reserved */
974 arr[n++] = (port_b >> 8) & 0xff;
975 arr[n++] = port_b & 0xff;
976
977 rlen = n - 4;
978 arr[0] = (rlen >> 24) & 0xff;
979 arr[1] = (rlen >> 16) & 0xff;
980 arr[2] = (rlen >> 8) & 0xff;
981 arr[3] = rlen & 0xff;
982
983 /*
984 * Return the smallest value of either
985 * - The allocated length
986 * - The constructed command length
987 * - The maximum array size
988 */
989 rlen = min(alen,n);
990 ret = fill_from_dev_buffer(scp, arr,
991 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
992 kfree(arr);
993 return ret;
994}
995
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996/* <<Following mode page info copied from ST318451LW>> */
997
998static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
999{ /* Read-Write Error Recovery page for mode_sense */
1000 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1001 5, 0, 0xff, 0xff};
1002
1003 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1004 if (1 == pcontrol)
1005 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1006 return sizeof(err_recov_pg);
1007}
1008
1009static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1010{ /* Disconnect-Reconnect page for mode_sense */
1011 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1012 0, 0, 0, 0, 0, 0, 0, 0};
1013
1014 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1015 if (1 == pcontrol)
1016 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1017 return sizeof(disconnect_pg);
1018}
1019
1020static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1021{ /* Format device page for mode_sense */
1022 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1023 0, 0, 0, 0, 0, 0, 0, 0,
1024 0, 0, 0, 0, 0x40, 0, 0, 0};
1025
1026 memcpy(p, format_pg, sizeof(format_pg));
1027 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1028 p[11] = sdebug_sectors_per & 0xff;
1029 p[12] = (SECT_SIZE >> 8) & 0xff;
1030 p[13] = SECT_SIZE & 0xff;
1031 if (DEV_REMOVEABLE(target))
1032 p[20] |= 0x20; /* should agree with INQUIRY */
1033 if (1 == pcontrol)
1034 memset(p + 2, 0, sizeof(format_pg) - 2);
1035 return sizeof(format_pg);
1036}
1037
1038static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1039{ /* Caching page for mode_sense */
1040 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1041 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1042
1043 memcpy(p, caching_pg, sizeof(caching_pg));
1044 if (1 == pcontrol)
1045 memset(p + 2, 0, sizeof(caching_pg) - 2);
1046 return sizeof(caching_pg);
1047}
1048
1049static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1050{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001051 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1052 0, 0, 0, 0};
1053 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 0, 0, 0x2, 0x4b};
1055
1056 if (scsi_debug_dsense)
1057 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001058 else
1059 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1061 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001062 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1063 else if (2 == pcontrol)
1064 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 return sizeof(ctrl_m_pg);
1066}
1067
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1070{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001071 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1072 0, 0, 0x0, 0x0};
1073 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1074 0, 0, 0x0, 0x0};
1075
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1077 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001078 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1079 else if (2 == pcontrol)
1080 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 return sizeof(iec_m_pg);
1082}
1083
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001084static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1085{ /* SAS SSP mode page - short format for mode_sense */
1086 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1087 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1088
1089 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1090 if (1 == pcontrol)
1091 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1092 return sizeof(sas_sf_m_pg);
1093}
1094
1095
1096static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1097 int target_dev_id)
1098{ /* SAS phy control and discover mode page for mode_sense */
1099 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1100 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1101 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1102 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1103 0x2, 0, 0, 0, 0, 0, 0, 0,
1104 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1105 0, 0, 0, 0, 0, 0, 0, 0,
1106 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1107 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1108 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1109 0x3, 0, 0, 0, 0, 0, 0, 0,
1110 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1111 0, 0, 0, 0, 0, 0, 0, 0,
1112 };
1113 int port_a, port_b;
1114
1115 port_a = target_dev_id + 1;
1116 port_b = port_a + 1;
1117 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1118 p[20] = (port_a >> 24);
1119 p[21] = (port_a >> 16) & 0xff;
1120 p[22] = (port_a >> 8) & 0xff;
1121 p[23] = port_a & 0xff;
1122 p[48 + 20] = (port_b >> 24);
1123 p[48 + 21] = (port_b >> 16) & 0xff;
1124 p[48 + 22] = (port_b >> 8) & 0xff;
1125 p[48 + 23] = port_b & 0xff;
1126 if (1 == pcontrol)
1127 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1128 return sizeof(sas_pcd_m_pg);
1129}
1130
1131static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1132{ /* SAS SSP shared protocol specific port mode subpage */
1133 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1134 0, 0, 0, 0, 0, 0, 0, 0,
1135 };
1136
1137 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1138 if (1 == pcontrol)
1139 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1140 return sizeof(sas_sha_m_pg);
1141}
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143#define SDEBUG_MAX_MSENSE_SZ 256
1144
1145static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1146 struct sdebug_dev_info * devip)
1147{
Douglas Gilbert23183912006-09-16 20:30:47 -04001148 unsigned char dbd, llbaa;
1149 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001151 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 unsigned char * ap;
1153 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1154 unsigned char *cmd = (unsigned char *)scp->cmnd;
1155
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001156 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001158 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 pcontrol = (cmd[2] & 0xc0) >> 6;
1160 pcode = cmd[2] & 0x3f;
1161 subpcode = cmd[3];
1162 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001163 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1164 if ((0 == scsi_debug_ptype) && (0 == dbd))
1165 bd_len = llbaa ? 16 : 8;
1166 else
1167 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1169 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1170 if (0x3 == pcontrol) { /* Saving values not supported */
1171 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1172 0);
1173 return check_condition_result;
1174 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001175 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1176 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001177 /* set DPOFUA bit for disks */
1178 if (0 == scsi_debug_ptype)
1179 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1180 else
1181 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 if (msense_6) {
1183 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001184 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 offset = 4;
1186 } else {
1187 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001188 if (16 == bd_len)
1189 arr[4] = 0x1; /* set LONGLBA bit */
1190 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 offset = 8;
1192 }
1193 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09001194 if ((bd_len > 0) && (!sdebug_capacity))
1195 sdebug_capacity = get_sdebug_capacity();
1196
Douglas Gilbert23183912006-09-16 20:30:47 -04001197 if (8 == bd_len) {
1198 if (sdebug_capacity > 0xfffffffe) {
1199 ap[0] = 0xff;
1200 ap[1] = 0xff;
1201 ap[2] = 0xff;
1202 ap[3] = 0xff;
1203 } else {
1204 ap[0] = (sdebug_capacity >> 24) & 0xff;
1205 ap[1] = (sdebug_capacity >> 16) & 0xff;
1206 ap[2] = (sdebug_capacity >> 8) & 0xff;
1207 ap[3] = sdebug_capacity & 0xff;
1208 }
1209 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1210 ap[7] = SECT_SIZE_PER(target) & 0xff;
1211 offset += bd_len;
1212 ap = arr + offset;
1213 } else if (16 == bd_len) {
1214 unsigned long long capac = sdebug_capacity;
1215
1216 for (k = 0; k < 8; ++k, capac >>= 8)
1217 ap[7 - k] = capac & 0xff;
1218 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1219 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1220 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1221 ap[15] = SECT_SIZE_PER(target) & 0xff;
1222 offset += bd_len;
1223 ap = arr + offset;
1224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001226 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1227 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1229 0);
1230 return check_condition_result;
1231 }
1232 switch (pcode) {
1233 case 0x1: /* Read-Write error recovery page, direct access */
1234 len = resp_err_recov_pg(ap, pcontrol, target);
1235 offset += len;
1236 break;
1237 case 0x2: /* Disconnect-Reconnect page, all devices */
1238 len = resp_disconnect_pg(ap, pcontrol, target);
1239 offset += len;
1240 break;
1241 case 0x3: /* Format device page, direct access */
1242 len = resp_format_pg(ap, pcontrol, target);
1243 offset += len;
1244 break;
1245 case 0x8: /* Caching page, direct access */
1246 len = resp_caching_pg(ap, pcontrol, target);
1247 offset += len;
1248 break;
1249 case 0xa: /* Control Mode page, all devices */
1250 len = resp_ctrl_m_pg(ap, pcontrol, target);
1251 offset += len;
1252 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001253 case 0x19: /* if spc==1 then sas phy, control+discover */
1254 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1255 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1256 INVALID_FIELD_IN_CDB, 0);
1257 return check_condition_result;
1258 }
1259 len = 0;
1260 if ((0x0 == subpcode) || (0xff == subpcode))
1261 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1262 if ((0x1 == subpcode) || (0xff == subpcode))
1263 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1264 target_dev_id);
1265 if ((0x2 == subpcode) || (0xff == subpcode))
1266 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1267 offset += len;
1268 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 case 0x1c: /* Informational Exceptions Mode page, all devices */
1270 len = resp_iec_m_pg(ap, pcontrol, target);
1271 offset += len;
1272 break;
1273 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001274 if ((0 == subpcode) || (0xff == subpcode)) {
1275 len = resp_err_recov_pg(ap, pcontrol, target);
1276 len += resp_disconnect_pg(ap + len, pcontrol, target);
1277 len += resp_format_pg(ap + len, pcontrol, target);
1278 len += resp_caching_pg(ap + len, pcontrol, target);
1279 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1280 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1281 if (0xff == subpcode) {
1282 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1283 target, target_dev_id);
1284 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1285 }
1286 len += resp_iec_m_pg(ap + len, pcontrol, target);
1287 } else {
1288 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1289 INVALID_FIELD_IN_CDB, 0);
1290 return check_condition_result;
1291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 offset += len;
1293 break;
1294 default:
1295 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1296 0);
1297 return check_condition_result;
1298 }
1299 if (msense_6)
1300 arr[0] = offset - 1;
1301 else {
1302 arr[0] = ((offset - 2) >> 8) & 0xff;
1303 arr[1] = (offset - 2) & 0xff;
1304 }
1305 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1306}
1307
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001308#define SDEBUG_MAX_MSELECT_SZ 512
1309
1310static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1311 struct sdebug_dev_info * devip)
1312{
1313 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1314 int param_len, res, errsts, mpage;
1315 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1316 unsigned char *cmd = (unsigned char *)scp->cmnd;
1317
1318 if ((errsts = check_readiness(scp, 1, devip)))
1319 return errsts;
1320 memset(arr, 0, sizeof(arr));
1321 pf = cmd[1] & 0x10;
1322 sp = cmd[1] & 0x1;
1323 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1324 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1325 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1326 INVALID_FIELD_IN_CDB, 0);
1327 return check_condition_result;
1328 }
1329 res = fetch_to_dev_buffer(scp, arr, param_len);
1330 if (-1 == res)
1331 return (DID_ERROR << 16);
1332 else if ((res < param_len) &&
1333 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1334 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1335 " IO sent=%d bytes\n", param_len, res);
1336 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1337 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001338 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001339 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1340 INVALID_FIELD_IN_PARAM_LIST, 0);
1341 return check_condition_result;
1342 }
1343 off = bd_len + (mselect6 ? 4 : 8);
1344 mpage = arr[off] & 0x3f;
1345 ps = !!(arr[off] & 0x80);
1346 if (ps) {
1347 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1348 INVALID_FIELD_IN_PARAM_LIST, 0);
1349 return check_condition_result;
1350 }
1351 spf = !!(arr[off] & 0x40);
1352 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1353 (arr[off + 1] + 2);
1354 if ((pg_len + off) > param_len) {
1355 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1356 PARAMETER_LIST_LENGTH_ERR, 0);
1357 return check_condition_result;
1358 }
1359 switch (mpage) {
1360 case 0xa: /* Control Mode page */
1361 if (ctrl_m_pg[1] == arr[off + 1]) {
1362 memcpy(ctrl_m_pg + 2, arr + off + 2,
1363 sizeof(ctrl_m_pg) - 2);
1364 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1365 return 0;
1366 }
1367 break;
1368 case 0x1c: /* Informational Exceptions Mode page */
1369 if (iec_m_pg[1] == arr[off + 1]) {
1370 memcpy(iec_m_pg + 2, arr + off + 2,
1371 sizeof(iec_m_pg) - 2);
1372 return 0;
1373 }
1374 break;
1375 default:
1376 break;
1377 }
1378 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1379 INVALID_FIELD_IN_PARAM_LIST, 0);
1380 return check_condition_result;
1381}
1382
1383static int resp_temp_l_pg(unsigned char * arr)
1384{
1385 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1386 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1387 };
1388
1389 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1390 return sizeof(temp_l_pg);
1391}
1392
1393static int resp_ie_l_pg(unsigned char * arr)
1394{
1395 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1396 };
1397
1398 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1399 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1400 arr[4] = THRESHOLD_EXCEEDED;
1401 arr[5] = 0xff;
1402 }
1403 return sizeof(ie_l_pg);
1404}
1405
1406#define SDEBUG_MAX_LSENSE_SZ 512
1407
1408static int resp_log_sense(struct scsi_cmnd * scp,
1409 struct sdebug_dev_info * devip)
1410{
Douglas Gilbert23183912006-09-16 20:30:47 -04001411 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001412 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1413 unsigned char *cmd = (unsigned char *)scp->cmnd;
1414
1415 if ((errsts = check_readiness(scp, 1, devip)))
1416 return errsts;
1417 memset(arr, 0, sizeof(arr));
1418 ppc = cmd[1] & 0x2;
1419 sp = cmd[1] & 0x1;
1420 if (ppc || sp) {
1421 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1422 INVALID_FIELD_IN_CDB, 0);
1423 return check_condition_result;
1424 }
1425 pcontrol = (cmd[2] & 0xc0) >> 6;
1426 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001427 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001428 alloc_len = (cmd[7] << 8) + cmd[8];
1429 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001430 if (0 == subpcode) {
1431 switch (pcode) {
1432 case 0x0: /* Supported log pages log page */
1433 n = 4;
1434 arr[n++] = 0x0; /* this page */
1435 arr[n++] = 0xd; /* Temperature */
1436 arr[n++] = 0x2f; /* Informational exceptions */
1437 arr[3] = n - 4;
1438 break;
1439 case 0xd: /* Temperature log page */
1440 arr[3] = resp_temp_l_pg(arr + 4);
1441 break;
1442 case 0x2f: /* Informational exceptions log page */
1443 arr[3] = resp_ie_l_pg(arr + 4);
1444 break;
1445 default:
1446 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1447 INVALID_FIELD_IN_CDB, 0);
1448 return check_condition_result;
1449 }
1450 } else if (0xff == subpcode) {
1451 arr[0] |= 0x40;
1452 arr[1] = subpcode;
1453 switch (pcode) {
1454 case 0x0: /* Supported log pages and subpages log page */
1455 n = 4;
1456 arr[n++] = 0x0;
1457 arr[n++] = 0x0; /* 0,0 page */
1458 arr[n++] = 0x0;
1459 arr[n++] = 0xff; /* this page */
1460 arr[n++] = 0xd;
1461 arr[n++] = 0x0; /* Temperature */
1462 arr[n++] = 0x2f;
1463 arr[n++] = 0x0; /* Informational exceptions */
1464 arr[3] = n - 4;
1465 break;
1466 case 0xd: /* Temperature subpages */
1467 n = 4;
1468 arr[n++] = 0xd;
1469 arr[n++] = 0x0; /* Temperature */
1470 arr[3] = n - 4;
1471 break;
1472 case 0x2f: /* Informational exceptions subpages */
1473 n = 4;
1474 arr[n++] = 0x2f;
1475 arr[n++] = 0x0; /* Informational exceptions */
1476 arr[3] = n - 4;
1477 break;
1478 default:
1479 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1480 INVALID_FIELD_IN_CDB, 0);
1481 return check_condition_result;
1482 }
1483 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001484 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1485 INVALID_FIELD_IN_CDB, 0);
1486 return check_condition_result;
1487 }
1488 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1489 return fill_from_dev_buffer(scp, arr,
1490 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1491}
1492
FUJITA Tomonori19789102008-03-30 00:59:56 +09001493static int check_device_access_params(struct sdebug_dev_info *devi,
1494 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001496 if (lba + num > sdebug_capacity) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001497 mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 return check_condition_result;
1499 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001500 /* transfer length excessive (tie in to block limits VPD page) */
1501 if (num > sdebug_store_sectors) {
FUJITA Tomonori19789102008-03-30 00:59:56 +09001502 mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001503 return check_condition_result;
1504 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09001505 return 0;
1506}
1507
1508static int do_device_access(struct scsi_cmnd *scmd,
1509 struct sdebug_dev_info *devi,
1510 unsigned long long lba, unsigned int num, int write)
1511{
1512 int ret;
1513 unsigned int block, rest = 0;
1514 int (*func)(struct scsi_cmnd *, unsigned char *, int);
1515
1516 func = write ? fetch_to_dev_buffer : fill_from_dev_buffer;
1517
1518 block = do_div(lba, sdebug_store_sectors);
1519 if (block + num > sdebug_store_sectors)
1520 rest = block + num - sdebug_store_sectors;
1521
1522 ret = func(scmd, fake_storep + (block * SECT_SIZE),
1523 (num - rest) * SECT_SIZE);
1524 if (!ret && rest)
1525 ret = func(scmd, fake_storep, rest * SECT_SIZE);
1526
1527 return ret;
1528}
1529
1530static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
1531 unsigned int num, struct sdebug_dev_info *devip)
1532{
1533 unsigned long iflags;
1534 int ret;
1535
1536 ret = check_device_access_params(devip, lba, num);
1537 if (ret)
1538 return ret;
1539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001541 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1542 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1543 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1545 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001546 /* set info field and valid bit for fixed descriptor */
1547 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1548 devip->sense_buff[0] |= 0x80; /* Valid bit */
1549 ret = OPT_MEDIUM_ERR_ADDR;
1550 devip->sense_buff[3] = (ret >> 24) & 0xff;
1551 devip->sense_buff[4] = (ret >> 16) & 0xff;
1552 devip->sense_buff[5] = (ret >> 8) & 0xff;
1553 devip->sense_buff[6] = ret & 0xff;
1554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 return check_condition_result;
1556 }
1557 read_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001558 ret = do_device_access(SCpnt, devip, lba, num, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 read_unlock_irqrestore(&atomic_rw, iflags);
1560 return ret;
1561}
1562
FUJITA Tomonori19789102008-03-30 00:59:56 +09001563static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
1564 unsigned int num, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565{
1566 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09001567 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
FUJITA Tomonori19789102008-03-30 00:59:56 +09001569 ret = check_device_access_params(devip, lba, num);
1570 if (ret)
1571 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
1573 write_lock_irqsave(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001574 ret = do_device_access(SCpnt, devip, lba, num, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 write_unlock_irqrestore(&atomic_rw, iflags);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001576 if (-1 == ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 return (DID_ERROR << 16);
FUJITA Tomonori19789102008-03-30 00:59:56 +09001578 else if ((ret < (num * SECT_SIZE)) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001580 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
FUJITA Tomonori19789102008-03-30 00:59:56 +09001581 " IO sent=%d bytes\n", num * SECT_SIZE, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 return 0;
1583}
1584
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001585#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587static int resp_report_luns(struct scsi_cmnd * scp,
1588 struct sdebug_dev_info * devip)
1589{
1590 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001591 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 unsigned char *cmd = (unsigned char *)scp->cmnd;
1593 int select_report = (int)cmd[2];
1594 struct scsi_lun *one_lun;
1595 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001596 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
1598 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001599 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1601 0);
1602 return check_condition_result;
1603 }
1604 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1605 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1606 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001607 if (1 == select_report)
1608 lun_cnt = 0;
1609 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1610 --lun_cnt;
1611 wlun = (select_report > 0) ? 1 : 0;
1612 num = lun_cnt + wlun;
1613 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1614 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1615 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1616 sizeof(struct scsi_lun)), num);
1617 if (n < num) {
1618 wlun = 0;
1619 lun_cnt = n;
1620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001622 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1623 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1624 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1625 i++, lun++) {
1626 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 if (upper)
1628 one_lun[i].scsi_lun[0] =
1629 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001630 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001632 if (wlun) {
1633 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1634 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1635 i++;
1636 }
1637 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 return fill_from_dev_buffer(scp, arr,
1639 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1640}
1641
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001642static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
1643 unsigned int num, struct sdebug_dev_info *devip)
1644{
1645 int i, j, ret = -1;
1646 unsigned char *kaddr, *buf;
1647 unsigned int offset;
1648 struct scatterlist *sg;
1649 struct scsi_data_buffer *sdb = scsi_in(scp);
1650
1651 /* better not to use temporary buffer. */
1652 buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
1653 if (!buf)
1654 return ret;
1655
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001656 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
FUJITA Tomonoric639d142008-01-23 01:32:01 +09001657
1658 offset = 0;
1659 for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
1660 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
1661 if (!kaddr)
1662 goto out;
1663
1664 for (j = 0; j < sg->length; j++)
1665 *(kaddr + sg->offset + j) ^= *(buf + offset + j);
1666
1667 offset += sg->length;
1668 kunmap_atomic(kaddr, KM_USER0);
1669 }
1670 ret = 0;
1671out:
1672 kfree(buf);
1673
1674 return ret;
1675}
1676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677/* When timer goes off this function is called. */
1678static void timer_intr_handler(unsigned long indx)
1679{
1680 struct sdebug_queued_cmd * sqcp;
1681 unsigned long iflags;
1682
1683 if (indx >= SCSI_DEBUG_CANQUEUE) {
1684 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1685 "large\n");
1686 return;
1687 }
1688 spin_lock_irqsave(&queued_arr_lock, iflags);
1689 sqcp = &queued_arr[(int)indx];
1690 if (! sqcp->in_use) {
1691 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1692 "interrupt\n");
1693 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1694 return;
1695 }
1696 sqcp->in_use = 0;
1697 if (sqcp->done_funct) {
1698 sqcp->a_cmnd->result = sqcp->scsi_result;
1699 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1700 }
1701 sqcp->done_funct = NULL;
1702 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1703}
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001706static struct sdebug_dev_info *
1707sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001708{
1709 struct sdebug_dev_info *devip;
1710
1711 devip = kzalloc(sizeof(*devip), flags);
1712 if (devip) {
1713 devip->sdbg_host = sdbg_host;
1714 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
1715 }
1716 return devip;
1717}
1718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1720{
1721 struct sdebug_host_info * sdbg_host;
1722 struct sdebug_dev_info * open_devip = NULL;
1723 struct sdebug_dev_info * devip =
1724 (struct sdebug_dev_info *)sdev->hostdata;
1725
1726 if (devip)
1727 return devip;
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001728 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
1729 if (!sdbg_host) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 printk(KERN_ERR "Host info NULL\n");
1731 return NULL;
1732 }
1733 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1734 if ((devip->used) && (devip->channel == sdev->channel) &&
1735 (devip->target == sdev->id) &&
1736 (devip->lun == sdev->lun))
1737 return devip;
1738 else {
1739 if ((!devip->used) && (!open_devip))
1740 open_devip = devip;
1741 }
1742 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09001743 if (!open_devip) { /* try and make a new one */
1744 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
1745 if (!open_devip) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 printk(KERN_ERR "%s: out of memory at line %d\n",
1747 __FUNCTION__, __LINE__);
1748 return NULL;
1749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09001751
1752 open_devip->channel = sdev->channel;
1753 open_devip->target = sdev->id;
1754 open_devip->lun = sdev->lun;
1755 open_devip->sdbg_host = sdbg_host;
1756 open_devip->reset = 1;
1757 open_devip->used = 1;
1758 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1759 if (scsi_debug_dsense)
1760 open_devip->sense_buff[0] = 0x72;
1761 else {
1762 open_devip->sense_buff[0] = 0x70;
1763 open_devip->sense_buff[7] = 0xa;
1764 }
1765 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1766 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
1767
1768 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769}
1770
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001771static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001773 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1774 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1775 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
1776 set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
1777 return 0;
1778}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001780static int scsi_debug_slave_configure(struct scsi_device *sdp)
1781{
1782 struct sdebug_dev_info *devip;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09001783
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09001785 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1786 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
1787 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1788 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1789 devip = devInfoReg(sdp);
1790 if (NULL == devip)
1791 return 1; /* no resources, will be marked offline */
1792 sdp->hostdata = devip;
1793 if (sdp->host->cmd_per_lun)
1794 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1795 sdp->host->cmd_per_lun);
1796 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
1797 return 0;
1798}
1799
1800static void scsi_debug_slave_destroy(struct scsi_device *sdp)
1801{
1802 struct sdebug_dev_info *devip =
1803 (struct sdebug_dev_info *)sdp->hostdata;
1804
1805 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1806 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1807 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
1808 if (devip) {
1809 /* make this slot avaliable for re-use */
1810 devip->used = 0;
1811 sdp->hostdata = NULL;
1812 }
1813}
1814
1815/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1816static int stop_queued_cmnd(struct scsi_cmnd *cmnd)
1817{
1818 unsigned long iflags;
1819 int k;
1820 struct sdebug_queued_cmd *sqcp;
1821
1822 spin_lock_irqsave(&queued_arr_lock, iflags);
1823 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1824 sqcp = &queued_arr[k];
1825 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
1826 del_timer_sync(&sqcp->cmnd_timer);
1827 sqcp->in_use = 0;
1828 sqcp->a_cmnd = NULL;
1829 break;
1830 }
1831 }
1832 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1833 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
1834}
1835
1836/* Deletes (stops) timers of all queued commands */
1837static void stop_all_queued(void)
1838{
1839 unsigned long iflags;
1840 int k;
1841 struct sdebug_queued_cmd *sqcp;
1842
1843 spin_lock_irqsave(&queued_arr_lock, iflags);
1844 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1845 sqcp = &queued_arr[k];
1846 if (sqcp->in_use && sqcp->a_cmnd) {
1847 del_timer_sync(&sqcp->cmnd_timer);
1848 sqcp->in_use = 0;
1849 sqcp->a_cmnd = NULL;
1850 }
1851 }
1852 spin_unlock_irqrestore(&queued_arr_lock, iflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853}
1854
1855static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1856{
1857 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1858 printk(KERN_INFO "scsi_debug: abort\n");
1859 ++num_aborts;
1860 stop_queued_cmnd(SCpnt);
1861 return SUCCESS;
1862}
1863
1864static int scsi_debug_biosparam(struct scsi_device *sdev,
1865 struct block_device * bdev, sector_t capacity, int *info)
1866{
1867 int res;
1868 unsigned char *buf;
1869
1870 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1871 printk(KERN_INFO "scsi_debug: biosparam\n");
1872 buf = scsi_bios_ptable(bdev);
1873 if (buf) {
1874 res = scsi_partsize(buf, capacity,
1875 &info[2], &info[0], &info[1]);
1876 kfree(buf);
1877 if (! res)
1878 return res;
1879 }
1880 info[0] = sdebug_heads;
1881 info[1] = sdebug_sectors_per;
1882 info[2] = sdebug_cylinders_per;
1883 return 0;
1884}
1885
1886static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1887{
1888 struct sdebug_dev_info * devip;
1889
1890 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1891 printk(KERN_INFO "scsi_debug: device_reset\n");
1892 ++num_dev_resets;
1893 if (SCpnt) {
1894 devip = devInfoReg(SCpnt->device);
1895 if (devip)
1896 devip->reset = 1;
1897 }
1898 return SUCCESS;
1899}
1900
1901static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1902{
1903 struct sdebug_host_info *sdbg_host;
1904 struct sdebug_dev_info * dev_info;
1905 struct scsi_device * sdp;
1906 struct Scsi_Host * hp;
1907
1908 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1909 printk(KERN_INFO "scsi_debug: bus_reset\n");
1910 ++num_bus_resets;
1911 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09001912 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 if (sdbg_host) {
1914 list_for_each_entry(dev_info,
1915 &sdbg_host->dev_info_list,
1916 dev_list)
1917 dev_info->reset = 1;
1918 }
1919 }
1920 return SUCCESS;
1921}
1922
1923static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1924{
1925 struct sdebug_host_info * sdbg_host;
1926 struct sdebug_dev_info * dev_info;
1927
1928 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1929 printk(KERN_INFO "scsi_debug: host_reset\n");
1930 ++num_host_resets;
1931 spin_lock(&sdebug_host_list_lock);
1932 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1933 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1934 dev_list)
1935 dev_info->reset = 1;
1936 }
1937 spin_unlock(&sdebug_host_list_lock);
1938 stop_all_queued();
1939 return SUCCESS;
1940}
1941
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942/* Initializes timers in queued array */
1943static void __init init_all_queued(void)
1944{
1945 unsigned long iflags;
1946 int k;
1947 struct sdebug_queued_cmd * sqcp;
1948
1949 spin_lock_irqsave(&queued_arr_lock, iflags);
1950 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1951 sqcp = &queued_arr[k];
1952 init_timer(&sqcp->cmnd_timer);
1953 sqcp->in_use = 0;
1954 sqcp->a_cmnd = NULL;
1955 }
1956 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1957}
1958
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001959static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09001960 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961{
1962 struct partition * pp;
1963 int starts[SDEBUG_MAX_PARTS + 2];
1964 int sectors_per_part, num_sectors, k;
1965 int heads_by_sects, start_sec, end_sec;
1966
1967 /* assume partition table already zeroed */
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09001968 if ((scsi_debug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 return;
1970 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
1971 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
1972 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
1973 "partitions to %d\n", SDEBUG_MAX_PARTS);
1974 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001975 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 sectors_per_part = (num_sectors - sdebug_sectors_per)
1977 / scsi_debug_num_parts;
1978 heads_by_sects = sdebug_heads * sdebug_sectors_per;
1979 starts[0] = sdebug_sectors_per;
1980 for (k = 1; k < scsi_debug_num_parts; ++k)
1981 starts[k] = ((k * sectors_per_part) / heads_by_sects)
1982 * heads_by_sects;
1983 starts[scsi_debug_num_parts] = num_sectors;
1984 starts[scsi_debug_num_parts + 1] = 0;
1985
1986 ramp[510] = 0x55; /* magic partition markings */
1987 ramp[511] = 0xAA;
1988 pp = (struct partition *)(ramp + 0x1be);
1989 for (k = 0; starts[k + 1]; ++k, ++pp) {
1990 start_sec = starts[k];
1991 end_sec = starts[k + 1] - 1;
1992 pp->boot_ind = 0;
1993
1994 pp->cyl = start_sec / heads_by_sects;
1995 pp->head = (start_sec - (pp->cyl * heads_by_sects))
1996 / sdebug_sectors_per;
1997 pp->sector = (start_sec % sdebug_sectors_per) + 1;
1998
1999 pp->end_cyl = end_sec / heads_by_sects;
2000 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2001 / sdebug_sectors_per;
2002 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2003
2004 pp->start_sect = start_sec;
2005 pp->nr_sects = end_sec - start_sec + 1;
2006 pp->sys_ind = 0x83; /* plain Linux partition */
2007 }
2008}
2009
2010static int schedule_resp(struct scsi_cmnd * cmnd,
2011 struct sdebug_dev_info * devip,
2012 done_funct_t done, int scsi_result, int delta_jiff)
2013{
2014 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2015 if (scsi_result) {
2016 struct scsi_device * sdp = cmnd->device;
2017
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002018 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2019 "non-zero result=0x%x\n", sdp->host->host_no,
2020 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 }
2022 }
2023 if (cmnd && devip) {
2024 /* simulate autosense by this driver */
2025 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2026 memcpy(cmnd->sense_buffer, devip->sense_buff,
2027 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2028 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2029 }
2030 if (delta_jiff <= 0) {
2031 if (cmnd)
2032 cmnd->result = scsi_result;
2033 if (done)
2034 done(cmnd);
2035 return 0;
2036 } else {
2037 unsigned long iflags;
2038 int k;
2039 struct sdebug_queued_cmd * sqcp = NULL;
2040
2041 spin_lock_irqsave(&queued_arr_lock, iflags);
2042 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2043 sqcp = &queued_arr[k];
2044 if (! sqcp->in_use)
2045 break;
2046 }
2047 if (k >= SCSI_DEBUG_CANQUEUE) {
2048 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2049 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2050 return 1; /* report busy to mid level */
2051 }
2052 sqcp->in_use = 1;
2053 sqcp->a_cmnd = cmnd;
2054 sqcp->scsi_result = scsi_result;
2055 sqcp->done_funct = done;
2056 sqcp->cmnd_timer.function = timer_intr_handler;
2057 sqcp->cmnd_timer.data = k;
2058 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2059 add_timer(&sqcp->cmnd_timer);
2060 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2061 if (cmnd)
2062 cmnd->result = 0;
2063 return 0;
2064 }
2065}
Douglas Gilbert23183912006-09-16 20:30:47 -04002066/* Note: The following macros create attribute files in the
2067 /sys/module/scsi_debug/parameters directory. Unfortunately this
2068 driver is unaware of a change and cannot trigger auxiliary actions
2069 as it can when the corresponding attribute in the
2070 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2071 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002072module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2073module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2074module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2075module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2076module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002077module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002078module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2079module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2080module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2081module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2082module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2083module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2084module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2085module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002086module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2087 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
2089MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2090MODULE_DESCRIPTION("SCSI debug adapter driver");
2091MODULE_LICENSE("GPL");
2092MODULE_VERSION(SCSI_DEBUG_VERSION);
2093
2094MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2095MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002096MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2097MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002098MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002099MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002100MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2101MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002103MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002104MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2106MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002107MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002108MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
2110
2111static char sdebug_info[256];
2112
2113static const char * scsi_debug_info(struct Scsi_Host * shp)
2114{
2115 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2116 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2117 scsi_debug_version_date, scsi_debug_dev_size_mb,
2118 scsi_debug_opts);
2119 return sdebug_info;
2120}
2121
2122/* scsi_debug_proc_info
2123 * Used if the driver currently has no own support for /proc/scsi
2124 */
2125static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2126 int length, int inout)
2127{
2128 int len, pos, begin;
2129 int orig_length;
2130
2131 orig_length = length;
2132
2133 if (inout == 1) {
2134 char arr[16];
2135 int minLen = length > 15 ? 15 : length;
2136
2137 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2138 return -EACCES;
2139 memcpy(arr, buffer, minLen);
2140 arr[minLen] = '\0';
2141 if (1 != sscanf(arr, "%d", &pos))
2142 return -EINVAL;
2143 scsi_debug_opts = pos;
2144 if (scsi_debug_every_nth != 0)
2145 scsi_debug_cmnd_count = 0;
2146 return length;
2147 }
2148 begin = 0;
2149 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2150 "%s [%s]\n"
2151 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2152 "every_nth=%d(curr:%d)\n"
2153 "delay=%d, max_luns=%d, scsi_level=%d\n"
2154 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2155 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2156 "host_resets=%d\n",
2157 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2158 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2159 scsi_debug_cmnd_count, scsi_debug_delay,
2160 scsi_debug_max_luns, scsi_debug_scsi_level,
2161 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2162 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2163 if (pos < offset) {
2164 len = 0;
2165 begin = pos;
2166 }
2167 *start = buffer + (offset - begin); /* Start of wanted data */
2168 len -= (offset - begin);
2169 if (len > length)
2170 len = length;
2171 return len;
2172}
2173
2174static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2175{
2176 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2177}
2178
2179static ssize_t sdebug_delay_store(struct device_driver * ddp,
2180 const char * buf, size_t count)
2181{
2182 int delay;
2183 char work[20];
2184
2185 if (1 == sscanf(buf, "%10s", work)) {
2186 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2187 scsi_debug_delay = delay;
2188 return count;
2189 }
2190 }
2191 return -EINVAL;
2192}
2193DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2194 sdebug_delay_store);
2195
2196static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2197{
2198 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2199}
2200
2201static ssize_t sdebug_opts_store(struct device_driver * ddp,
2202 const char * buf, size_t count)
2203{
2204 int opts;
2205 char work[20];
2206
2207 if (1 == sscanf(buf, "%10s", work)) {
2208 if (0 == strnicmp(work,"0x", 2)) {
2209 if (1 == sscanf(&work[2], "%x", &opts))
2210 goto opts_done;
2211 } else {
2212 if (1 == sscanf(work, "%d", &opts))
2213 goto opts_done;
2214 }
2215 }
2216 return -EINVAL;
2217opts_done:
2218 scsi_debug_opts = opts;
2219 scsi_debug_cmnd_count = 0;
2220 return count;
2221}
2222DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2223 sdebug_opts_store);
2224
2225static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2226{
2227 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2228}
2229static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2230 const char * buf, size_t count)
2231{
2232 int n;
2233
2234 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2235 scsi_debug_ptype = n;
2236 return count;
2237 }
2238 return -EINVAL;
2239}
2240DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2241
2242static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2243{
2244 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2245}
2246static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2247 const char * buf, size_t count)
2248{
2249 int n;
2250
2251 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2252 scsi_debug_dsense = n;
2253 return count;
2254 }
2255 return -EINVAL;
2256}
2257DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2258 sdebug_dsense_store);
2259
Douglas Gilbert23183912006-09-16 20:30:47 -04002260static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2261{
2262 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2263}
2264static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2265 const char * buf, size_t count)
2266{
2267 int n;
2268
2269 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2270 scsi_debug_fake_rw = n;
2271 return count;
2272 }
2273 return -EINVAL;
2274}
2275DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2276 sdebug_fake_rw_store);
2277
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002278static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2279{
2280 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2281}
2282static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2283 const char * buf, size_t count)
2284{
2285 int n;
2286
2287 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2288 scsi_debug_no_lun_0 = n;
2289 return count;
2290 }
2291 return -EINVAL;
2292}
2293DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2294 sdebug_no_lun_0_store);
2295
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2297{
2298 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2299}
2300static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2301 const char * buf, size_t count)
2302{
2303 int n;
2304
2305 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2306 scsi_debug_num_tgts = n;
2307 sdebug_max_tgts_luns();
2308 return count;
2309 }
2310 return -EINVAL;
2311}
2312DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2313 sdebug_num_tgts_store);
2314
2315static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2316{
2317 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2318}
2319DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2320
2321static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2322{
2323 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2324}
2325DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2326
2327static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2328{
2329 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2330}
2331static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2332 const char * buf, size_t count)
2333{
2334 int nth;
2335
2336 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2337 scsi_debug_every_nth = nth;
2338 scsi_debug_cmnd_count = 0;
2339 return count;
2340 }
2341 return -EINVAL;
2342}
2343DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2344 sdebug_every_nth_store);
2345
2346static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2347{
2348 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2349}
2350static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2351 const char * buf, size_t count)
2352{
2353 int n;
2354
2355 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2356 scsi_debug_max_luns = n;
2357 sdebug_max_tgts_luns();
2358 return count;
2359 }
2360 return -EINVAL;
2361}
2362DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2363 sdebug_max_luns_store);
2364
2365static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2366{
2367 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2368}
2369DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2370
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002371static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2372{
2373 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2374}
2375static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2376 const char * buf, size_t count)
2377{
2378 int n;
2379
2380 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2381 scsi_debug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002382
2383 sdebug_capacity = get_sdebug_capacity();
2384
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002385 return count;
2386 }
2387 return -EINVAL;
2388}
2389DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2390 sdebug_virtual_gb_store);
2391
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2393{
2394 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2395}
2396
2397static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2398 const char * buf, size_t count)
2399{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002400 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002402 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 if (delta_hosts > 0) {
2405 do {
2406 sdebug_add_adapter();
2407 } while (--delta_hosts);
2408 } else if (delta_hosts < 0) {
2409 do {
2410 sdebug_remove_adapter();
2411 } while (++delta_hosts);
2412 }
2413 return count;
2414}
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09002415DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 sdebug_add_host_store);
2417
Douglas Gilbert23183912006-09-16 20:30:47 -04002418static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2419 char * buf)
2420{
2421 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2422}
2423static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2424 const char * buf, size_t count)
2425{
2426 int n;
2427
2428 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2429 scsi_debug_vpd_use_hostno = n;
2430 return count;
2431 }
2432 return -EINVAL;
2433}
2434DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2435 sdebug_vpd_use_hostno_store);
2436
2437/* Note: The following function creates attribute files in the
2438 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2439 files (over those found in the /sys/module/scsi_debug/parameters
2440 directory) is that auxiliary actions can be triggered when an attribute
2441 is changed. For example see: sdebug_add_host_store() above.
2442 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002443static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002445 int ret;
2446
2447 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2448 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2449 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2450 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2451 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002452 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002453 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002454 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002455 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002456 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002457 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2458 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2459 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002460 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2461 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002462 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463}
2464
2465static void do_remove_driverfs_files(void)
2466{
Douglas Gilbert23183912006-09-16 20:30:47 -04002467 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2468 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2470 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2471 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002473 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2474 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002476 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2478 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2479 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2480 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2481 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2482}
2483
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09002484static void pseudo_0_release(struct device *dev)
2485{
2486 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2487 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2488}
2489
2490static struct device pseudo_primary = {
2491 .bus_id = "pseudo_0",
2492 .release = pseudo_0_release,
2493};
2494
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495static int __init scsi_debug_init(void)
2496{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002497 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 int host_to_add;
2499 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002500 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
2502 if (scsi_debug_dev_size_mb < 1)
2503 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09002504 sz = (unsigned long)scsi_debug_dev_size_mb * 1048576;
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002505 sdebug_store_sectors = sz / SECT_SIZE;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002506 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507
2508 /* play around with geometry, don't waste too much on track 0 */
2509 sdebug_heads = 8;
2510 sdebug_sectors_per = 32;
2511 if (scsi_debug_dev_size_mb >= 16)
2512 sdebug_heads = 32;
2513 else if (scsi_debug_dev_size_mb >= 256)
2514 sdebug_heads = 64;
2515 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2516 (sdebug_sectors_per * sdebug_heads);
2517 if (sdebug_cylinders_per >= 1024) {
2518 /* other LLDs do this; implies >= 1GB ram disk ... */
2519 sdebug_heads = 255;
2520 sdebug_sectors_per = 63;
2521 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2522 (sdebug_sectors_per * sdebug_heads);
2523 }
2524
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 fake_storep = vmalloc(sz);
2526 if (NULL == fake_storep) {
2527 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2528 return -ENOMEM;
2529 }
2530 memset(fake_storep, 0, sz);
2531 if (scsi_debug_num_parts > 0)
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09002532 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002534 ret = device_register(&pseudo_primary);
2535 if (ret < 0) {
2536 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2537 ret);
2538 goto free_vm;
2539 }
2540 ret = bus_register(&pseudo_lld_bus);
2541 if (ret < 0) {
2542 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2543 ret);
2544 goto dev_unreg;
2545 }
2546 ret = driver_register(&sdebug_driverfs_driver);
2547 if (ret < 0) {
2548 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2549 ret);
2550 goto bus_unreg;
2551 }
2552 ret = do_create_driverfs_files();
2553 if (ret < 0) {
2554 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2555 ret);
2556 goto del_files;
2557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002559 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 host_to_add = scsi_debug_add_host;
2562 scsi_debug_add_host = 0;
2563
2564 for (k = 0; k < host_to_add; k++) {
2565 if (sdebug_add_adapter()) {
2566 printk(KERN_ERR "scsi_debug_init: "
2567 "sdebug_add_adapter failed k=%d\n", k);
2568 break;
2569 }
2570 }
2571
2572 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2573 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2574 scsi_debug_add_host);
2575 }
2576 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002577
2578del_files:
2579 do_remove_driverfs_files();
2580 driver_unregister(&sdebug_driverfs_driver);
2581bus_unreg:
2582 bus_unregister(&pseudo_lld_bus);
2583dev_unreg:
2584 device_unregister(&pseudo_primary);
2585free_vm:
2586 vfree(fake_storep);
2587
2588 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589}
2590
2591static void __exit scsi_debug_exit(void)
2592{
2593 int k = scsi_debug_add_host;
2594
2595 stop_all_queued();
2596 for (; k; k--)
2597 sdebug_remove_adapter();
2598 do_remove_driverfs_files();
2599 driver_unregister(&sdebug_driverfs_driver);
2600 bus_unregister(&pseudo_lld_bus);
2601 device_unregister(&pseudo_primary);
2602
2603 vfree(fake_storep);
2604}
2605
2606device_initcall(scsi_debug_init);
2607module_exit(scsi_debug_exit);
2608
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609static void sdebug_release_adapter(struct device * dev)
2610{
2611 struct sdebug_host_info *sdbg_host;
2612
2613 sdbg_host = to_sdebug_host(dev);
2614 kfree(sdbg_host);
2615}
2616
2617static int sdebug_add_adapter(void)
2618{
2619 int k, devs_per_host;
2620 int error = 0;
2621 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002622 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002624 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 if (NULL == sdbg_host) {
2626 printk(KERN_ERR "%s: out of memory at line %d\n",
2627 __FUNCTION__, __LINE__);
2628 return -ENOMEM;
2629 }
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2632
2633 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2634 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09002635 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
2636 if (!sdbg_devinfo) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 printk(KERN_ERR "%s: out of memory at line %d\n",
2638 __FUNCTION__, __LINE__);
2639 error = -ENOMEM;
2640 goto clean;
2641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 }
2643
2644 spin_lock(&sdebug_host_list_lock);
2645 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2646 spin_unlock(&sdebug_host_list_lock);
2647
2648 sdbg_host->dev.bus = &pseudo_lld_bus;
2649 sdbg_host->dev.parent = &pseudo_primary;
2650 sdbg_host->dev.release = &sdebug_release_adapter;
2651 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2652
2653 error = device_register(&sdbg_host->dev);
2654
2655 if (error)
2656 goto clean;
2657
2658 ++scsi_debug_add_host;
2659 return error;
2660
2661clean:
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002662 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2663 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 list_del(&sdbg_devinfo->dev_list);
2665 kfree(sdbg_devinfo);
2666 }
2667
2668 kfree(sdbg_host);
2669 return error;
2670}
2671
2672static void sdebug_remove_adapter(void)
2673{
2674 struct sdebug_host_info * sdbg_host = NULL;
2675
2676 spin_lock(&sdebug_host_list_lock);
2677 if (!list_empty(&sdebug_host_list)) {
2678 sdbg_host = list_entry(sdebug_host_list.prev,
2679 struct sdebug_host_info, host_list);
2680 list_del(&sdbg_host->host_list);
2681 }
2682 spin_unlock(&sdebug_host_list_lock);
2683
2684 if (!sdbg_host)
2685 return;
2686
2687 device_unregister(&sdbg_host->dev);
2688 --scsi_debug_add_host;
2689}
2690
FUJITA Tomonori639db472008-03-20 11:09:19 +09002691static
2692int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
2693{
2694 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
2695 int len, k;
2696 unsigned int num;
2697 unsigned long long lba;
2698 int errsts = 0;
2699 int target = SCpnt->device->id;
2700 struct sdebug_dev_info *devip = NULL;
2701 int inj_recovered = 0;
2702 int inj_transport = 0;
2703 int delay_override = 0;
2704
2705 scsi_set_resid(SCpnt, 0);
2706 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
2707 printk(KERN_INFO "scsi_debug: cmd ");
2708 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
2709 printk("%02x ", (int)cmd[k]);
2710 printk("\n");
2711 }
2712
2713 if (target == SCpnt->device->host->hostt->this_id) {
2714 printk(KERN_INFO "scsi_debug: initiator's id used as "
2715 "target!\n");
2716 return schedule_resp(SCpnt, NULL, done,
2717 DID_NO_CONNECT << 16, 0);
2718 }
2719
2720 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
2721 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
2722 return schedule_resp(SCpnt, NULL, done,
2723 DID_NO_CONNECT << 16, 0);
2724 devip = devInfoReg(SCpnt->device);
2725 if (NULL == devip)
2726 return schedule_resp(SCpnt, NULL, done,
2727 DID_NO_CONNECT << 16, 0);
2728
2729 if ((scsi_debug_every_nth != 0) &&
2730 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
2731 scsi_debug_cmnd_count = 0;
2732 if (scsi_debug_every_nth < -1)
2733 scsi_debug_every_nth = -1;
2734 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
2735 return 0; /* ignore command causing timeout */
2736 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
2737 inj_recovered = 1; /* to reads and writes below */
2738 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
2739 inj_transport = 1; /* to reads and writes below */
2740 }
2741
2742 if (devip->wlun) {
2743 switch (*cmd) {
2744 case INQUIRY:
2745 case REQUEST_SENSE:
2746 case TEST_UNIT_READY:
2747 case REPORT_LUNS:
2748 break; /* only allowable wlun commands */
2749 default:
2750 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2751 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
2752 "not supported for wlun\n", *cmd);
2753 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2754 INVALID_OPCODE, 0);
2755 errsts = check_condition_result;
2756 return schedule_resp(SCpnt, devip, done, errsts,
2757 0);
2758 }
2759 }
2760
2761 switch (*cmd) {
2762 case INQUIRY: /* mandatory, ignore unit attention */
2763 delay_override = 1;
2764 errsts = resp_inquiry(SCpnt, target, devip);
2765 break;
2766 case REQUEST_SENSE: /* mandatory, ignore unit attention */
2767 delay_override = 1;
2768 errsts = resp_requests(SCpnt, devip);
2769 break;
2770 case REZERO_UNIT: /* actually this is REWIND for SSC */
2771 case START_STOP:
2772 errsts = resp_start_stop(SCpnt, devip);
2773 break;
2774 case ALLOW_MEDIUM_REMOVAL:
2775 errsts = check_readiness(SCpnt, 1, devip);
2776 if (errsts)
2777 break;
2778 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2779 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
2780 cmd[4] ? "inhibited" : "enabled");
2781 break;
2782 case SEND_DIAGNOSTIC: /* mandatory */
2783 errsts = check_readiness(SCpnt, 1, devip);
2784 break;
2785 case TEST_UNIT_READY: /* mandatory */
2786 delay_override = 1;
2787 errsts = check_readiness(SCpnt, 0, devip);
2788 break;
2789 case RESERVE:
2790 errsts = check_readiness(SCpnt, 1, devip);
2791 break;
2792 case RESERVE_10:
2793 errsts = check_readiness(SCpnt, 1, devip);
2794 break;
2795 case RELEASE:
2796 errsts = check_readiness(SCpnt, 1, devip);
2797 break;
2798 case RELEASE_10:
2799 errsts = check_readiness(SCpnt, 1, devip);
2800 break;
2801 case READ_CAPACITY:
2802 errsts = resp_readcap(SCpnt, devip);
2803 break;
2804 case SERVICE_ACTION_IN:
2805 if (SAI_READ_CAPACITY_16 != cmd[1]) {
2806 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2807 INVALID_OPCODE, 0);
2808 errsts = check_condition_result;
2809 break;
2810 }
2811 errsts = resp_readcap16(SCpnt, devip);
2812 break;
2813 case MAINTENANCE_IN:
2814 if (MI_REPORT_TARGET_PGS != cmd[1]) {
2815 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2816 INVALID_OPCODE, 0);
2817 errsts = check_condition_result;
2818 break;
2819 }
2820 errsts = resp_report_tgtpgs(SCpnt, devip);
2821 break;
2822 case READ_16:
2823 case READ_12:
2824 case READ_10:
2825 case READ_6:
2826 errsts = check_readiness(SCpnt, 0, devip);
2827 if (errsts)
2828 break;
2829 if (scsi_debug_fake_rw)
2830 break;
2831 get_data_transfer_info(cmd, &lba, &num);
2832 errsts = resp_read(SCpnt, lba, num, devip);
2833 if (inj_recovered && (0 == errsts)) {
2834 mk_sense_buffer(devip, RECOVERED_ERROR,
2835 THRESHOLD_EXCEEDED, 0);
2836 errsts = check_condition_result;
2837 } else if (inj_transport && (0 == errsts)) {
2838 mk_sense_buffer(devip, ABORTED_COMMAND,
2839 TRANSPORT_PROBLEM, ACK_NAK_TO);
2840 errsts = check_condition_result;
2841 }
2842 break;
2843 case REPORT_LUNS: /* mandatory, ignore unit attention */
2844 delay_override = 1;
2845 errsts = resp_report_luns(SCpnt, devip);
2846 break;
2847 case VERIFY: /* 10 byte SBC-2 command */
2848 errsts = check_readiness(SCpnt, 0, devip);
2849 break;
2850 case WRITE_16:
2851 case WRITE_12:
2852 case WRITE_10:
2853 case WRITE_6:
2854 errsts = check_readiness(SCpnt, 0, devip);
2855 if (errsts)
2856 break;
2857 if (scsi_debug_fake_rw)
2858 break;
2859 get_data_transfer_info(cmd, &lba, &num);
2860 errsts = resp_write(SCpnt, lba, num, devip);
2861 if (inj_recovered && (0 == errsts)) {
2862 mk_sense_buffer(devip, RECOVERED_ERROR,
2863 THRESHOLD_EXCEEDED, 0);
2864 errsts = check_condition_result;
2865 }
2866 break;
2867 case MODE_SENSE:
2868 case MODE_SENSE_10:
2869 errsts = resp_mode_sense(SCpnt, target, devip);
2870 break;
2871 case MODE_SELECT:
2872 errsts = resp_mode_select(SCpnt, 1, devip);
2873 break;
2874 case MODE_SELECT_10:
2875 errsts = resp_mode_select(SCpnt, 0, devip);
2876 break;
2877 case LOG_SENSE:
2878 errsts = resp_log_sense(SCpnt, devip);
2879 break;
2880 case SYNCHRONIZE_CACHE:
2881 delay_override = 1;
2882 errsts = check_readiness(SCpnt, 0, devip);
2883 break;
2884 case WRITE_BUFFER:
2885 errsts = check_readiness(SCpnt, 1, devip);
2886 break;
2887 case XDWRITEREAD_10:
2888 if (!scsi_bidi_cmnd(SCpnt)) {
2889 mk_sense_buffer(devip, ILLEGAL_REQUEST,
2890 INVALID_FIELD_IN_CDB, 0);
2891 errsts = check_condition_result;
2892 break;
2893 }
2894
2895 errsts = check_readiness(SCpnt, 0, devip);
2896 if (errsts)
2897 break;
2898 if (scsi_debug_fake_rw)
2899 break;
2900 get_data_transfer_info(cmd, &lba, &num);
2901 errsts = resp_read(SCpnt, lba, num, devip);
2902 if (errsts)
2903 break;
2904 errsts = resp_write(SCpnt, lba, num, devip);
2905 if (errsts)
2906 break;
2907 errsts = resp_xdwriteread(SCpnt, lba, num, devip);
2908 break;
2909 default:
2910 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2911 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
2912 "supported\n", *cmd);
2913 errsts = check_readiness(SCpnt, 1, devip);
2914 if (errsts)
2915 break; /* Unit attention takes precedence */
2916 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
2917 errsts = check_condition_result;
2918 break;
2919 }
2920 return schedule_resp(SCpnt, devip, done, errsts,
2921 (delay_override ? 0 : scsi_debug_delay));
2922}
2923
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09002924static struct scsi_host_template sdebug_driver_template = {
2925 .proc_info = scsi_debug_proc_info,
2926 .proc_name = sdebug_proc_name,
2927 .name = "SCSI DEBUG",
2928 .info = scsi_debug_info,
2929 .slave_alloc = scsi_debug_slave_alloc,
2930 .slave_configure = scsi_debug_slave_configure,
2931 .slave_destroy = scsi_debug_slave_destroy,
2932 .ioctl = scsi_debug_ioctl,
2933 .queuecommand = scsi_debug_queuecommand,
2934 .eh_abort_handler = scsi_debug_abort,
2935 .eh_bus_reset_handler = scsi_debug_bus_reset,
2936 .eh_device_reset_handler = scsi_debug_device_reset,
2937 .eh_host_reset_handler = scsi_debug_host_reset,
2938 .bios_param = scsi_debug_biosparam,
2939 .can_queue = SCSI_DEBUG_CANQUEUE,
2940 .this_id = 7,
2941 .sg_tablesize = 256,
2942 .cmd_per_lun = 16,
2943 .max_sectors = 0xffff,
2944 .use_clustering = DISABLE_CLUSTERING,
2945 .module = THIS_MODULE,
2946};
2947
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948static int sdebug_driver_probe(struct device * dev)
2949{
2950 int error = 0;
2951 struct sdebug_host_info *sdbg_host;
2952 struct Scsi_Host *hpnt;
2953
2954 sdbg_host = to_sdebug_host(dev);
2955
2956 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2957 if (NULL == hpnt) {
2958 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2959 error = -ENODEV;
2960 return error;
2961 }
2962
2963 sdbg_host->shost = hpnt;
2964 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2965 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2966 hpnt->max_id = scsi_debug_num_tgts + 1;
2967 else
2968 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002969 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
2971 error = scsi_add_host(hpnt, &sdbg_host->dev);
2972 if (error) {
2973 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
2974 error = -ENODEV;
2975 scsi_host_put(hpnt);
2976 } else
2977 scsi_scan_host(hpnt);
2978
2979
2980 return error;
2981}
2982
2983static int sdebug_driver_remove(struct device * dev)
2984{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002986 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
2988 sdbg_host = to_sdebug_host(dev);
2989
2990 if (!sdbg_host) {
2991 printk(KERN_ERR "%s: Unable to locate host info\n",
2992 __FUNCTION__);
2993 return -ENODEV;
2994 }
2995
2996 scsi_remove_host(sdbg_host->shost);
2997
FUJITA Tomonori8b40228f2008-03-20 11:09:18 +09002998 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
2999 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 list_del(&sdbg_devinfo->dev_list);
3001 kfree(sdbg_devinfo);
3002 }
3003
3004 scsi_host_put(sdbg_host->shost);
3005 return 0;
3006}
3007
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003008static int pseudo_lld_bus_match(struct device *dev,
3009 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003011 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003013
3014static struct bus_type pseudo_lld_bus = {
3015 .name = "pseudo",
3016 .match = pseudo_lld_bus_match,
3017 .probe = sdebug_driver_probe,
3018 .remove = sdebug_driver_remove,
3019};