blob: 31f7378c5c46c8d86a58b992496eefd2f47a0bdc [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
43#include <linux/blkdev.h>
44#include "scsi.h"
45#include <scsi/scsi_host.h>
46#include <scsi/scsicam.h>
47
48#include <linux/stat.h>
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include "scsi_logging.h"
51#include "scsi_debug.h"
52
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050053#define SCSI_DEBUG_VERSION "1.81"
54static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050056/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040057#define NO_ADDITIONAL_SENSE 0x0
58#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040060#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#define INVALID_OPCODE 0x20
62#define ADDR_OUT_OF_RANGE 0x21
63#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040064#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define POWERON_RESET 0x29
66#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050067#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define THRESHOLD_EXCEEDED 0x5d
69#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050071/* Additional Sense Code Qualifier (ASCQ) */
72#define ACK_NAK_TO 0x3
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
75
76/* Default values for driver parameters */
77#define DEF_NUM_HOST 1
78#define DEF_NUM_TGTS 1
79#define DEF_MAX_LUNS 1
80/* With these defaults, this driver will make 1 host with 1 target
81 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
82 */
83#define DEF_DELAY 1
84#define DEF_DEV_SIZE_MB 8
85#define DEF_EVERY_NTH 0
86#define DEF_NUM_PARTS 0
87#define DEF_OPTS 0
88#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
89#define DEF_PTYPE 0
90#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define DEF_NO_LUN_0 0
92#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040093#define DEF_FAKE_RW 0
94#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96/* bit mask values for scsi_debug_opts */
97#define SCSI_DEBUG_OPT_NOISE 1
98#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
99#define SCSI_DEBUG_OPT_TIMEOUT 4
100#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500101#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102/* When "every_nth" > 0 then modulo "every_nth" commands:
103 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
104 * - a RECOVERED_ERROR is simulated on successful read and write
105 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500106 * - a TRANSPORT_ERROR is simulated on successful read and write
107 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 *
109 * When "every_nth" < 0 then after "- every_nth" commands:
110 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
111 * - a RECOVERED_ERROR is simulated on successful read and write
112 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500113 * - a TRANSPORT_ERROR is simulated on successful read and write
114 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 * This will continue until some other action occurs (e.g. the user
116 * writing a new value (other than -1 or 1) to every_nth via sysfs).
117 */
118
119/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
120 * sector on read commands: */
121#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
122
123/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
124 * or "peripheral device" addressing (value 0) */
125#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400126#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128static int scsi_debug_add_host = DEF_NUM_HOST;
129static int scsi_debug_delay = DEF_DELAY;
130static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
131static int scsi_debug_every_nth = DEF_EVERY_NTH;
132static int scsi_debug_max_luns = DEF_MAX_LUNS;
133static int scsi_debug_num_parts = DEF_NUM_PARTS;
134static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
135static int scsi_debug_opts = DEF_OPTS;
136static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
137static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
138static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400139static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
140static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400141static int scsi_debug_fake_rw = DEF_FAKE_RW;
142static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144static int scsi_debug_cmnd_count = 0;
145
146#define DEV_READONLY(TGT) (0)
147#define DEV_REMOVEABLE(TGT) (0)
148
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400149static unsigned int sdebug_store_size; /* in bytes */
150static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static sector_t sdebug_capacity; /* in sectors */
152
153/* old BIOS stuff, kernel may get rid of them but some mode sense pages
154 may still need them */
155static int sdebug_heads; /* heads per disk */
156static int sdebug_cylinders_per; /* cylinders per surface */
157static int sdebug_sectors_per; /* sectors per cylinder */
158
159/* default sector size is 512 bytes, 2**9 bytes */
160#define POW2_SECT_SIZE 9
161#define SECT_SIZE (1 << POW2_SECT_SIZE)
162#define SECT_SIZE_PER(TGT) SECT_SIZE
163
164#define SDEBUG_MAX_PARTS 4
165
166#define SDEBUG_SENSE_LEN 32
167
168struct sdebug_dev_info {
169 struct list_head dev_list;
170 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
171 unsigned int channel;
172 unsigned int target;
173 unsigned int lun;
174 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400175 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400177 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 char used;
179};
180
181struct sdebug_host_info {
182 struct list_head host_list;
183 struct Scsi_Host *shost;
184 struct device dev;
185 struct list_head dev_info_list;
186};
187
188#define to_sdebug_host(d) \
189 container_of(d, struct sdebug_host_info, dev)
190
191static LIST_HEAD(sdebug_host_list);
192static DEFINE_SPINLOCK(sdebug_host_list_lock);
193
194typedef void (* done_funct_t) (struct scsi_cmnd *);
195
196struct sdebug_queued_cmd {
197 int in_use;
198 struct timer_list cmnd_timer;
199 done_funct_t done_funct;
200 struct scsi_cmnd * a_cmnd;
201 int scsi_result;
202};
203static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
204
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100205static struct scsi_host_template sdebug_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 .proc_info = scsi_debug_proc_info,
207 .name = "SCSI DEBUG",
208 .info = scsi_debug_info,
209 .slave_alloc = scsi_debug_slave_alloc,
210 .slave_configure = scsi_debug_slave_configure,
211 .slave_destroy = scsi_debug_slave_destroy,
212 .ioctl = scsi_debug_ioctl,
213 .queuecommand = scsi_debug_queuecommand,
214 .eh_abort_handler = scsi_debug_abort,
215 .eh_bus_reset_handler = scsi_debug_bus_reset,
216 .eh_device_reset_handler = scsi_debug_device_reset,
217 .eh_host_reset_handler = scsi_debug_host_reset,
218 .bios_param = scsi_debug_biosparam,
219 .can_queue = SCSI_DEBUG_CANQUEUE,
220 .this_id = 7,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400221 .sg_tablesize = 256,
222 .cmd_per_lun = 16,
223 .max_sectors = 0xffff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 .unchecked_isa_dma = 0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400225 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 .module = THIS_MODULE,
227};
228
229static unsigned char * fake_storep; /* ramdisk storage */
230
231static int num_aborts = 0;
232static int num_dev_resets = 0;
233static int num_bus_resets = 0;
234static int num_host_resets = 0;
235
236static DEFINE_SPINLOCK(queued_arr_lock);
237static DEFINE_RWLOCK(atomic_rw);
238
239static char sdebug_proc_name[] = "scsi_debug";
240
241static int sdebug_driver_probe(struct device *);
242static int sdebug_driver_remove(struct device *);
243static struct bus_type pseudo_lld_bus;
244
245static struct device_driver sdebug_driverfs_driver = {
246 .name = sdebug_proc_name,
247 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248};
249
250static const int check_condition_result =
251 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
252
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400253static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
254 0, 0, 0x2, 0x4b};
255static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
256 0, 0, 0x0, 0x0};
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258/* function declarations */
259static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
260 struct sdebug_dev_info * devip);
261static int resp_requests(struct scsi_cmnd * SCpnt,
262 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400263static int resp_start_stop(struct scsi_cmnd * scp,
264 struct sdebug_dev_info * devip);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200265static int resp_report_tgtpgs(struct scsi_cmnd * scp,
266 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267static int resp_readcap(struct scsi_cmnd * SCpnt,
268 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400269static int resp_readcap16(struct scsi_cmnd * SCpnt,
270 struct sdebug_dev_info * devip);
271static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400273static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
274 struct sdebug_dev_info * devip);
275static int resp_log_sense(struct scsi_cmnd * scp,
276 struct sdebug_dev_info * devip);
277static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
278 unsigned int num, struct sdebug_dev_info * devip);
279static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
280 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281static int resp_report_luns(struct scsi_cmnd * SCpnt,
282 struct sdebug_dev_info * devip);
283static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
284 int arr_len);
285static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
286 int max_arr_len);
287static void timer_intr_handler(unsigned long);
288static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
289static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
290 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400291static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
292 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293static int schedule_resp(struct scsi_cmnd * cmnd,
294 struct sdebug_dev_info * devip,
295 done_funct_t done, int scsi_result, int delta_jiff);
296static void __init sdebug_build_parts(unsigned char * ramp);
297static void __init init_all_queued(void);
298static void stop_all_queued(void);
299static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200300static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
301 int target_dev_id, int dev_id_num,
302 const char * dev_id_str, int dev_id_str_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400303static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Randy Dunlap6ecaff72006-07-11 20:53:22 -0700304static int do_create_driverfs_files(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305static void do_remove_driverfs_files(void);
306
307static int sdebug_add_adapter(void);
308static void sdebug_remove_adapter(void);
309static void sdebug_max_tgts_luns(void);
310
311static struct device pseudo_primary;
312static struct bus_type pseudo_lld_bus;
313
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900314static void get_data_transfer_info(unsigned char *cmd,
315 unsigned long long *lba, unsigned int *num)
316{
317 int i;
318
319 switch (*cmd) {
320 case WRITE_16:
321 case READ_16:
322 for (*lba = 0, i = 0; i < 8; ++i) {
323 if (i > 0)
324 *lba <<= 8;
325 *lba += cmd[2 + i];
326 }
327 *num = cmd[13] + (cmd[12] << 8) +
328 (cmd[11] << 16) + (cmd[10] << 24);
329 break;
330 case WRITE_12:
331 case READ_12:
332 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
333 *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
334 break;
335 case WRITE_10:
336 case READ_10:
337 *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
338 *num = cmd[8] + (cmd[7] << 8);
339 break;
340 case WRITE_6:
341 case READ_6:
342 *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
343 *num = (0 == cmd[4]) ? 256 : cmd[4];
344 break;
345 default:
346 break;
347 }
348}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350static
351int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
352{
353 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900354 int len, k;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400355 unsigned int num;
356 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400358 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 struct sdebug_dev_info * devip = NULL;
360 int inj_recovered = 0;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500361 int inj_transport = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400362 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 if (done == NULL)
365 return 0; /* assume mid level reprocessing command */
366
Boaz Harroshc73961e2007-09-07 06:50:20 +0900367 scsi_set_resid(SCpnt, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
369 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400370 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 printk("%02x ", (int)cmd[k]);
372 printk("\n");
373 }
374 if(target == sdebug_driver_template.this_id) {
375 printk(KERN_INFO "scsi_debug: initiator's id used as "
376 "target!\n");
377 return schedule_resp(SCpnt, NULL, done,
378 DID_NO_CONNECT << 16, 0);
379 }
380
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400381 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
382 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 return schedule_resp(SCpnt, NULL, done,
384 DID_NO_CONNECT << 16, 0);
385 devip = devInfoReg(SCpnt->device);
386 if (NULL == devip)
387 return schedule_resp(SCpnt, NULL, done,
388 DID_NO_CONNECT << 16, 0);
389
390 if ((scsi_debug_every_nth != 0) &&
391 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
392 scsi_debug_cmnd_count = 0;
393 if (scsi_debug_every_nth < -1)
394 scsi_debug_every_nth = -1;
395 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
396 return 0; /* ignore command causing timeout */
397 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
398 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500399 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
400 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 }
402
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400403 if (devip->wlun) {
404 switch (*cmd) {
405 case INQUIRY:
406 case REQUEST_SENSE:
407 case TEST_UNIT_READY:
408 case REPORT_LUNS:
409 break; /* only allowable wlun commands */
410 default:
411 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
412 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
413 "not supported for wlun\n", *cmd);
414 mk_sense_buffer(devip, ILLEGAL_REQUEST,
415 INVALID_OPCODE, 0);
416 errsts = check_condition_result;
417 return schedule_resp(SCpnt, devip, done, errsts,
418 0);
419 }
420 }
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 switch (*cmd) {
423 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 errsts = resp_inquiry(SCpnt, target, devip);
426 break;
427 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400428 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 errsts = resp_requests(SCpnt, devip);
430 break;
431 case REZERO_UNIT: /* actually this is REWIND for SSC */
432 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400433 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 break;
435 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400436 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 break;
438 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
439 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
440 cmd[4] ? "inhibited" : "enabled");
441 break;
442 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400443 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 break;
445 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400446 delay_override = 1;
447 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 break;
449 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400450 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 break;
452 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400453 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 break;
455 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400456 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 break;
458 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400459 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 break;
461 case READ_CAPACITY:
462 errsts = resp_readcap(SCpnt, devip);
463 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400464 case SERVICE_ACTION_IN:
465 if (SAI_READ_CAPACITY_16 != cmd[1]) {
466 mk_sense_buffer(devip, ILLEGAL_REQUEST,
467 INVALID_OPCODE, 0);
468 errsts = check_condition_result;
469 break;
470 }
471 errsts = resp_readcap16(SCpnt, devip);
472 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200473 case MAINTENANCE_IN:
474 if (MI_REPORT_TARGET_PGS != cmd[1]) {
475 mk_sense_buffer(devip, ILLEGAL_REQUEST,
476 INVALID_OPCODE, 0);
477 errsts = check_condition_result;
478 break;
479 }
480 errsts = resp_report_tgtpgs(SCpnt, devip);
481 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 case READ_16:
483 case READ_12:
484 case READ_10:
485 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400486 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400488 if (scsi_debug_fake_rw)
489 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900490 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400491 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 if (inj_recovered && (0 == errsts)) {
493 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400494 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500496 } else if (inj_transport && (0 == errsts)) {
497 mk_sense_buffer(devip, ABORTED_COMMAND,
498 TRANSPORT_PROBLEM, ACK_NAK_TO);
499 errsts = check_condition_result;
500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 break;
502 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400503 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 errsts = resp_report_luns(SCpnt, devip);
505 break;
506 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400507 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 break;
509 case WRITE_16:
510 case WRITE_12:
511 case WRITE_10:
512 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400513 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400515 if (scsi_debug_fake_rw)
516 break;
FUJITA Tomonori3de9f942008-01-23 01:31:59 +0900517 get_data_transfer_info(cmd, &lba, &num);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400518 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 if (inj_recovered && (0 == errsts)) {
520 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400521 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 errsts = check_condition_result;
523 }
524 break;
525 case MODE_SENSE:
526 case MODE_SENSE_10:
527 errsts = resp_mode_sense(SCpnt, target, devip);
528 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400529 case MODE_SELECT:
530 errsts = resp_mode_select(SCpnt, 1, devip);
531 break;
532 case MODE_SELECT_10:
533 errsts = resp_mode_select(SCpnt, 0, devip);
534 break;
535 case LOG_SENSE:
536 errsts = resp_log_sense(SCpnt, devip);
537 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400539 delay_override = 1;
540 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500542 case WRITE_BUFFER:
543 errsts = check_readiness(SCpnt, 1, devip);
544 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 default:
546 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
547 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
548 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400549 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 break; /* Unit attention takes precedence */
551 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
552 errsts = check_condition_result;
553 break;
554 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400555 return schedule_resp(SCpnt, devip, done, errsts,
556 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557}
558
559static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
560{
561 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
562 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
563 }
564 return -EINVAL;
565 /* return -ENOTTY; // correct return but upsets fdisk */
566}
567
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400568static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
569 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 if (devip->reset) {
572 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
573 printk(KERN_INFO "scsi_debug: Reporting Unit "
574 "attention: power on reset\n");
575 devip->reset = 0;
576 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
577 return check_condition_result;
578 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400579 if ((0 == reset_only) && devip->stopped) {
580 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
581 printk(KERN_INFO "scsi_debug: Reporting Not "
582 "ready: initializing command required\n");
583 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
584 0x2);
585 return check_condition_result;
586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 return 0;
588}
589
590/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
591static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
592 int arr_len)
593{
594 int k, req_len, act_len, len, active;
595 void * kaddr;
596 void * kaddr_off;
Jens Axboe852e0342007-07-16 10:19:24 +0200597 struct scatterlist * sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Boaz Harroshc73961e2007-09-07 06:50:20 +0900599 if (0 == scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 return 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900601 if (NULL == scsi_sglist(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 return (DID_ERROR << 16);
603 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
604 (scp->sc_data_direction == DMA_FROM_DEVICE)))
605 return (DID_ERROR << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 active = 1;
Jens Axboe852e0342007-07-16 10:19:24 +0200607 req_len = act_len = 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900608 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 if (active) {
610 kaddr = (unsigned char *)
Jens Axboe45711f12007-10-22 21:19:53 +0200611 kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 if (NULL == kaddr)
613 return (DID_ERROR << 16);
Jens Axboe852e0342007-07-16 10:19:24 +0200614 kaddr_off = (unsigned char *)kaddr + sg->offset;
615 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if ((req_len + len) > arr_len) {
617 active = 0;
618 len = arr_len - req_len;
619 }
620 memcpy(kaddr_off, arr + req_len, len);
621 kunmap_atomic(kaddr, KM_USER0);
622 act_len += len;
623 }
Jens Axboe852e0342007-07-16 10:19:24 +0200624 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
Boaz Harroshc73961e2007-09-07 06:50:20 +0900626 if (scsi_get_resid(scp))
627 scsi_set_resid(scp, scsi_get_resid(scp) - act_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400628 else
Boaz Harroshc73961e2007-09-07 06:50:20 +0900629 scsi_set_resid(scp, req_len - act_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 return 0;
631}
632
633/* Returns number of bytes fetched into 'arr' or -1 if error. */
634static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
635 int max_arr_len)
636{
637 int k, req_len, len, fin;
638 void * kaddr;
639 void * kaddr_off;
Jens Axboe852e0342007-07-16 10:19:24 +0200640 struct scatterlist * sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Boaz Harroshc73961e2007-09-07 06:50:20 +0900642 if (0 == scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 return 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900644 if (NULL == scsi_sglist(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return -1;
646 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
647 (scp->sc_data_direction == DMA_TO_DEVICE)))
648 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200649 req_len = fin = 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900650 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
Jens Axboe45711f12007-10-22 21:19:53 +0200651 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 if (NULL == kaddr)
653 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200654 kaddr_off = (unsigned char *)kaddr + sg->offset;
655 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 if ((req_len + len) > max_arr_len) {
657 len = max_arr_len - req_len;
658 fin = 1;
659 }
660 memcpy(arr + req_len, kaddr_off, len);
661 kunmap_atomic(kaddr, KM_USER0);
662 if (fin)
663 return req_len + len;
Jens Axboe852e0342007-07-16 10:19:24 +0200664 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
666 return req_len;
667}
668
669
670static const char * inq_vendor_id = "Linux ";
671static const char * inq_product_id = "scsi_debug ";
672static const char * inq_product_rev = "0004";
673
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200674static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
675 int target_dev_id, int dev_id_num,
676 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400677 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400679 int num, port_a;
680 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400682 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 /* T10 vendor identifier field format (faked) */
684 arr[0] = 0x2; /* ASCII */
685 arr[1] = 0x1;
686 arr[2] = 0x0;
687 memcpy(&arr[4], inq_vendor_id, 8);
688 memcpy(&arr[12], inq_product_id, 16);
689 memcpy(&arr[28], dev_id_str, dev_id_str_len);
690 num = 8 + 16 + dev_id_str_len;
691 arr[3] = num;
692 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400693 if (dev_id_num >= 0) {
694 /* NAA-5, Logical unit identifier (binary) */
695 arr[num++] = 0x1; /* binary (not necessarily sas) */
696 arr[num++] = 0x3; /* PIV=0, lu, naa */
697 arr[num++] = 0x0;
698 arr[num++] = 0x8;
699 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
700 arr[num++] = 0x33;
701 arr[num++] = 0x33;
702 arr[num++] = 0x30;
703 arr[num++] = (dev_id_num >> 24);
704 arr[num++] = (dev_id_num >> 16) & 0xff;
705 arr[num++] = (dev_id_num >> 8) & 0xff;
706 arr[num++] = dev_id_num & 0xff;
707 /* Target relative port number */
708 arr[num++] = 0x61; /* proto=sas, binary */
709 arr[num++] = 0x94; /* PIV=1, target port, rel port */
710 arr[num++] = 0x0; /* reserved */
711 arr[num++] = 0x4; /* length */
712 arr[num++] = 0x0; /* reserved */
713 arr[num++] = 0x0; /* reserved */
714 arr[num++] = 0x0;
715 arr[num++] = 0x1; /* relative port A */
716 }
717 /* NAA-5, Target port identifier */
718 arr[num++] = 0x61; /* proto=sas, binary */
719 arr[num++] = 0x93; /* piv=1, target port, naa */
720 arr[num++] = 0x0;
721 arr[num++] = 0x8;
722 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
723 arr[num++] = 0x22;
724 arr[num++] = 0x22;
725 arr[num++] = 0x20;
726 arr[num++] = (port_a >> 24);
727 arr[num++] = (port_a >> 16) & 0xff;
728 arr[num++] = (port_a >> 8) & 0xff;
729 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200730 /* NAA-5, Target port group identifier */
731 arr[num++] = 0x61; /* proto=sas, binary */
732 arr[num++] = 0x95; /* piv=1, target port group id */
733 arr[num++] = 0x0;
734 arr[num++] = 0x4;
735 arr[num++] = 0;
736 arr[num++] = 0;
737 arr[num++] = (port_group_id >> 8) & 0xff;
738 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400739 /* NAA-5, Target device identifier */
740 arr[num++] = 0x61; /* proto=sas, binary */
741 arr[num++] = 0xa3; /* piv=1, target device, naa */
742 arr[num++] = 0x0;
743 arr[num++] = 0x8;
744 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
745 arr[num++] = 0x22;
746 arr[num++] = 0x22;
747 arr[num++] = 0x20;
748 arr[num++] = (target_dev_id >> 24);
749 arr[num++] = (target_dev_id >> 16) & 0xff;
750 arr[num++] = (target_dev_id >> 8) & 0xff;
751 arr[num++] = target_dev_id & 0xff;
752 /* SCSI name string: Target device identifier */
753 arr[num++] = 0x63; /* proto=sas, UTF-8 */
754 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
755 arr[num++] = 0x0;
756 arr[num++] = 24;
757 memcpy(arr + num, "naa.52222220", 12);
758 num += 12;
759 snprintf(b, sizeof(b), "%08X", target_dev_id);
760 memcpy(arr + num, b, 8);
761 num += 8;
762 memset(arr + num, 0, 4);
763 num += 4;
764 return num;
765}
766
767
768static unsigned char vpd84_data[] = {
769/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
770 0x22,0x22,0x22,0x0,0xbb,0x1,
771 0x22,0x22,0x22,0x0,0xbb,0x2,
772};
773
774static int inquiry_evpd_84(unsigned char * arr)
775{
776 memcpy(arr, vpd84_data, sizeof(vpd84_data));
777 return sizeof(vpd84_data);
778}
779
780static int inquiry_evpd_85(unsigned char * arr)
781{
782 int num = 0;
783 const char * na1 = "https://www.kernel.org/config";
784 const char * na2 = "http://www.kernel.org/log";
785 int plen, olen;
786
787 arr[num++] = 0x1; /* lu, storage config */
788 arr[num++] = 0x0; /* reserved */
789 arr[num++] = 0x0;
790 olen = strlen(na1);
791 plen = olen + 1;
792 if (plen % 4)
793 plen = ((plen / 4) + 1) * 4;
794 arr[num++] = plen; /* length, null termianted, padded */
795 memcpy(arr + num, na1, olen);
796 memset(arr + num + olen, 0, plen - olen);
797 num += plen;
798
799 arr[num++] = 0x4; /* lu, logging */
800 arr[num++] = 0x0; /* reserved */
801 arr[num++] = 0x0;
802 olen = strlen(na2);
803 plen = olen + 1;
804 if (plen % 4)
805 plen = ((plen / 4) + 1) * 4;
806 arr[num++] = plen; /* length, null terminated, padded */
807 memcpy(arr + num, na2, olen);
808 memset(arr + num + olen, 0, plen - olen);
809 num += plen;
810
811 return num;
812}
813
814/* SCSI ports VPD page */
815static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
816{
817 int num = 0;
818 int port_a, port_b;
819
820 port_a = target_dev_id + 1;
821 port_b = port_a + 1;
822 arr[num++] = 0x0; /* reserved */
823 arr[num++] = 0x0; /* reserved */
824 arr[num++] = 0x0;
825 arr[num++] = 0x1; /* relative port 1 (primary) */
826 memset(arr + num, 0, 6);
827 num += 6;
828 arr[num++] = 0x0;
829 arr[num++] = 12; /* length tp descriptor */
830 /* naa-5 target port identifier (A) */
831 arr[num++] = 0x61; /* proto=sas, binary */
832 arr[num++] = 0x93; /* PIV=1, target port, NAA */
833 arr[num++] = 0x0; /* reserved */
834 arr[num++] = 0x8; /* length */
835 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
836 arr[num++] = 0x22;
837 arr[num++] = 0x22;
838 arr[num++] = 0x20;
839 arr[num++] = (port_a >> 24);
840 arr[num++] = (port_a >> 16) & 0xff;
841 arr[num++] = (port_a >> 8) & 0xff;
842 arr[num++] = port_a & 0xff;
843
844 arr[num++] = 0x0; /* reserved */
845 arr[num++] = 0x0; /* reserved */
846 arr[num++] = 0x0;
847 arr[num++] = 0x2; /* relative port 2 (secondary) */
848 memset(arr + num, 0, 6);
849 num += 6;
850 arr[num++] = 0x0;
851 arr[num++] = 12; /* length tp descriptor */
852 /* naa-5 target port identifier (B) */
853 arr[num++] = 0x61; /* proto=sas, binary */
854 arr[num++] = 0x93; /* PIV=1, target port, NAA */
855 arr[num++] = 0x0; /* reserved */
856 arr[num++] = 0x8; /* length */
857 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
858 arr[num++] = 0x22;
859 arr[num++] = 0x22;
860 arr[num++] = 0x20;
861 arr[num++] = (port_b >> 24);
862 arr[num++] = (port_b >> 16) & 0xff;
863 arr[num++] = (port_b >> 8) & 0xff;
864 arr[num++] = port_b & 0xff;
865
866 return num;
867}
868
869
870static unsigned char vpd89_data[] = {
871/* from 4th byte */ 0,0,0,0,
872'l','i','n','u','x',' ',' ',' ',
873'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
874'1','2','3','4',
8750x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8760xec,0,0,0,
8770x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
8780,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
8790x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
8800x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
8810x53,0x41,
8820x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8830x20,0x20,
8840x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8850x10,0x80,
8860,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8870x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8880x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8890,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8900x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8910x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8920,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
8930,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8940,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8960x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
8970,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
8980xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
8990,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
9000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9020,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9030,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9050,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9060,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9090,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9110,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
912};
913
914static int inquiry_evpd_89(unsigned char * arr)
915{
916 memcpy(arr, vpd89_data, sizeof(vpd89_data));
917 return sizeof(vpd89_data);
918}
919
920
921static unsigned char vpdb0_data[] = {
922 /* from 4th byte */ 0,0,0,4,
923 0,0,0x4,0,
924 0,0,0,64,
925};
926
927static int inquiry_evpd_b0(unsigned char * arr)
928{
929 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
930 if (sdebug_store_sectors > 0x400) {
931 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
932 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
933 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
934 arr[7] = sdebug_store_sectors & 0xff;
935 }
936 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937}
938
939
940#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400941#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943static int resp_inquiry(struct scsi_cmnd * scp, int target,
944 struct sdebug_dev_info * devip)
945{
946 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200947 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200949 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950
951 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500952 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
953 if (! arr)
954 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400955 if (devip->wlun)
956 pq_pdt = 0x1e; /* present, wlun */
957 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
958 pq_pdt = 0x7f; /* not present, no device type */
959 else
960 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 arr[0] = pq_pdt;
962 if (0x2 & cmd[1]) { /* CMDDT bit set */
963 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
964 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200965 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 return check_condition_result;
967 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200968 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400969 char lu_id_str[6];
970 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200972 port_group_id = (((host_no + 1) & 0x7f) << 8) +
973 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400974 if (0 == scsi_debug_vpd_use_hostno)
975 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400976 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
977 (devip->target * 1000) + devip->lun);
978 target_dev_id = ((host_no + 1) * 2000) +
979 (devip->target * 1000) - 3;
980 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400982 arr[1] = cmd[2]; /*sanity */
983 n = 4;
984 arr[n++] = 0x0; /* this page */
985 arr[n++] = 0x80; /* unit serial number */
986 arr[n++] = 0x83; /* device identification */
987 arr[n++] = 0x84; /* software interface ident. */
988 arr[n++] = 0x85; /* management network addresses */
989 arr[n++] = 0x86; /* extended inquiry */
990 arr[n++] = 0x87; /* mode page policy */
991 arr[n++] = 0x88; /* SCSI ports */
992 arr[n++] = 0x89; /* ATA information */
993 arr[n++] = 0xb0; /* Block limits (SBC) */
994 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400996 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400998 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001000 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001001 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1002 target_dev_id, lu_id_num,
1003 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001004 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1005 arr[1] = cmd[2]; /*sanity */
1006 arr[3] = inquiry_evpd_84(&arr[4]);
1007 } else if (0x85 == cmd[2]) { /* Management network addresses */
1008 arr[1] = cmd[2]; /*sanity */
1009 arr[3] = inquiry_evpd_85(&arr[4]);
1010 } else if (0x86 == cmd[2]) { /* extended inquiry */
1011 arr[1] = cmd[2]; /*sanity */
1012 arr[3] = 0x3c; /* number of following entries */
1013 arr[4] = 0x0; /* no protection stuff */
1014 arr[5] = 0x7; /* head of q, ordered + simple q's */
1015 } else if (0x87 == cmd[2]) { /* mode page policy */
1016 arr[1] = cmd[2]; /*sanity */
1017 arr[3] = 0x8; /* number of following entries */
1018 arr[4] = 0x2; /* disconnect-reconnect mp */
1019 arr[6] = 0x80; /* mlus, shared */
1020 arr[8] = 0x18; /* protocol specific lu */
1021 arr[10] = 0x82; /* mlus, per initiator port */
1022 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1023 arr[1] = cmd[2]; /*sanity */
1024 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1025 } else if (0x89 == cmd[2]) { /* ATA information */
1026 arr[1] = cmd[2]; /*sanity */
1027 n = inquiry_evpd_89(&arr[4]);
1028 arr[2] = (n >> 8);
1029 arr[3] = (n & 0xff);
1030 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1031 arr[1] = cmd[2]; /*sanity */
1032 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 } else {
1034 /* Illegal request, invalid field in cdb */
1035 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1036 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001037 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return check_condition_result;
1039 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001040 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001041 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001042 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001043 kfree(arr);
1044 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 }
1046 /* drops through here for a standard inquiry */
1047 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1048 arr[2] = scsi_debug_scsi_level;
1049 arr[3] = 2; /* response_data_format==2 */
1050 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001051 if (0 == scsi_debug_vpd_use_hostno)
1052 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001053 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001055 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 memcpy(&arr[8], inq_vendor_id, 8);
1057 memcpy(&arr[16], inq_product_id, 16);
1058 memcpy(&arr[32], inq_product_rev, 4);
1059 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001060 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1061 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1062 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001064 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001066 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001068 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001069 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001071 kfree(arr);
1072 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073}
1074
1075static int resp_requests(struct scsi_cmnd * scp,
1076 struct sdebug_dev_info * devip)
1077{
1078 unsigned char * sbuff;
1079 unsigned char *cmd = (unsigned char *)scp->cmnd;
1080 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001081 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 int len = 18;
1083
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001084 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001086 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1087 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001089 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1090 if (want_dsense) {
1091 arr[0] = 0x72;
1092 arr[1] = 0x0; /* NO_SENSE in sense_key */
1093 arr[2] = THRESHOLD_EXCEEDED;
1094 arr[3] = 0xff; /* TEST set and MRIE==6 */
1095 } else {
1096 arr[0] = 0x70;
1097 arr[2] = 0x0; /* NO_SENSE in sense_key */
1098 arr[7] = 0xa; /* 18 byte sense buffer */
1099 arr[12] = THRESHOLD_EXCEEDED;
1100 arr[13] = 0xff; /* TEST set and MRIE==6 */
1101 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001102 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001104 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1105 /* DESC bit set and sense_buff in fixed format */
1106 memset(arr, 0, sizeof(arr));
1107 arr[0] = 0x72;
1108 arr[1] = sbuff[2]; /* sense key */
1109 arr[2] = sbuff[12]; /* asc */
1110 arr[3] = sbuff[13]; /* ascq */
1111 len = 8;
1112 }
1113 }
1114 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 return fill_from_dev_buffer(scp, arr, len);
1116}
1117
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001118static int resp_start_stop(struct scsi_cmnd * scp,
1119 struct sdebug_dev_info * devip)
1120{
1121 unsigned char *cmd = (unsigned char *)scp->cmnd;
1122 int power_cond, errsts, start;
1123
1124 if ((errsts = check_readiness(scp, 1, devip)))
1125 return errsts;
1126 power_cond = (cmd[4] & 0xf0) >> 4;
1127 if (power_cond) {
1128 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1129 0);
1130 return check_condition_result;
1131 }
1132 start = cmd[4] & 1;
1133 if (start == devip->stopped)
1134 devip->stopped = !start;
1135 return 0;
1136}
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138#define SDEBUG_READCAP_ARR_SZ 8
1139static int resp_readcap(struct scsi_cmnd * scp,
1140 struct sdebug_dev_info * devip)
1141{
1142 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001143 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 int errsts;
1145
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001146 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001148 /* following just in case virtual_gb changed */
1149 if (scsi_debug_virtual_gb > 0) {
1150 sdebug_capacity = 2048 * 1024;
1151 sdebug_capacity *= scsi_debug_virtual_gb;
1152 } else
1153 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001155 if (sdebug_capacity < 0xffffffff) {
1156 capac = (unsigned int)sdebug_capacity - 1;
1157 arr[0] = (capac >> 24);
1158 arr[1] = (capac >> 16) & 0xff;
1159 arr[2] = (capac >> 8) & 0xff;
1160 arr[3] = capac & 0xff;
1161 } else {
1162 arr[0] = 0xff;
1163 arr[1] = 0xff;
1164 arr[2] = 0xff;
1165 arr[3] = 0xff;
1166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1168 arr[7] = SECT_SIZE_PER(target) & 0xff;
1169 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1170}
1171
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001172#define SDEBUG_READCAP16_ARR_SZ 32
1173static int resp_readcap16(struct scsi_cmnd * scp,
1174 struct sdebug_dev_info * devip)
1175{
1176 unsigned char *cmd = (unsigned char *)scp->cmnd;
1177 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1178 unsigned long long capac;
1179 int errsts, k, alloc_len;
1180
1181 if ((errsts = check_readiness(scp, 1, devip)))
1182 return errsts;
1183 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1184 + cmd[13]);
1185 /* following just in case virtual_gb changed */
1186 if (scsi_debug_virtual_gb > 0) {
1187 sdebug_capacity = 2048 * 1024;
1188 sdebug_capacity *= scsi_debug_virtual_gb;
1189 } else
1190 sdebug_capacity = sdebug_store_sectors;
1191 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1192 capac = sdebug_capacity - 1;
1193 for (k = 0; k < 8; ++k, capac >>= 8)
1194 arr[7 - k] = capac & 0xff;
1195 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1196 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1197 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1198 arr[11] = SECT_SIZE_PER(target) & 0xff;
1199 return fill_from_dev_buffer(scp, arr,
1200 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1201}
1202
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001203#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1204
1205static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1206 struct sdebug_dev_info * devip)
1207{
1208 unsigned char *cmd = (unsigned char *)scp->cmnd;
1209 unsigned char * arr;
1210 int host_no = devip->sdbg_host->shost->host_no;
1211 int n, ret, alen, rlen;
1212 int port_group_a, port_group_b, port_a, port_b;
1213
1214 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1215 + cmd[9]);
1216
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001217 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1218 if (! arr)
1219 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001220 /*
1221 * EVPD page 0x88 states we have two ports, one
1222 * real and a fake port with no device connected.
1223 * So we create two port groups with one port each
1224 * and set the group with port B to unavailable.
1225 */
1226 port_a = 0x1; /* relative port A */
1227 port_b = 0x2; /* relative port B */
1228 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1229 (devip->channel & 0x7f);
1230 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1231 (devip->channel & 0x7f) + 0x80;
1232
1233 /*
1234 * The asymmetric access state is cycled according to the host_id.
1235 */
1236 n = 4;
1237 if (0 == scsi_debug_vpd_use_hostno) {
1238 arr[n++] = host_no % 3; /* Asymm access state */
1239 arr[n++] = 0x0F; /* claim: all states are supported */
1240 } else {
1241 arr[n++] = 0x0; /* Active/Optimized path */
1242 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1243 }
1244 arr[n++] = (port_group_a >> 8) & 0xff;
1245 arr[n++] = port_group_a & 0xff;
1246 arr[n++] = 0; /* Reserved */
1247 arr[n++] = 0; /* Status code */
1248 arr[n++] = 0; /* Vendor unique */
1249 arr[n++] = 0x1; /* One port per group */
1250 arr[n++] = 0; /* Reserved */
1251 arr[n++] = 0; /* Reserved */
1252 arr[n++] = (port_a >> 8) & 0xff;
1253 arr[n++] = port_a & 0xff;
1254 arr[n++] = 3; /* Port unavailable */
1255 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1256 arr[n++] = (port_group_b >> 8) & 0xff;
1257 arr[n++] = port_group_b & 0xff;
1258 arr[n++] = 0; /* Reserved */
1259 arr[n++] = 0; /* Status code */
1260 arr[n++] = 0; /* Vendor unique */
1261 arr[n++] = 0x1; /* One port per group */
1262 arr[n++] = 0; /* Reserved */
1263 arr[n++] = 0; /* Reserved */
1264 arr[n++] = (port_b >> 8) & 0xff;
1265 arr[n++] = port_b & 0xff;
1266
1267 rlen = n - 4;
1268 arr[0] = (rlen >> 24) & 0xff;
1269 arr[1] = (rlen >> 16) & 0xff;
1270 arr[2] = (rlen >> 8) & 0xff;
1271 arr[3] = rlen & 0xff;
1272
1273 /*
1274 * Return the smallest value of either
1275 * - The allocated length
1276 * - The constructed command length
1277 * - The maximum array size
1278 */
1279 rlen = min(alen,n);
1280 ret = fill_from_dev_buffer(scp, arr,
1281 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1282 kfree(arr);
1283 return ret;
1284}
1285
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286/* <<Following mode page info copied from ST318451LW>> */
1287
1288static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1289{ /* Read-Write Error Recovery page for mode_sense */
1290 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1291 5, 0, 0xff, 0xff};
1292
1293 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1294 if (1 == pcontrol)
1295 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1296 return sizeof(err_recov_pg);
1297}
1298
1299static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1300{ /* Disconnect-Reconnect page for mode_sense */
1301 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1302 0, 0, 0, 0, 0, 0, 0, 0};
1303
1304 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1305 if (1 == pcontrol)
1306 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1307 return sizeof(disconnect_pg);
1308}
1309
1310static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1311{ /* Format device page for mode_sense */
1312 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1313 0, 0, 0, 0, 0, 0, 0, 0,
1314 0, 0, 0, 0, 0x40, 0, 0, 0};
1315
1316 memcpy(p, format_pg, sizeof(format_pg));
1317 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1318 p[11] = sdebug_sectors_per & 0xff;
1319 p[12] = (SECT_SIZE >> 8) & 0xff;
1320 p[13] = SECT_SIZE & 0xff;
1321 if (DEV_REMOVEABLE(target))
1322 p[20] |= 0x20; /* should agree with INQUIRY */
1323 if (1 == pcontrol)
1324 memset(p + 2, 0, sizeof(format_pg) - 2);
1325 return sizeof(format_pg);
1326}
1327
1328static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1329{ /* Caching page for mode_sense */
1330 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1331 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1332
1333 memcpy(p, caching_pg, sizeof(caching_pg));
1334 if (1 == pcontrol)
1335 memset(p + 2, 0, sizeof(caching_pg) - 2);
1336 return sizeof(caching_pg);
1337}
1338
1339static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1340{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001341 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1342 0, 0, 0, 0};
1343 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 0, 0, 0x2, 0x4b};
1345
1346 if (scsi_debug_dsense)
1347 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001348 else
1349 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1351 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001352 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1353 else if (2 == pcontrol)
1354 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 return sizeof(ctrl_m_pg);
1356}
1357
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001358
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1360{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001361 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1362 0, 0, 0x0, 0x0};
1363 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1364 0, 0, 0x0, 0x0};
1365
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1367 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001368 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1369 else if (2 == pcontrol)
1370 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 return sizeof(iec_m_pg);
1372}
1373
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001374static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1375{ /* SAS SSP mode page - short format for mode_sense */
1376 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1377 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1378
1379 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1380 if (1 == pcontrol)
1381 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1382 return sizeof(sas_sf_m_pg);
1383}
1384
1385
1386static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1387 int target_dev_id)
1388{ /* SAS phy control and discover mode page for mode_sense */
1389 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1390 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1391 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1392 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1393 0x2, 0, 0, 0, 0, 0, 0, 0,
1394 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1395 0, 0, 0, 0, 0, 0, 0, 0,
1396 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1397 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1398 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1399 0x3, 0, 0, 0, 0, 0, 0, 0,
1400 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1401 0, 0, 0, 0, 0, 0, 0, 0,
1402 };
1403 int port_a, port_b;
1404
1405 port_a = target_dev_id + 1;
1406 port_b = port_a + 1;
1407 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1408 p[20] = (port_a >> 24);
1409 p[21] = (port_a >> 16) & 0xff;
1410 p[22] = (port_a >> 8) & 0xff;
1411 p[23] = port_a & 0xff;
1412 p[48 + 20] = (port_b >> 24);
1413 p[48 + 21] = (port_b >> 16) & 0xff;
1414 p[48 + 22] = (port_b >> 8) & 0xff;
1415 p[48 + 23] = port_b & 0xff;
1416 if (1 == pcontrol)
1417 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1418 return sizeof(sas_pcd_m_pg);
1419}
1420
1421static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1422{ /* SAS SSP shared protocol specific port mode subpage */
1423 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1424 0, 0, 0, 0, 0, 0, 0, 0,
1425 };
1426
1427 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1428 if (1 == pcontrol)
1429 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1430 return sizeof(sas_sha_m_pg);
1431}
1432
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433#define SDEBUG_MAX_MSENSE_SZ 256
1434
1435static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1436 struct sdebug_dev_info * devip)
1437{
Douglas Gilbert23183912006-09-16 20:30:47 -04001438 unsigned char dbd, llbaa;
1439 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001441 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 unsigned char * ap;
1443 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1444 unsigned char *cmd = (unsigned char *)scp->cmnd;
1445
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001446 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001448 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 pcontrol = (cmd[2] & 0xc0) >> 6;
1450 pcode = cmd[2] & 0x3f;
1451 subpcode = cmd[3];
1452 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001453 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1454 if ((0 == scsi_debug_ptype) && (0 == dbd))
1455 bd_len = llbaa ? 16 : 8;
1456 else
1457 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1459 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1460 if (0x3 == pcontrol) { /* Saving values not supported */
1461 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1462 0);
1463 return check_condition_result;
1464 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001465 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1466 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001467 /* set DPOFUA bit for disks */
1468 if (0 == scsi_debug_ptype)
1469 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1470 else
1471 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 if (msense_6) {
1473 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001474 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 offset = 4;
1476 } else {
1477 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001478 if (16 == bd_len)
1479 arr[4] = 0x1; /* set LONGLBA bit */
1480 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 offset = 8;
1482 }
1483 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001484 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1485 if (scsi_debug_virtual_gb > 0) {
1486 sdebug_capacity = 2048 * 1024;
1487 sdebug_capacity *= scsi_debug_virtual_gb;
1488 } else
1489 sdebug_capacity = sdebug_store_sectors;
1490 }
1491 if (8 == bd_len) {
1492 if (sdebug_capacity > 0xfffffffe) {
1493 ap[0] = 0xff;
1494 ap[1] = 0xff;
1495 ap[2] = 0xff;
1496 ap[3] = 0xff;
1497 } else {
1498 ap[0] = (sdebug_capacity >> 24) & 0xff;
1499 ap[1] = (sdebug_capacity >> 16) & 0xff;
1500 ap[2] = (sdebug_capacity >> 8) & 0xff;
1501 ap[3] = sdebug_capacity & 0xff;
1502 }
1503 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1504 ap[7] = SECT_SIZE_PER(target) & 0xff;
1505 offset += bd_len;
1506 ap = arr + offset;
1507 } else if (16 == bd_len) {
1508 unsigned long long capac = sdebug_capacity;
1509
1510 for (k = 0; k < 8; ++k, capac >>= 8)
1511 ap[7 - k] = capac & 0xff;
1512 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1513 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1514 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1515 ap[15] = SECT_SIZE_PER(target) & 0xff;
1516 offset += bd_len;
1517 ap = arr + offset;
1518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001520 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1521 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1523 0);
1524 return check_condition_result;
1525 }
1526 switch (pcode) {
1527 case 0x1: /* Read-Write error recovery page, direct access */
1528 len = resp_err_recov_pg(ap, pcontrol, target);
1529 offset += len;
1530 break;
1531 case 0x2: /* Disconnect-Reconnect page, all devices */
1532 len = resp_disconnect_pg(ap, pcontrol, target);
1533 offset += len;
1534 break;
1535 case 0x3: /* Format device page, direct access */
1536 len = resp_format_pg(ap, pcontrol, target);
1537 offset += len;
1538 break;
1539 case 0x8: /* Caching page, direct access */
1540 len = resp_caching_pg(ap, pcontrol, target);
1541 offset += len;
1542 break;
1543 case 0xa: /* Control Mode page, all devices */
1544 len = resp_ctrl_m_pg(ap, pcontrol, target);
1545 offset += len;
1546 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001547 case 0x19: /* if spc==1 then sas phy, control+discover */
1548 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1549 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1550 INVALID_FIELD_IN_CDB, 0);
1551 return check_condition_result;
1552 }
1553 len = 0;
1554 if ((0x0 == subpcode) || (0xff == subpcode))
1555 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1556 if ((0x1 == subpcode) || (0xff == subpcode))
1557 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1558 target_dev_id);
1559 if ((0x2 == subpcode) || (0xff == subpcode))
1560 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1561 offset += len;
1562 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 case 0x1c: /* Informational Exceptions Mode page, all devices */
1564 len = resp_iec_m_pg(ap, pcontrol, target);
1565 offset += len;
1566 break;
1567 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001568 if ((0 == subpcode) || (0xff == subpcode)) {
1569 len = resp_err_recov_pg(ap, pcontrol, target);
1570 len += resp_disconnect_pg(ap + len, pcontrol, target);
1571 len += resp_format_pg(ap + len, pcontrol, target);
1572 len += resp_caching_pg(ap + len, pcontrol, target);
1573 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1574 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1575 if (0xff == subpcode) {
1576 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1577 target, target_dev_id);
1578 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1579 }
1580 len += resp_iec_m_pg(ap + len, pcontrol, target);
1581 } else {
1582 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1583 INVALID_FIELD_IN_CDB, 0);
1584 return check_condition_result;
1585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 offset += len;
1587 break;
1588 default:
1589 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1590 0);
1591 return check_condition_result;
1592 }
1593 if (msense_6)
1594 arr[0] = offset - 1;
1595 else {
1596 arr[0] = ((offset - 2) >> 8) & 0xff;
1597 arr[1] = (offset - 2) & 0xff;
1598 }
1599 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1600}
1601
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001602#define SDEBUG_MAX_MSELECT_SZ 512
1603
1604static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1605 struct sdebug_dev_info * devip)
1606{
1607 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1608 int param_len, res, errsts, mpage;
1609 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1610 unsigned char *cmd = (unsigned char *)scp->cmnd;
1611
1612 if ((errsts = check_readiness(scp, 1, devip)))
1613 return errsts;
1614 memset(arr, 0, sizeof(arr));
1615 pf = cmd[1] & 0x10;
1616 sp = cmd[1] & 0x1;
1617 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1618 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1619 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1620 INVALID_FIELD_IN_CDB, 0);
1621 return check_condition_result;
1622 }
1623 res = fetch_to_dev_buffer(scp, arr, param_len);
1624 if (-1 == res)
1625 return (DID_ERROR << 16);
1626 else if ((res < param_len) &&
1627 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1628 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1629 " IO sent=%d bytes\n", param_len, res);
1630 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1631 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001632 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001633 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1634 INVALID_FIELD_IN_PARAM_LIST, 0);
1635 return check_condition_result;
1636 }
1637 off = bd_len + (mselect6 ? 4 : 8);
1638 mpage = arr[off] & 0x3f;
1639 ps = !!(arr[off] & 0x80);
1640 if (ps) {
1641 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1642 INVALID_FIELD_IN_PARAM_LIST, 0);
1643 return check_condition_result;
1644 }
1645 spf = !!(arr[off] & 0x40);
1646 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1647 (arr[off + 1] + 2);
1648 if ((pg_len + off) > param_len) {
1649 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1650 PARAMETER_LIST_LENGTH_ERR, 0);
1651 return check_condition_result;
1652 }
1653 switch (mpage) {
1654 case 0xa: /* Control Mode page */
1655 if (ctrl_m_pg[1] == arr[off + 1]) {
1656 memcpy(ctrl_m_pg + 2, arr + off + 2,
1657 sizeof(ctrl_m_pg) - 2);
1658 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1659 return 0;
1660 }
1661 break;
1662 case 0x1c: /* Informational Exceptions Mode page */
1663 if (iec_m_pg[1] == arr[off + 1]) {
1664 memcpy(iec_m_pg + 2, arr + off + 2,
1665 sizeof(iec_m_pg) - 2);
1666 return 0;
1667 }
1668 break;
1669 default:
1670 break;
1671 }
1672 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1673 INVALID_FIELD_IN_PARAM_LIST, 0);
1674 return check_condition_result;
1675}
1676
1677static int resp_temp_l_pg(unsigned char * arr)
1678{
1679 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1680 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1681 };
1682
1683 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1684 return sizeof(temp_l_pg);
1685}
1686
1687static int resp_ie_l_pg(unsigned char * arr)
1688{
1689 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1690 };
1691
1692 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1693 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1694 arr[4] = THRESHOLD_EXCEEDED;
1695 arr[5] = 0xff;
1696 }
1697 return sizeof(ie_l_pg);
1698}
1699
1700#define SDEBUG_MAX_LSENSE_SZ 512
1701
1702static int resp_log_sense(struct scsi_cmnd * scp,
1703 struct sdebug_dev_info * devip)
1704{
Douglas Gilbert23183912006-09-16 20:30:47 -04001705 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001706 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1707 unsigned char *cmd = (unsigned char *)scp->cmnd;
1708
1709 if ((errsts = check_readiness(scp, 1, devip)))
1710 return errsts;
1711 memset(arr, 0, sizeof(arr));
1712 ppc = cmd[1] & 0x2;
1713 sp = cmd[1] & 0x1;
1714 if (ppc || sp) {
1715 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1716 INVALID_FIELD_IN_CDB, 0);
1717 return check_condition_result;
1718 }
1719 pcontrol = (cmd[2] & 0xc0) >> 6;
1720 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001721 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001722 alloc_len = (cmd[7] << 8) + cmd[8];
1723 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001724 if (0 == subpcode) {
1725 switch (pcode) {
1726 case 0x0: /* Supported log pages log page */
1727 n = 4;
1728 arr[n++] = 0x0; /* this page */
1729 arr[n++] = 0xd; /* Temperature */
1730 arr[n++] = 0x2f; /* Informational exceptions */
1731 arr[3] = n - 4;
1732 break;
1733 case 0xd: /* Temperature log page */
1734 arr[3] = resp_temp_l_pg(arr + 4);
1735 break;
1736 case 0x2f: /* Informational exceptions log page */
1737 arr[3] = resp_ie_l_pg(arr + 4);
1738 break;
1739 default:
1740 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1741 INVALID_FIELD_IN_CDB, 0);
1742 return check_condition_result;
1743 }
1744 } else if (0xff == subpcode) {
1745 arr[0] |= 0x40;
1746 arr[1] = subpcode;
1747 switch (pcode) {
1748 case 0x0: /* Supported log pages and subpages log page */
1749 n = 4;
1750 arr[n++] = 0x0;
1751 arr[n++] = 0x0; /* 0,0 page */
1752 arr[n++] = 0x0;
1753 arr[n++] = 0xff; /* this page */
1754 arr[n++] = 0xd;
1755 arr[n++] = 0x0; /* Temperature */
1756 arr[n++] = 0x2f;
1757 arr[n++] = 0x0; /* Informational exceptions */
1758 arr[3] = n - 4;
1759 break;
1760 case 0xd: /* Temperature subpages */
1761 n = 4;
1762 arr[n++] = 0xd;
1763 arr[n++] = 0x0; /* Temperature */
1764 arr[3] = n - 4;
1765 break;
1766 case 0x2f: /* Informational exceptions subpages */
1767 n = 4;
1768 arr[n++] = 0x2f;
1769 arr[n++] = 0x0; /* Informational exceptions */
1770 arr[3] = n - 4;
1771 break;
1772 default:
1773 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1774 INVALID_FIELD_IN_CDB, 0);
1775 return check_condition_result;
1776 }
1777 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001778 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1779 INVALID_FIELD_IN_CDB, 0);
1780 return check_condition_result;
1781 }
1782 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1783 return fill_from_dev_buffer(scp, arr,
1784 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1785}
1786
1787static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1788 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789{
1790 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001791 unsigned int block, from_bottom;
1792 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 int ret;
1794
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001795 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1797 0);
1798 return check_condition_result;
1799 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001800 /* transfer length excessive (tie in to block limits VPD page) */
1801 if (num > sdebug_store_sectors) {
1802 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1803 0);
1804 return check_condition_result;
1805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001807 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1808 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1809 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1811 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001812 /* set info field and valid bit for fixed descriptor */
1813 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1814 devip->sense_buff[0] |= 0x80; /* Valid bit */
1815 ret = OPT_MEDIUM_ERR_ADDR;
1816 devip->sense_buff[3] = (ret >> 24) & 0xff;
1817 devip->sense_buff[4] = (ret >> 16) & 0xff;
1818 devip->sense_buff[5] = (ret >> 8) & 0xff;
1819 devip->sense_buff[6] = ret & 0xff;
1820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 return check_condition_result;
1822 }
1823 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001824 if ((lba + num) <= sdebug_store_sectors)
1825 ret = fill_from_dev_buffer(SCpnt,
1826 fake_storep + (lba * SECT_SIZE),
1827 num * SECT_SIZE);
1828 else {
1829 /* modulo when one arg is 64 bits needs do_div() */
1830 u = lba;
1831 block = do_div(u, sdebug_store_sectors);
1832 from_bottom = 0;
1833 if ((block + num) > sdebug_store_sectors)
1834 from_bottom = (block + num) - sdebug_store_sectors;
1835 ret = fill_from_dev_buffer(SCpnt,
1836 fake_storep + (block * SECT_SIZE),
1837 (num - from_bottom) * SECT_SIZE);
1838 if ((0 == ret) && (from_bottom > 0))
1839 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1840 from_bottom * SECT_SIZE);
1841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 read_unlock_irqrestore(&atomic_rw, iflags);
1843 return ret;
1844}
1845
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001846static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1847 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848{
1849 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001850 unsigned int block, to_bottom;
1851 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 int res;
1853
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001854 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1856 0);
1857 return check_condition_result;
1858 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001859 /* transfer length excessive (tie in to block limits VPD page) */
1860 if (num > sdebug_store_sectors) {
1861 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1862 0);
1863 return check_condition_result;
1864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001867 if ((lba + num) <= sdebug_store_sectors)
1868 res = fetch_to_dev_buffer(SCpnt,
1869 fake_storep + (lba * SECT_SIZE),
1870 num * SECT_SIZE);
1871 else {
1872 /* modulo when one arg is 64 bits needs do_div() */
1873 u = lba;
1874 block = do_div(u, sdebug_store_sectors);
1875 to_bottom = 0;
1876 if ((block + num) > sdebug_store_sectors)
1877 to_bottom = (block + num) - sdebug_store_sectors;
1878 res = fetch_to_dev_buffer(SCpnt,
1879 fake_storep + (block * SECT_SIZE),
1880 (num - to_bottom) * SECT_SIZE);
1881 if ((0 == res) && (to_bottom > 0))
1882 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1883 to_bottom * SECT_SIZE);
1884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 write_unlock_irqrestore(&atomic_rw, iflags);
1886 if (-1 == res)
1887 return (DID_ERROR << 16);
1888 else if ((res < (num * SECT_SIZE)) &&
1889 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001890 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1892 return 0;
1893}
1894
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001895#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897static int resp_report_luns(struct scsi_cmnd * scp,
1898 struct sdebug_dev_info * devip)
1899{
1900 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001901 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 unsigned char *cmd = (unsigned char *)scp->cmnd;
1903 int select_report = (int)cmd[2];
1904 struct scsi_lun *one_lun;
1905 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001906 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
1908 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001909 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1911 0);
1912 return check_condition_result;
1913 }
1914 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1915 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1916 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001917 if (1 == select_report)
1918 lun_cnt = 0;
1919 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1920 --lun_cnt;
1921 wlun = (select_report > 0) ? 1 : 0;
1922 num = lun_cnt + wlun;
1923 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1924 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1925 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1926 sizeof(struct scsi_lun)), num);
1927 if (n < num) {
1928 wlun = 0;
1929 lun_cnt = n;
1930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001932 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1933 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1934 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1935 i++, lun++) {
1936 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 if (upper)
1938 one_lun[i].scsi_lun[0] =
1939 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001940 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001942 if (wlun) {
1943 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1944 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1945 i++;
1946 }
1947 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 return fill_from_dev_buffer(scp, arr,
1949 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1950}
1951
1952/* When timer goes off this function is called. */
1953static void timer_intr_handler(unsigned long indx)
1954{
1955 struct sdebug_queued_cmd * sqcp;
1956 unsigned long iflags;
1957
1958 if (indx >= SCSI_DEBUG_CANQUEUE) {
1959 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1960 "large\n");
1961 return;
1962 }
1963 spin_lock_irqsave(&queued_arr_lock, iflags);
1964 sqcp = &queued_arr[(int)indx];
1965 if (! sqcp->in_use) {
1966 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1967 "interrupt\n");
1968 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1969 return;
1970 }
1971 sqcp->in_use = 0;
1972 if (sqcp->done_funct) {
1973 sqcp->a_cmnd->result = sqcp->scsi_result;
1974 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1975 }
1976 sqcp->done_funct = NULL;
1977 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1978}
1979
1980static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1981{
1982 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001983 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1984 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 return 0;
1986}
1987
1988static int scsi_debug_slave_configure(struct scsi_device * sdp)
1989{
1990 struct sdebug_dev_info * devip;
1991
1992 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001993 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1994 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1996 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1997 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001998 if (NULL == devip)
1999 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 sdp->hostdata = devip;
2001 if (sdp->host->cmd_per_lun)
2002 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2003 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002004 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 return 0;
2006}
2007
2008static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2009{
2010 struct sdebug_dev_info * devip =
2011 (struct sdebug_dev_info *)sdp->hostdata;
2012
2013 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002014 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2015 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 if (devip) {
2017 /* make this slot avaliable for re-use */
2018 devip->used = 0;
2019 sdp->hostdata = NULL;
2020 }
2021}
2022
2023static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2024{
2025 struct sdebug_host_info * sdbg_host;
2026 struct sdebug_dev_info * open_devip = NULL;
2027 struct sdebug_dev_info * devip =
2028 (struct sdebug_dev_info *)sdev->hostdata;
2029
2030 if (devip)
2031 return devip;
2032 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
2033 if(! sdbg_host) {
2034 printk(KERN_ERR "Host info NULL\n");
2035 return NULL;
2036 }
2037 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2038 if ((devip->used) && (devip->channel == sdev->channel) &&
2039 (devip->target == sdev->id) &&
2040 (devip->lun == sdev->lun))
2041 return devip;
2042 else {
2043 if ((!devip->used) && (!open_devip))
2044 open_devip = devip;
2045 }
2046 }
2047 if (NULL == open_devip) { /* try and make a new one */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002048 open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 if (NULL == open_devip) {
2050 printk(KERN_ERR "%s: out of memory at line %d\n",
2051 __FUNCTION__, __LINE__);
2052 return NULL;
2053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 open_devip->sdbg_host = sdbg_host;
2055 list_add_tail(&open_devip->dev_list,
2056 &sdbg_host->dev_info_list);
2057 }
2058 if (open_devip) {
2059 open_devip->channel = sdev->channel;
2060 open_devip->target = sdev->id;
2061 open_devip->lun = sdev->lun;
2062 open_devip->sdbg_host = sdbg_host;
2063 open_devip->reset = 1;
2064 open_devip->used = 1;
2065 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2066 if (scsi_debug_dsense)
2067 open_devip->sense_buff[0] = 0x72;
2068 else {
2069 open_devip->sense_buff[0] = 0x70;
2070 open_devip->sense_buff[7] = 0xa;
2071 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002072 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2073 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 return open_devip;
2075 }
2076 return NULL;
2077}
2078
2079static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2080 int asc, int asq)
2081{
2082 unsigned char * sbuff;
2083
2084 sbuff = devip->sense_buff;
2085 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2086 if (scsi_debug_dsense) {
2087 sbuff[0] = 0x72; /* descriptor, current */
2088 sbuff[1] = key;
2089 sbuff[2] = asc;
2090 sbuff[3] = asq;
2091 } else {
2092 sbuff[0] = 0x70; /* fixed, current */
2093 sbuff[2] = key;
2094 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2095 sbuff[12] = asc;
2096 sbuff[13] = asq;
2097 }
2098 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2099 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2100 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2101}
2102
2103static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2104{
2105 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2106 printk(KERN_INFO "scsi_debug: abort\n");
2107 ++num_aborts;
2108 stop_queued_cmnd(SCpnt);
2109 return SUCCESS;
2110}
2111
2112static int scsi_debug_biosparam(struct scsi_device *sdev,
2113 struct block_device * bdev, sector_t capacity, int *info)
2114{
2115 int res;
2116 unsigned char *buf;
2117
2118 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2119 printk(KERN_INFO "scsi_debug: biosparam\n");
2120 buf = scsi_bios_ptable(bdev);
2121 if (buf) {
2122 res = scsi_partsize(buf, capacity,
2123 &info[2], &info[0], &info[1]);
2124 kfree(buf);
2125 if (! res)
2126 return res;
2127 }
2128 info[0] = sdebug_heads;
2129 info[1] = sdebug_sectors_per;
2130 info[2] = sdebug_cylinders_per;
2131 return 0;
2132}
2133
2134static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2135{
2136 struct sdebug_dev_info * devip;
2137
2138 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2139 printk(KERN_INFO "scsi_debug: device_reset\n");
2140 ++num_dev_resets;
2141 if (SCpnt) {
2142 devip = devInfoReg(SCpnt->device);
2143 if (devip)
2144 devip->reset = 1;
2145 }
2146 return SUCCESS;
2147}
2148
2149static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2150{
2151 struct sdebug_host_info *sdbg_host;
2152 struct sdebug_dev_info * dev_info;
2153 struct scsi_device * sdp;
2154 struct Scsi_Host * hp;
2155
2156 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2157 printk(KERN_INFO "scsi_debug: bus_reset\n");
2158 ++num_bus_resets;
2159 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2160 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
2161 if (sdbg_host) {
2162 list_for_each_entry(dev_info,
2163 &sdbg_host->dev_info_list,
2164 dev_list)
2165 dev_info->reset = 1;
2166 }
2167 }
2168 return SUCCESS;
2169}
2170
2171static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2172{
2173 struct sdebug_host_info * sdbg_host;
2174 struct sdebug_dev_info * dev_info;
2175
2176 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2177 printk(KERN_INFO "scsi_debug: host_reset\n");
2178 ++num_host_resets;
2179 spin_lock(&sdebug_host_list_lock);
2180 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2181 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2182 dev_list)
2183 dev_info->reset = 1;
2184 }
2185 spin_unlock(&sdebug_host_list_lock);
2186 stop_all_queued();
2187 return SUCCESS;
2188}
2189
2190/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2191static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2192{
2193 unsigned long iflags;
2194 int k;
2195 struct sdebug_queued_cmd * sqcp;
2196
2197 spin_lock_irqsave(&queued_arr_lock, iflags);
2198 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2199 sqcp = &queued_arr[k];
2200 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2201 del_timer_sync(&sqcp->cmnd_timer);
2202 sqcp->in_use = 0;
2203 sqcp->a_cmnd = NULL;
2204 break;
2205 }
2206 }
2207 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2208 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2209}
2210
2211/* Deletes (stops) timers of all queued commands */
2212static void stop_all_queued(void)
2213{
2214 unsigned long iflags;
2215 int k;
2216 struct sdebug_queued_cmd * sqcp;
2217
2218 spin_lock_irqsave(&queued_arr_lock, iflags);
2219 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2220 sqcp = &queued_arr[k];
2221 if (sqcp->in_use && sqcp->a_cmnd) {
2222 del_timer_sync(&sqcp->cmnd_timer);
2223 sqcp->in_use = 0;
2224 sqcp->a_cmnd = NULL;
2225 }
2226 }
2227 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2228}
2229
2230/* Initializes timers in queued array */
2231static void __init init_all_queued(void)
2232{
2233 unsigned long iflags;
2234 int k;
2235 struct sdebug_queued_cmd * sqcp;
2236
2237 spin_lock_irqsave(&queued_arr_lock, iflags);
2238 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2239 sqcp = &queued_arr[k];
2240 init_timer(&sqcp->cmnd_timer);
2241 sqcp->in_use = 0;
2242 sqcp->a_cmnd = NULL;
2243 }
2244 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2245}
2246
2247static void __init sdebug_build_parts(unsigned char * ramp)
2248{
2249 struct partition * pp;
2250 int starts[SDEBUG_MAX_PARTS + 2];
2251 int sectors_per_part, num_sectors, k;
2252 int heads_by_sects, start_sec, end_sec;
2253
2254 /* assume partition table already zeroed */
2255 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2256 return;
2257 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2258 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2259 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2260 "partitions to %d\n", SDEBUG_MAX_PARTS);
2261 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002262 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 sectors_per_part = (num_sectors - sdebug_sectors_per)
2264 / scsi_debug_num_parts;
2265 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2266 starts[0] = sdebug_sectors_per;
2267 for (k = 1; k < scsi_debug_num_parts; ++k)
2268 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2269 * heads_by_sects;
2270 starts[scsi_debug_num_parts] = num_sectors;
2271 starts[scsi_debug_num_parts + 1] = 0;
2272
2273 ramp[510] = 0x55; /* magic partition markings */
2274 ramp[511] = 0xAA;
2275 pp = (struct partition *)(ramp + 0x1be);
2276 for (k = 0; starts[k + 1]; ++k, ++pp) {
2277 start_sec = starts[k];
2278 end_sec = starts[k + 1] - 1;
2279 pp->boot_ind = 0;
2280
2281 pp->cyl = start_sec / heads_by_sects;
2282 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2283 / sdebug_sectors_per;
2284 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2285
2286 pp->end_cyl = end_sec / heads_by_sects;
2287 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2288 / sdebug_sectors_per;
2289 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2290
2291 pp->start_sect = start_sec;
2292 pp->nr_sects = end_sec - start_sec + 1;
2293 pp->sys_ind = 0x83; /* plain Linux partition */
2294 }
2295}
2296
2297static int schedule_resp(struct scsi_cmnd * cmnd,
2298 struct sdebug_dev_info * devip,
2299 done_funct_t done, int scsi_result, int delta_jiff)
2300{
2301 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2302 if (scsi_result) {
2303 struct scsi_device * sdp = cmnd->device;
2304
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002305 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2306 "non-zero result=0x%x\n", sdp->host->host_no,
2307 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 }
2309 }
2310 if (cmnd && devip) {
2311 /* simulate autosense by this driver */
2312 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2313 memcpy(cmnd->sense_buffer, devip->sense_buff,
2314 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2315 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2316 }
2317 if (delta_jiff <= 0) {
2318 if (cmnd)
2319 cmnd->result = scsi_result;
2320 if (done)
2321 done(cmnd);
2322 return 0;
2323 } else {
2324 unsigned long iflags;
2325 int k;
2326 struct sdebug_queued_cmd * sqcp = NULL;
2327
2328 spin_lock_irqsave(&queued_arr_lock, iflags);
2329 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2330 sqcp = &queued_arr[k];
2331 if (! sqcp->in_use)
2332 break;
2333 }
2334 if (k >= SCSI_DEBUG_CANQUEUE) {
2335 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2336 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2337 return 1; /* report busy to mid level */
2338 }
2339 sqcp->in_use = 1;
2340 sqcp->a_cmnd = cmnd;
2341 sqcp->scsi_result = scsi_result;
2342 sqcp->done_funct = done;
2343 sqcp->cmnd_timer.function = timer_intr_handler;
2344 sqcp->cmnd_timer.data = k;
2345 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2346 add_timer(&sqcp->cmnd_timer);
2347 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2348 if (cmnd)
2349 cmnd->result = 0;
2350 return 0;
2351 }
2352}
2353
Douglas Gilbert23183912006-09-16 20:30:47 -04002354/* Note: The following macros create attribute files in the
2355 /sys/module/scsi_debug/parameters directory. Unfortunately this
2356 driver is unaware of a change and cannot trigger auxiliary actions
2357 as it can when the corresponding attribute in the
2358 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2359 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002360module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2361module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2362module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2363module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2364module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002365module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002366module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2367module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2368module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2369module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2370module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2371module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2372module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2373module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002374module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2375 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
2377MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2378MODULE_DESCRIPTION("SCSI debug adapter driver");
2379MODULE_LICENSE("GPL");
2380MODULE_VERSION(SCSI_DEBUG_VERSION);
2381
2382MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2383MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002384MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2385MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002386MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002387MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002388MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2389MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002391MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002392MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2394MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002395MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002396MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398
2399static char sdebug_info[256];
2400
2401static const char * scsi_debug_info(struct Scsi_Host * shp)
2402{
2403 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2404 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2405 scsi_debug_version_date, scsi_debug_dev_size_mb,
2406 scsi_debug_opts);
2407 return sdebug_info;
2408}
2409
2410/* scsi_debug_proc_info
2411 * Used if the driver currently has no own support for /proc/scsi
2412 */
2413static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2414 int length, int inout)
2415{
2416 int len, pos, begin;
2417 int orig_length;
2418
2419 orig_length = length;
2420
2421 if (inout == 1) {
2422 char arr[16];
2423 int minLen = length > 15 ? 15 : length;
2424
2425 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2426 return -EACCES;
2427 memcpy(arr, buffer, minLen);
2428 arr[minLen] = '\0';
2429 if (1 != sscanf(arr, "%d", &pos))
2430 return -EINVAL;
2431 scsi_debug_opts = pos;
2432 if (scsi_debug_every_nth != 0)
2433 scsi_debug_cmnd_count = 0;
2434 return length;
2435 }
2436 begin = 0;
2437 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2438 "%s [%s]\n"
2439 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2440 "every_nth=%d(curr:%d)\n"
2441 "delay=%d, max_luns=%d, scsi_level=%d\n"
2442 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2443 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2444 "host_resets=%d\n",
2445 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2446 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2447 scsi_debug_cmnd_count, scsi_debug_delay,
2448 scsi_debug_max_luns, scsi_debug_scsi_level,
2449 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2450 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2451 if (pos < offset) {
2452 len = 0;
2453 begin = pos;
2454 }
2455 *start = buffer + (offset - begin); /* Start of wanted data */
2456 len -= (offset - begin);
2457 if (len > length)
2458 len = length;
2459 return len;
2460}
2461
2462static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2463{
2464 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2465}
2466
2467static ssize_t sdebug_delay_store(struct device_driver * ddp,
2468 const char * buf, size_t count)
2469{
2470 int delay;
2471 char work[20];
2472
2473 if (1 == sscanf(buf, "%10s", work)) {
2474 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2475 scsi_debug_delay = delay;
2476 return count;
2477 }
2478 }
2479 return -EINVAL;
2480}
2481DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2482 sdebug_delay_store);
2483
2484static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2485{
2486 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2487}
2488
2489static ssize_t sdebug_opts_store(struct device_driver * ddp,
2490 const char * buf, size_t count)
2491{
2492 int opts;
2493 char work[20];
2494
2495 if (1 == sscanf(buf, "%10s", work)) {
2496 if (0 == strnicmp(work,"0x", 2)) {
2497 if (1 == sscanf(&work[2], "%x", &opts))
2498 goto opts_done;
2499 } else {
2500 if (1 == sscanf(work, "%d", &opts))
2501 goto opts_done;
2502 }
2503 }
2504 return -EINVAL;
2505opts_done:
2506 scsi_debug_opts = opts;
2507 scsi_debug_cmnd_count = 0;
2508 return count;
2509}
2510DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2511 sdebug_opts_store);
2512
2513static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2514{
2515 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2516}
2517static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2518 const char * buf, size_t count)
2519{
2520 int n;
2521
2522 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2523 scsi_debug_ptype = n;
2524 return count;
2525 }
2526 return -EINVAL;
2527}
2528DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2529
2530static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2531{
2532 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2533}
2534static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2535 const char * buf, size_t count)
2536{
2537 int n;
2538
2539 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2540 scsi_debug_dsense = n;
2541 return count;
2542 }
2543 return -EINVAL;
2544}
2545DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2546 sdebug_dsense_store);
2547
Douglas Gilbert23183912006-09-16 20:30:47 -04002548static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2549{
2550 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2551}
2552static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2553 const char * buf, size_t count)
2554{
2555 int n;
2556
2557 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2558 scsi_debug_fake_rw = n;
2559 return count;
2560 }
2561 return -EINVAL;
2562}
2563DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2564 sdebug_fake_rw_store);
2565
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002566static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2567{
2568 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2569}
2570static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2571 const char * buf, size_t count)
2572{
2573 int n;
2574
2575 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2576 scsi_debug_no_lun_0 = n;
2577 return count;
2578 }
2579 return -EINVAL;
2580}
2581DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2582 sdebug_no_lun_0_store);
2583
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2585{
2586 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2587}
2588static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2589 const char * buf, size_t count)
2590{
2591 int n;
2592
2593 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2594 scsi_debug_num_tgts = n;
2595 sdebug_max_tgts_luns();
2596 return count;
2597 }
2598 return -EINVAL;
2599}
2600DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2601 sdebug_num_tgts_store);
2602
2603static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2604{
2605 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2606}
2607DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2608
2609static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2610{
2611 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2612}
2613DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2614
2615static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2616{
2617 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2618}
2619static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2620 const char * buf, size_t count)
2621{
2622 int nth;
2623
2624 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2625 scsi_debug_every_nth = nth;
2626 scsi_debug_cmnd_count = 0;
2627 return count;
2628 }
2629 return -EINVAL;
2630}
2631DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2632 sdebug_every_nth_store);
2633
2634static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2635{
2636 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2637}
2638static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2639 const char * buf, size_t count)
2640{
2641 int n;
2642
2643 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2644 scsi_debug_max_luns = n;
2645 sdebug_max_tgts_luns();
2646 return count;
2647 }
2648 return -EINVAL;
2649}
2650DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2651 sdebug_max_luns_store);
2652
2653static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2654{
2655 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2656}
2657DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2658
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002659static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2660{
2661 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2662}
2663static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2664 const char * buf, size_t count)
2665{
2666 int n;
2667
2668 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2669 scsi_debug_virtual_gb = n;
2670 if (scsi_debug_virtual_gb > 0) {
2671 sdebug_capacity = 2048 * 1024;
2672 sdebug_capacity *= scsi_debug_virtual_gb;
2673 } else
2674 sdebug_capacity = sdebug_store_sectors;
2675 return count;
2676 }
2677 return -EINVAL;
2678}
2679DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2680 sdebug_virtual_gb_store);
2681
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2683{
2684 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2685}
2686
2687static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2688 const char * buf, size_t count)
2689{
2690 int delta_hosts;
2691 char work[20];
2692
2693 if (1 != sscanf(buf, "%10s", work))
2694 return -EINVAL;
2695 { /* temporary hack around sscanf() problem with -ve nums */
2696 int neg = 0;
2697
2698 if ('-' == *work)
2699 neg = 1;
2700 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2701 return -EINVAL;
2702 if (neg)
2703 delta_hosts = -delta_hosts;
2704 }
2705 if (delta_hosts > 0) {
2706 do {
2707 sdebug_add_adapter();
2708 } while (--delta_hosts);
2709 } else if (delta_hosts < 0) {
2710 do {
2711 sdebug_remove_adapter();
2712 } while (++delta_hosts);
2713 }
2714 return count;
2715}
2716DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2717 sdebug_add_host_store);
2718
Douglas Gilbert23183912006-09-16 20:30:47 -04002719static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2720 char * buf)
2721{
2722 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2723}
2724static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2725 const char * buf, size_t count)
2726{
2727 int n;
2728
2729 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2730 scsi_debug_vpd_use_hostno = n;
2731 return count;
2732 }
2733 return -EINVAL;
2734}
2735DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2736 sdebug_vpd_use_hostno_store);
2737
2738/* Note: The following function creates attribute files in the
2739 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2740 files (over those found in the /sys/module/scsi_debug/parameters
2741 directory) is that auxiliary actions can be triggered when an attribute
2742 is changed. For example see: sdebug_add_host_store() above.
2743 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002744static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002746 int ret;
2747
2748 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2749 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2750 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2751 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2752 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002753 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002754 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002755 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002756 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002757 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002758 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2759 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2760 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002761 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2762 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002763 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764}
2765
2766static void do_remove_driverfs_files(void)
2767{
Douglas Gilbert23183912006-09-16 20:30:47 -04002768 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2769 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2771 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2772 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002774 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2775 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002777 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2779 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2780 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2781 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2782 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2783}
2784
2785static int __init scsi_debug_init(void)
2786{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002787 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 int host_to_add;
2789 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002790 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791
2792 if (scsi_debug_dev_size_mb < 1)
2793 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002794 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2795 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2796 if (scsi_debug_virtual_gb > 0) {
2797 sdebug_capacity = 2048 * 1024;
2798 sdebug_capacity *= scsi_debug_virtual_gb;
2799 } else
2800 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
2802 /* play around with geometry, don't waste too much on track 0 */
2803 sdebug_heads = 8;
2804 sdebug_sectors_per = 32;
2805 if (scsi_debug_dev_size_mb >= 16)
2806 sdebug_heads = 32;
2807 else if (scsi_debug_dev_size_mb >= 256)
2808 sdebug_heads = 64;
2809 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2810 (sdebug_sectors_per * sdebug_heads);
2811 if (sdebug_cylinders_per >= 1024) {
2812 /* other LLDs do this; implies >= 1GB ram disk ... */
2813 sdebug_heads = 255;
2814 sdebug_sectors_per = 63;
2815 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2816 (sdebug_sectors_per * sdebug_heads);
2817 }
2818
2819 sz = sdebug_store_size;
2820 fake_storep = vmalloc(sz);
2821 if (NULL == fake_storep) {
2822 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2823 return -ENOMEM;
2824 }
2825 memset(fake_storep, 0, sz);
2826 if (scsi_debug_num_parts > 0)
2827 sdebug_build_parts(fake_storep);
2828
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002829 ret = device_register(&pseudo_primary);
2830 if (ret < 0) {
2831 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2832 ret);
2833 goto free_vm;
2834 }
2835 ret = bus_register(&pseudo_lld_bus);
2836 if (ret < 0) {
2837 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2838 ret);
2839 goto dev_unreg;
2840 }
2841 ret = driver_register(&sdebug_driverfs_driver);
2842 if (ret < 0) {
2843 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2844 ret);
2845 goto bus_unreg;
2846 }
2847 ret = do_create_driverfs_files();
2848 if (ret < 0) {
2849 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2850 ret);
2851 goto del_files;
2852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002854 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855
Kristian Høgsbergb02b6bc2007-05-09 19:23:12 -04002856 sdebug_driver_template.proc_name = sdebug_proc_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
2858 host_to_add = scsi_debug_add_host;
2859 scsi_debug_add_host = 0;
2860
2861 for (k = 0; k < host_to_add; k++) {
2862 if (sdebug_add_adapter()) {
2863 printk(KERN_ERR "scsi_debug_init: "
2864 "sdebug_add_adapter failed k=%d\n", k);
2865 break;
2866 }
2867 }
2868
2869 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2870 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2871 scsi_debug_add_host);
2872 }
2873 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002874
2875del_files:
2876 do_remove_driverfs_files();
2877 driver_unregister(&sdebug_driverfs_driver);
2878bus_unreg:
2879 bus_unregister(&pseudo_lld_bus);
2880dev_unreg:
2881 device_unregister(&pseudo_primary);
2882free_vm:
2883 vfree(fake_storep);
2884
2885 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886}
2887
2888static void __exit scsi_debug_exit(void)
2889{
2890 int k = scsi_debug_add_host;
2891
2892 stop_all_queued();
2893 for (; k; k--)
2894 sdebug_remove_adapter();
2895 do_remove_driverfs_files();
2896 driver_unregister(&sdebug_driverfs_driver);
2897 bus_unregister(&pseudo_lld_bus);
2898 device_unregister(&pseudo_primary);
2899
2900 vfree(fake_storep);
2901}
2902
2903device_initcall(scsi_debug_init);
2904module_exit(scsi_debug_exit);
2905
Adrian Bunk52c1da32005-06-23 22:05:33 -07002906static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907{
2908 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2909 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2910}
2911
2912static struct device pseudo_primary = {
2913 .bus_id = "pseudo_0",
2914 .release = pseudo_0_release,
2915};
2916
2917static int pseudo_lld_bus_match(struct device *dev,
2918 struct device_driver *dev_driver)
2919{
2920 return 1;
2921}
2922
2923static struct bus_type pseudo_lld_bus = {
2924 .name = "pseudo",
2925 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002926 .probe = sdebug_driver_probe,
2927 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928};
2929
2930static void sdebug_release_adapter(struct device * dev)
2931{
2932 struct sdebug_host_info *sdbg_host;
2933
2934 sdbg_host = to_sdebug_host(dev);
2935 kfree(sdbg_host);
2936}
2937
2938static int sdebug_add_adapter(void)
2939{
2940 int k, devs_per_host;
2941 int error = 0;
2942 struct sdebug_host_info *sdbg_host;
2943 struct sdebug_dev_info *sdbg_devinfo;
2944 struct list_head *lh, *lh_sf;
2945
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002946 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 if (NULL == sdbg_host) {
2948 printk(KERN_ERR "%s: out of memory at line %d\n",
2949 __FUNCTION__, __LINE__);
2950 return -ENOMEM;
2951 }
2952
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2954
2955 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2956 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002957 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 if (NULL == sdbg_devinfo) {
2959 printk(KERN_ERR "%s: out of memory at line %d\n",
2960 __FUNCTION__, __LINE__);
2961 error = -ENOMEM;
2962 goto clean;
2963 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 sdbg_devinfo->sdbg_host = sdbg_host;
2965 list_add_tail(&sdbg_devinfo->dev_list,
2966 &sdbg_host->dev_info_list);
2967 }
2968
2969 spin_lock(&sdebug_host_list_lock);
2970 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2971 spin_unlock(&sdebug_host_list_lock);
2972
2973 sdbg_host->dev.bus = &pseudo_lld_bus;
2974 sdbg_host->dev.parent = &pseudo_primary;
2975 sdbg_host->dev.release = &sdebug_release_adapter;
2976 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2977
2978 error = device_register(&sdbg_host->dev);
2979
2980 if (error)
2981 goto clean;
2982
2983 ++scsi_debug_add_host;
2984 return error;
2985
2986clean:
2987 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
2988 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
2989 dev_list);
2990 list_del(&sdbg_devinfo->dev_list);
2991 kfree(sdbg_devinfo);
2992 }
2993
2994 kfree(sdbg_host);
2995 return error;
2996}
2997
2998static void sdebug_remove_adapter(void)
2999{
3000 struct sdebug_host_info * sdbg_host = NULL;
3001
3002 spin_lock(&sdebug_host_list_lock);
3003 if (!list_empty(&sdebug_host_list)) {
3004 sdbg_host = list_entry(sdebug_host_list.prev,
3005 struct sdebug_host_info, host_list);
3006 list_del(&sdbg_host->host_list);
3007 }
3008 spin_unlock(&sdebug_host_list_lock);
3009
3010 if (!sdbg_host)
3011 return;
3012
3013 device_unregister(&sdbg_host->dev);
3014 --scsi_debug_add_host;
3015}
3016
3017static int sdebug_driver_probe(struct device * dev)
3018{
3019 int error = 0;
3020 struct sdebug_host_info *sdbg_host;
3021 struct Scsi_Host *hpnt;
3022
3023 sdbg_host = to_sdebug_host(dev);
3024
3025 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3026 if (NULL == hpnt) {
3027 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3028 error = -ENODEV;
3029 return error;
3030 }
3031
3032 sdbg_host->shost = hpnt;
3033 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3034 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3035 hpnt->max_id = scsi_debug_num_tgts + 1;
3036 else
3037 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003038 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
3040 error = scsi_add_host(hpnt, &sdbg_host->dev);
3041 if (error) {
3042 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3043 error = -ENODEV;
3044 scsi_host_put(hpnt);
3045 } else
3046 scsi_scan_host(hpnt);
3047
3048
3049 return error;
3050}
3051
3052static int sdebug_driver_remove(struct device * dev)
3053{
3054 struct list_head *lh, *lh_sf;
3055 struct sdebug_host_info *sdbg_host;
3056 struct sdebug_dev_info *sdbg_devinfo;
3057
3058 sdbg_host = to_sdebug_host(dev);
3059
3060 if (!sdbg_host) {
3061 printk(KERN_ERR "%s: Unable to locate host info\n",
3062 __FUNCTION__);
3063 return -ENODEV;
3064 }
3065
3066 scsi_remove_host(sdbg_host->shost);
3067
3068 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3069 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3070 dev_list);
3071 list_del(&sdbg_devinfo->dev_list);
3072 kfree(sdbg_devinfo);
3073 }
3074
3075 scsi_host_put(sdbg_host->shost);
3076 return 0;
3077}
3078
3079static void sdebug_max_tgts_luns(void)
3080{
3081 struct sdebug_host_info * sdbg_host;
3082 struct Scsi_Host *hpnt;
3083
3084 spin_lock(&sdebug_host_list_lock);
3085 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3086 hpnt = sdbg_host->shost;
3087 if ((hpnt->this_id >= 0) &&
3088 (scsi_debug_num_tgts > hpnt->this_id))
3089 hpnt->max_id = scsi_debug_num_tgts + 1;
3090 else
3091 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003092 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 }
3094 spin_unlock(&sdebug_host_list_lock);
3095}