blob: 1da8ccde6d14f4e81a5da53f64abaaef5124f290 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/kernel/scsi_debug.c
3 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
4 * Copyright (C) 1992 Eric Youngdale
5 * Simulate a host adapter with 2 disks attached. Do a lot of checking
6 * to make sure that we are not getting blocks mixed up, and PANIC if
7 * anything out of the ordinary is seen.
8 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9 *
10 * This version is more generic, simulating a variable number of disk
11 * (or disk like devices) sharing a common amount of RAM
12 *
13 *
14 * For documentation see http://www.torque.net/sg/sdebug26.html
15 *
16 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
17 * dpg: work for devfs large number of disks [20010809]
18 * forked for lk 2.5 series [20011216, 20020101]
19 * use vmalloc() more inquiry+mode_sense [20020302]
20 * add timers for delayed responses [20020721]
21 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
22 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
23 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
24 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
25 */
26
27#include <linux/config.h>
28#include <linux/module.h>
29
30#include <linux/kernel.h>
31#include <linux/sched.h>
32#include <linux/errno.h>
33#include <linux/timer.h>
34#include <linux/types.h>
35#include <linux/string.h>
36#include <linux/genhd.h>
37#include <linux/fs.h>
38#include <linux/init.h>
39#include <linux/proc_fs.h>
40#include <linux/smp_lock.h>
41#include <linux/vmalloc.h>
42#include <linux/moduleparam.h>
43
44#include <linux/blkdev.h>
45#include "scsi.h"
46#include <scsi/scsi_host.h>
47#include <scsi/scsicam.h>
48
49#include <linux/stat.h>
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include "scsi_logging.h"
52#include "scsi_debug.h"
53
Douglas Gilbertc65b1442006-06-06 00:11:24 -040054#define SCSI_DEBUG_VERSION "1.79"
55static const char * scsi_debug_version_date = "20060604";
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57/* Additional Sense Code (ASC) used */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040058#define NO_ADDITIONAL_SENSE 0x0
59#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040061#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#define INVALID_OPCODE 0x20
63#define ADDR_OUT_OF_RANGE 0x21
64#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040065#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#define POWERON_RESET 0x29
67#define SAVING_PARAMS_UNSUP 0x39
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
71#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
72
73/* Default values for driver parameters */
74#define DEF_NUM_HOST 1
75#define DEF_NUM_TGTS 1
76#define DEF_MAX_LUNS 1
77/* With these defaults, this driver will make 1 host with 1 target
78 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
79 */
80#define DEF_DELAY 1
81#define DEF_DEV_SIZE_MB 8
82#define DEF_EVERY_NTH 0
83#define DEF_NUM_PARTS 0
84#define DEF_OPTS 0
85#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
86#define DEF_PTYPE 0
87#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040088#define DEF_NO_LUN_0 0
89#define DEF_VIRTUAL_GB 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
91/* bit mask values for scsi_debug_opts */
92#define SCSI_DEBUG_OPT_NOISE 1
93#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
94#define SCSI_DEBUG_OPT_TIMEOUT 4
95#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
96/* When "every_nth" > 0 then modulo "every_nth" commands:
97 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
98 * - a RECOVERED_ERROR is simulated on successful read and write
99 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
100 *
101 * When "every_nth" < 0 then after "- every_nth" commands:
102 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
103 * - a RECOVERED_ERROR is simulated on successful read and write
104 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
105 * This will continue until some other action occurs (e.g. the user
106 * writing a new value (other than -1 or 1) to every_nth via sysfs).
107 */
108
109/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
110 * sector on read commands: */
111#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
112
113/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
114 * or "peripheral device" addressing (value 0) */
115#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400116#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118static int scsi_debug_add_host = DEF_NUM_HOST;
119static int scsi_debug_delay = DEF_DELAY;
120static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
121static int scsi_debug_every_nth = DEF_EVERY_NTH;
122static int scsi_debug_max_luns = DEF_MAX_LUNS;
123static int scsi_debug_num_parts = DEF_NUM_PARTS;
124static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
125static int scsi_debug_opts = DEF_OPTS;
126static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
127static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
128static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400129static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
130static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132static int scsi_debug_cmnd_count = 0;
133
134#define DEV_READONLY(TGT) (0)
135#define DEV_REMOVEABLE(TGT) (0)
136
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400137static unsigned int sdebug_store_size; /* in bytes */
138static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139static sector_t sdebug_capacity; /* in sectors */
140
141/* old BIOS stuff, kernel may get rid of them but some mode sense pages
142 may still need them */
143static int sdebug_heads; /* heads per disk */
144static int sdebug_cylinders_per; /* cylinders per surface */
145static int sdebug_sectors_per; /* sectors per cylinder */
146
147/* default sector size is 512 bytes, 2**9 bytes */
148#define POW2_SECT_SIZE 9
149#define SECT_SIZE (1 << POW2_SECT_SIZE)
150#define SECT_SIZE_PER(TGT) SECT_SIZE
151
152#define SDEBUG_MAX_PARTS 4
153
154#define SDEBUG_SENSE_LEN 32
155
156struct sdebug_dev_info {
157 struct list_head dev_list;
158 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
159 unsigned int channel;
160 unsigned int target;
161 unsigned int lun;
162 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400163 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400165 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 char used;
167};
168
169struct sdebug_host_info {
170 struct list_head host_list;
171 struct Scsi_Host *shost;
172 struct device dev;
173 struct list_head dev_info_list;
174};
175
176#define to_sdebug_host(d) \
177 container_of(d, struct sdebug_host_info, dev)
178
179static LIST_HEAD(sdebug_host_list);
180static DEFINE_SPINLOCK(sdebug_host_list_lock);
181
182typedef void (* done_funct_t) (struct scsi_cmnd *);
183
184struct sdebug_queued_cmd {
185 int in_use;
186 struct timer_list cmnd_timer;
187 done_funct_t done_funct;
188 struct scsi_cmnd * a_cmnd;
189 int scsi_result;
190};
191static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
192
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100193static struct scsi_host_template sdebug_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 .proc_info = scsi_debug_proc_info,
195 .name = "SCSI DEBUG",
196 .info = scsi_debug_info,
197 .slave_alloc = scsi_debug_slave_alloc,
198 .slave_configure = scsi_debug_slave_configure,
199 .slave_destroy = scsi_debug_slave_destroy,
200 .ioctl = scsi_debug_ioctl,
201 .queuecommand = scsi_debug_queuecommand,
202 .eh_abort_handler = scsi_debug_abort,
203 .eh_bus_reset_handler = scsi_debug_bus_reset,
204 .eh_device_reset_handler = scsi_debug_device_reset,
205 .eh_host_reset_handler = scsi_debug_host_reset,
206 .bios_param = scsi_debug_biosparam,
207 .can_queue = SCSI_DEBUG_CANQUEUE,
208 .this_id = 7,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400209 .sg_tablesize = 256,
210 .cmd_per_lun = 16,
211 .max_sectors = 0xffff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 .unchecked_isa_dma = 0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400213 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 .module = THIS_MODULE,
215};
216
217static unsigned char * fake_storep; /* ramdisk storage */
218
219static int num_aborts = 0;
220static int num_dev_resets = 0;
221static int num_bus_resets = 0;
222static int num_host_resets = 0;
223
224static DEFINE_SPINLOCK(queued_arr_lock);
225static DEFINE_RWLOCK(atomic_rw);
226
227static char sdebug_proc_name[] = "scsi_debug";
228
229static int sdebug_driver_probe(struct device *);
230static int sdebug_driver_remove(struct device *);
231static struct bus_type pseudo_lld_bus;
232
233static struct device_driver sdebug_driverfs_driver = {
234 .name = sdebug_proc_name,
235 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236};
237
238static const int check_condition_result =
239 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
240
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400241static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
242 0, 0, 0x2, 0x4b};
243static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
244 0, 0, 0x0, 0x0};
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246/* function declarations */
247static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
248 struct sdebug_dev_info * devip);
249static int resp_requests(struct scsi_cmnd * SCpnt,
250 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400251static int resp_start_stop(struct scsi_cmnd * scp,
252 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253static int resp_readcap(struct scsi_cmnd * SCpnt,
254 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400255static int resp_readcap16(struct scsi_cmnd * SCpnt,
256 struct sdebug_dev_info * devip);
257static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400259static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
260 struct sdebug_dev_info * devip);
261static int resp_log_sense(struct scsi_cmnd * scp,
262 struct sdebug_dev_info * devip);
263static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
264 unsigned int num, struct sdebug_dev_info * devip);
265static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
266 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267static int resp_report_luns(struct scsi_cmnd * SCpnt,
268 struct sdebug_dev_info * devip);
269static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
270 int arr_len);
271static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
272 int max_arr_len);
273static void timer_intr_handler(unsigned long);
274static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
275static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
276 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400277static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
278 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279static int schedule_resp(struct scsi_cmnd * cmnd,
280 struct sdebug_dev_info * devip,
281 done_funct_t done, int scsi_result, int delta_jiff);
282static void __init sdebug_build_parts(unsigned char * ramp);
283static void __init init_all_queued(void);
284static void stop_all_queued(void);
285static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400286static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
287 int dev_id_num, const char * dev_id_str,
288 int dev_id_str_len);
289static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290static void do_create_driverfs_files(void);
291static void do_remove_driverfs_files(void);
292
293static int sdebug_add_adapter(void);
294static void sdebug_remove_adapter(void);
295static void sdebug_max_tgts_luns(void);
296
297static struct device pseudo_primary;
298static struct bus_type pseudo_lld_bus;
299
300
301static
302int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
303{
304 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400305 int len, k, j;
306 unsigned int num;
307 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400309 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 struct sdebug_dev_info * devip = NULL;
311 int inj_recovered = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400312 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 if (done == NULL)
315 return 0; /* assume mid level reprocessing command */
316
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400317 SCpnt->resid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
319 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400320 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 printk("%02x ", (int)cmd[k]);
322 printk("\n");
323 }
324 if(target == sdebug_driver_template.this_id) {
325 printk(KERN_INFO "scsi_debug: initiator's id used as "
326 "target!\n");
327 return schedule_resp(SCpnt, NULL, done,
328 DID_NO_CONNECT << 16, 0);
329 }
330
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400331 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
332 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 return schedule_resp(SCpnt, NULL, done,
334 DID_NO_CONNECT << 16, 0);
335 devip = devInfoReg(SCpnt->device);
336 if (NULL == devip)
337 return schedule_resp(SCpnt, NULL, done,
338 DID_NO_CONNECT << 16, 0);
339
340 if ((scsi_debug_every_nth != 0) &&
341 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
342 scsi_debug_cmnd_count = 0;
343 if (scsi_debug_every_nth < -1)
344 scsi_debug_every_nth = -1;
345 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
346 return 0; /* ignore command causing timeout */
347 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
348 inj_recovered = 1; /* to reads and writes below */
349 }
350
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400351 if (devip->wlun) {
352 switch (*cmd) {
353 case INQUIRY:
354 case REQUEST_SENSE:
355 case TEST_UNIT_READY:
356 case REPORT_LUNS:
357 break; /* only allowable wlun commands */
358 default:
359 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
360 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
361 "not supported for wlun\n", *cmd);
362 mk_sense_buffer(devip, ILLEGAL_REQUEST,
363 INVALID_OPCODE, 0);
364 errsts = check_condition_result;
365 return schedule_resp(SCpnt, devip, done, errsts,
366 0);
367 }
368 }
369
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 switch (*cmd) {
371 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400372 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 errsts = resp_inquiry(SCpnt, target, devip);
374 break;
375 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400376 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 errsts = resp_requests(SCpnt, devip);
378 break;
379 case REZERO_UNIT: /* actually this is REWIND for SSC */
380 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400381 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 break;
383 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400384 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 break;
386 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
387 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
388 cmd[4] ? "inhibited" : "enabled");
389 break;
390 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400391 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 break;
393 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400394 delay_override = 1;
395 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 break;
397 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400398 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 break;
400 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400401 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 break;
403 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400404 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 break;
406 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400407 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 break;
409 case READ_CAPACITY:
410 errsts = resp_readcap(SCpnt, devip);
411 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400412 case SERVICE_ACTION_IN:
413 if (SAI_READ_CAPACITY_16 != cmd[1]) {
414 mk_sense_buffer(devip, ILLEGAL_REQUEST,
415 INVALID_OPCODE, 0);
416 errsts = check_condition_result;
417 break;
418 }
419 errsts = resp_readcap16(SCpnt, devip);
420 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 case READ_16:
422 case READ_12:
423 case READ_10:
424 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400425 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 if ((*cmd) == READ_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400428 for (lba = 0, j = 0; j < 8; ++j) {
429 if (j > 0)
430 lba <<= 8;
431 lba += cmd[2 + j];
432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 num = cmd[13] + (cmd[12] << 8) +
434 (cmd[11] << 16) + (cmd[10] << 24);
435 } else if ((*cmd) == READ_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400436 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 (cmd[3] << 16) + (cmd[2] << 24);
438 num = cmd[9] + (cmd[8] << 8) +
439 (cmd[7] << 16) + (cmd[6] << 24);
440 } else if ((*cmd) == READ_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400441 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 (cmd[3] << 16) + (cmd[2] << 24);
443 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400444 } else { /* READ (6) */
445 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400447 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400449 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (inj_recovered && (0 == errsts)) {
451 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400452 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 errsts = check_condition_result;
454 }
455 break;
456 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400457 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 errsts = resp_report_luns(SCpnt, devip);
459 break;
460 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400461 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 break;
463 case WRITE_16:
464 case WRITE_12:
465 case WRITE_10:
466 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400467 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if ((*cmd) == WRITE_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400470 for (lba = 0, j = 0; j < 8; ++j) {
471 if (j > 0)
472 lba <<= 8;
473 lba += cmd[2 + j];
474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 num = cmd[13] + (cmd[12] << 8) +
476 (cmd[11] << 16) + (cmd[10] << 24);
477 } else if ((*cmd) == WRITE_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400478 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 (cmd[3] << 16) + (cmd[2] << 24);
480 num = cmd[9] + (cmd[8] << 8) +
481 (cmd[7] << 16) + (cmd[6] << 24);
482 } else if ((*cmd) == WRITE_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400483 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 (cmd[3] << 16) + (cmd[2] << 24);
485 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400486 } else { /* WRITE (6) */
487 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400489 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400491 errsts = resp_write(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;
496 }
497 break;
498 case MODE_SENSE:
499 case MODE_SENSE_10:
500 errsts = resp_mode_sense(SCpnt, target, devip);
501 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400502 case MODE_SELECT:
503 errsts = resp_mode_select(SCpnt, 1, devip);
504 break;
505 case MODE_SELECT_10:
506 errsts = resp_mode_select(SCpnt, 0, devip);
507 break;
508 case LOG_SENSE:
509 errsts = resp_log_sense(SCpnt, devip);
510 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400512 delay_override = 1;
513 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 break;
515 default:
516 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
517 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
518 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400519 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 break; /* Unit attention takes precedence */
521 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
522 errsts = check_condition_result;
523 break;
524 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400525 return schedule_resp(SCpnt, devip, done, errsts,
526 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527}
528
529static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
530{
531 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
532 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
533 }
534 return -EINVAL;
535 /* return -ENOTTY; // correct return but upsets fdisk */
536}
537
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400538static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
539 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 if (devip->reset) {
542 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
543 printk(KERN_INFO "scsi_debug: Reporting Unit "
544 "attention: power on reset\n");
545 devip->reset = 0;
546 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
547 return check_condition_result;
548 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400549 if ((0 == reset_only) && devip->stopped) {
550 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
551 printk(KERN_INFO "scsi_debug: Reporting Not "
552 "ready: initializing command required\n");
553 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
554 0x2);
555 return check_condition_result;
556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 return 0;
558}
559
560/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
561static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
562 int arr_len)
563{
564 int k, req_len, act_len, len, active;
565 void * kaddr;
566 void * kaddr_off;
567 struct scatterlist * sgpnt;
568
569 if (0 == scp->request_bufflen)
570 return 0;
571 if (NULL == scp->request_buffer)
572 return (DID_ERROR << 16);
573 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
574 (scp->sc_data_direction == DMA_FROM_DEVICE)))
575 return (DID_ERROR << 16);
576 if (0 == scp->use_sg) {
577 req_len = scp->request_bufflen;
578 act_len = (req_len < arr_len) ? req_len : arr_len;
579 memcpy(scp->request_buffer, arr, act_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400580 if (scp->resid)
581 scp->resid -= act_len;
582 else
583 scp->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 return 0;
585 }
586 sgpnt = (struct scatterlist *)scp->request_buffer;
587 active = 1;
588 for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) {
589 if (active) {
590 kaddr = (unsigned char *)
591 kmap_atomic(sgpnt->page, KM_USER0);
592 if (NULL == kaddr)
593 return (DID_ERROR << 16);
594 kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
595 len = sgpnt->length;
596 if ((req_len + len) > arr_len) {
597 active = 0;
598 len = arr_len - req_len;
599 }
600 memcpy(kaddr_off, arr + req_len, len);
601 kunmap_atomic(kaddr, KM_USER0);
602 act_len += len;
603 }
604 req_len += sgpnt->length;
605 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400606 if (scp->resid)
607 scp->resid -= act_len;
608 else
609 scp->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 return 0;
611}
612
613/* Returns number of bytes fetched into 'arr' or -1 if error. */
614static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
615 int max_arr_len)
616{
617 int k, req_len, len, fin;
618 void * kaddr;
619 void * kaddr_off;
620 struct scatterlist * sgpnt;
621
622 if (0 == scp->request_bufflen)
623 return 0;
624 if (NULL == scp->request_buffer)
625 return -1;
626 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
627 (scp->sc_data_direction == DMA_TO_DEVICE)))
628 return -1;
629 if (0 == scp->use_sg) {
630 req_len = scp->request_bufflen;
631 len = (req_len < max_arr_len) ? req_len : max_arr_len;
632 memcpy(arr, scp->request_buffer, len);
633 return len;
634 }
635 sgpnt = (struct scatterlist *)scp->request_buffer;
636 for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) {
637 kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0);
638 if (NULL == kaddr)
639 return -1;
640 kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
641 len = sgpnt->length;
642 if ((req_len + len) > max_arr_len) {
643 len = max_arr_len - req_len;
644 fin = 1;
645 }
646 memcpy(arr + req_len, kaddr_off, len);
647 kunmap_atomic(kaddr, KM_USER0);
648 if (fin)
649 return req_len + len;
650 req_len += sgpnt->length;
651 }
652 return req_len;
653}
654
655
656static const char * inq_vendor_id = "Linux ";
657static const char * inq_product_id = "scsi_debug ";
658static const char * inq_product_rev = "0004";
659
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400660static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
661 int dev_id_num, const char * dev_id_str,
662 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400664 int num, port_a;
665 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400667 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 /* T10 vendor identifier field format (faked) */
669 arr[0] = 0x2; /* ASCII */
670 arr[1] = 0x1;
671 arr[2] = 0x0;
672 memcpy(&arr[4], inq_vendor_id, 8);
673 memcpy(&arr[12], inq_product_id, 16);
674 memcpy(&arr[28], dev_id_str, dev_id_str_len);
675 num = 8 + 16 + dev_id_str_len;
676 arr[3] = num;
677 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400678 if (dev_id_num >= 0) {
679 /* NAA-5, Logical unit identifier (binary) */
680 arr[num++] = 0x1; /* binary (not necessarily sas) */
681 arr[num++] = 0x3; /* PIV=0, lu, naa */
682 arr[num++] = 0x0;
683 arr[num++] = 0x8;
684 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
685 arr[num++] = 0x33;
686 arr[num++] = 0x33;
687 arr[num++] = 0x30;
688 arr[num++] = (dev_id_num >> 24);
689 arr[num++] = (dev_id_num >> 16) & 0xff;
690 arr[num++] = (dev_id_num >> 8) & 0xff;
691 arr[num++] = dev_id_num & 0xff;
692 /* Target relative port number */
693 arr[num++] = 0x61; /* proto=sas, binary */
694 arr[num++] = 0x94; /* PIV=1, target port, rel port */
695 arr[num++] = 0x0; /* reserved */
696 arr[num++] = 0x4; /* length */
697 arr[num++] = 0x0; /* reserved */
698 arr[num++] = 0x0; /* reserved */
699 arr[num++] = 0x0;
700 arr[num++] = 0x1; /* relative port A */
701 }
702 /* NAA-5, Target port identifier */
703 arr[num++] = 0x61; /* proto=sas, binary */
704 arr[num++] = 0x93; /* piv=1, target port, naa */
705 arr[num++] = 0x0;
706 arr[num++] = 0x8;
707 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
708 arr[num++] = 0x22;
709 arr[num++] = 0x22;
710 arr[num++] = 0x20;
711 arr[num++] = (port_a >> 24);
712 arr[num++] = (port_a >> 16) & 0xff;
713 arr[num++] = (port_a >> 8) & 0xff;
714 arr[num++] = port_a & 0xff;
715 /* NAA-5, Target device identifier */
716 arr[num++] = 0x61; /* proto=sas, binary */
717 arr[num++] = 0xa3; /* piv=1, target device, naa */
718 arr[num++] = 0x0;
719 arr[num++] = 0x8;
720 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
721 arr[num++] = 0x22;
722 arr[num++] = 0x22;
723 arr[num++] = 0x20;
724 arr[num++] = (target_dev_id >> 24);
725 arr[num++] = (target_dev_id >> 16) & 0xff;
726 arr[num++] = (target_dev_id >> 8) & 0xff;
727 arr[num++] = target_dev_id & 0xff;
728 /* SCSI name string: Target device identifier */
729 arr[num++] = 0x63; /* proto=sas, UTF-8 */
730 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
731 arr[num++] = 0x0;
732 arr[num++] = 24;
733 memcpy(arr + num, "naa.52222220", 12);
734 num += 12;
735 snprintf(b, sizeof(b), "%08X", target_dev_id);
736 memcpy(arr + num, b, 8);
737 num += 8;
738 memset(arr + num, 0, 4);
739 num += 4;
740 return num;
741}
742
743
744static unsigned char vpd84_data[] = {
745/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
746 0x22,0x22,0x22,0x0,0xbb,0x1,
747 0x22,0x22,0x22,0x0,0xbb,0x2,
748};
749
750static int inquiry_evpd_84(unsigned char * arr)
751{
752 memcpy(arr, vpd84_data, sizeof(vpd84_data));
753 return sizeof(vpd84_data);
754}
755
756static int inquiry_evpd_85(unsigned char * arr)
757{
758 int num = 0;
759 const char * na1 = "https://www.kernel.org/config";
760 const char * na2 = "http://www.kernel.org/log";
761 int plen, olen;
762
763 arr[num++] = 0x1; /* lu, storage config */
764 arr[num++] = 0x0; /* reserved */
765 arr[num++] = 0x0;
766 olen = strlen(na1);
767 plen = olen + 1;
768 if (plen % 4)
769 plen = ((plen / 4) + 1) * 4;
770 arr[num++] = plen; /* length, null termianted, padded */
771 memcpy(arr + num, na1, olen);
772 memset(arr + num + olen, 0, plen - olen);
773 num += plen;
774
775 arr[num++] = 0x4; /* lu, logging */
776 arr[num++] = 0x0; /* reserved */
777 arr[num++] = 0x0;
778 olen = strlen(na2);
779 plen = olen + 1;
780 if (plen % 4)
781 plen = ((plen / 4) + 1) * 4;
782 arr[num++] = plen; /* length, null terminated, padded */
783 memcpy(arr + num, na2, olen);
784 memset(arr + num + olen, 0, plen - olen);
785 num += plen;
786
787 return num;
788}
789
790/* SCSI ports VPD page */
791static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
792{
793 int num = 0;
794 int port_a, port_b;
795
796 port_a = target_dev_id + 1;
797 port_b = port_a + 1;
798 arr[num++] = 0x0; /* reserved */
799 arr[num++] = 0x0; /* reserved */
800 arr[num++] = 0x0;
801 arr[num++] = 0x1; /* relative port 1 (primary) */
802 memset(arr + num, 0, 6);
803 num += 6;
804 arr[num++] = 0x0;
805 arr[num++] = 12; /* length tp descriptor */
806 /* naa-5 target port identifier (A) */
807 arr[num++] = 0x61; /* proto=sas, binary */
808 arr[num++] = 0x93; /* PIV=1, target port, NAA */
809 arr[num++] = 0x0; /* reserved */
810 arr[num++] = 0x8; /* length */
811 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
812 arr[num++] = 0x22;
813 arr[num++] = 0x22;
814 arr[num++] = 0x20;
815 arr[num++] = (port_a >> 24);
816 arr[num++] = (port_a >> 16) & 0xff;
817 arr[num++] = (port_a >> 8) & 0xff;
818 arr[num++] = port_a & 0xff;
819
820 arr[num++] = 0x0; /* reserved */
821 arr[num++] = 0x0; /* reserved */
822 arr[num++] = 0x0;
823 arr[num++] = 0x2; /* relative port 2 (secondary) */
824 memset(arr + num, 0, 6);
825 num += 6;
826 arr[num++] = 0x0;
827 arr[num++] = 12; /* length tp descriptor */
828 /* naa-5 target port identifier (B) */
829 arr[num++] = 0x61; /* proto=sas, binary */
830 arr[num++] = 0x93; /* PIV=1, target port, NAA */
831 arr[num++] = 0x0; /* reserved */
832 arr[num++] = 0x8; /* length */
833 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
834 arr[num++] = 0x22;
835 arr[num++] = 0x22;
836 arr[num++] = 0x20;
837 arr[num++] = (port_b >> 24);
838 arr[num++] = (port_b >> 16) & 0xff;
839 arr[num++] = (port_b >> 8) & 0xff;
840 arr[num++] = port_b & 0xff;
841
842 return num;
843}
844
845
846static unsigned char vpd89_data[] = {
847/* from 4th byte */ 0,0,0,0,
848'l','i','n','u','x',' ',' ',' ',
849'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
850'1','2','3','4',
8510x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8520xec,0,0,0,
8530x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
8540,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
8550x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
8560x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
8570x53,0x41,
8580x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8590x20,0x20,
8600x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8610x10,0x80,
8620,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8630x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8640x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8650,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8660x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8670x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8680,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
8690,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8720x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
8730,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
8740xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
8750,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
8760,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8770,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
8870,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
888};
889
890static int inquiry_evpd_89(unsigned char * arr)
891{
892 memcpy(arr, vpd89_data, sizeof(vpd89_data));
893 return sizeof(vpd89_data);
894}
895
896
897static unsigned char vpdb0_data[] = {
898 /* from 4th byte */ 0,0,0,4,
899 0,0,0x4,0,
900 0,0,0,64,
901};
902
903static int inquiry_evpd_b0(unsigned char * arr)
904{
905 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
906 if (sdebug_store_sectors > 0x400) {
907 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
908 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
909 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
910 arr[7] = sdebug_store_sectors & 0xff;
911 }
912 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
915
916#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400917#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
919static int resp_inquiry(struct scsi_cmnd * scp, int target,
920 struct sdebug_dev_info * devip)
921{
922 unsigned char pq_pdt;
923 unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
924 unsigned char *cmd = (unsigned char *)scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400925 int alloc_len, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927 alloc_len = (cmd[3] << 8) + cmd[4];
928 memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400929 if (devip->wlun)
930 pq_pdt = 0x1e; /* present, wlun */
931 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
932 pq_pdt = 0x7f; /* not present, no device type */
933 else
934 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 arr[0] = pq_pdt;
936 if (0x2 & cmd[1]) { /* CMDDT bit set */
937 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
938 0);
939 return check_condition_result;
940 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400941 int lu_id_num, target_dev_id, len;
942 char lu_id_str[6];
943 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400945 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
946 (devip->target * 1000) + devip->lun);
947 target_dev_id = ((host_no + 1) * 2000) +
948 (devip->target * 1000) - 3;
949 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400951 arr[1] = cmd[2]; /*sanity */
952 n = 4;
953 arr[n++] = 0x0; /* this page */
954 arr[n++] = 0x80; /* unit serial number */
955 arr[n++] = 0x83; /* device identification */
956 arr[n++] = 0x84; /* software interface ident. */
957 arr[n++] = 0x85; /* management network addresses */
958 arr[n++] = 0x86; /* extended inquiry */
959 arr[n++] = 0x87; /* mode page policy */
960 arr[n++] = 0x88; /* SCSI ports */
961 arr[n++] = 0x89; /* ATA information */
962 arr[n++] = 0xb0; /* Block limits (SBC) */
963 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400965 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400967 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400969 arr[1] = cmd[2]; /*sanity */
970 arr[3] = inquiry_evpd_83(&arr[4], target_dev_id,
971 lu_id_num, lu_id_str, len);
972 } else if (0x84 == cmd[2]) { /* Software interface ident. */
973 arr[1] = cmd[2]; /*sanity */
974 arr[3] = inquiry_evpd_84(&arr[4]);
975 } else if (0x85 == cmd[2]) { /* Management network addresses */
976 arr[1] = cmd[2]; /*sanity */
977 arr[3] = inquiry_evpd_85(&arr[4]);
978 } else if (0x86 == cmd[2]) { /* extended inquiry */
979 arr[1] = cmd[2]; /*sanity */
980 arr[3] = 0x3c; /* number of following entries */
981 arr[4] = 0x0; /* no protection stuff */
982 arr[5] = 0x7; /* head of q, ordered + simple q's */
983 } else if (0x87 == cmd[2]) { /* mode page policy */
984 arr[1] = cmd[2]; /*sanity */
985 arr[3] = 0x8; /* number of following entries */
986 arr[4] = 0x2; /* disconnect-reconnect mp */
987 arr[6] = 0x80; /* mlus, shared */
988 arr[8] = 0x18; /* protocol specific lu */
989 arr[10] = 0x82; /* mlus, per initiator port */
990 } else if (0x88 == cmd[2]) { /* SCSI Ports */
991 arr[1] = cmd[2]; /*sanity */
992 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
993 } else if (0x89 == cmd[2]) { /* ATA information */
994 arr[1] = cmd[2]; /*sanity */
995 n = inquiry_evpd_89(&arr[4]);
996 arr[2] = (n >> 8);
997 arr[3] = (n & 0xff);
998 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
999 arr[1] = cmd[2]; /*sanity */
1000 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 } else {
1002 /* Illegal request, invalid field in cdb */
1003 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1004 INVALID_FIELD_IN_CDB, 0);
1005 return check_condition_result;
1006 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001007 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001009 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 }
1011 /* drops through here for a standard inquiry */
1012 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1013 arr[2] = scsi_debug_scsi_level;
1014 arr[3] = 2; /* response_data_format==2 */
1015 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001016 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001018 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 memcpy(&arr[8], inq_vendor_id, 8);
1020 memcpy(&arr[16], inq_product_id, 16);
1021 memcpy(&arr[32], inq_product_rev, 4);
1022 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001023 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1024 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1025 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001027 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001029 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001031 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return fill_from_dev_buffer(scp, arr,
1033 min(alloc_len, SDEBUG_LONG_INQ_SZ));
1034}
1035
1036static int resp_requests(struct scsi_cmnd * scp,
1037 struct sdebug_dev_info * devip)
1038{
1039 unsigned char * sbuff;
1040 unsigned char *cmd = (unsigned char *)scp->cmnd;
1041 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001042 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 int len = 18;
1044
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001045 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001047 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1048 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001050 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1051 if (want_dsense) {
1052 arr[0] = 0x72;
1053 arr[1] = 0x0; /* NO_SENSE in sense_key */
1054 arr[2] = THRESHOLD_EXCEEDED;
1055 arr[3] = 0xff; /* TEST set and MRIE==6 */
1056 } else {
1057 arr[0] = 0x70;
1058 arr[2] = 0x0; /* NO_SENSE in sense_key */
1059 arr[7] = 0xa; /* 18 byte sense buffer */
1060 arr[12] = THRESHOLD_EXCEEDED;
1061 arr[13] = 0xff; /* TEST set and MRIE==6 */
1062 }
1063 } else if (devip->stopped) {
1064 if (want_dsense) {
1065 arr[0] = 0x72;
1066 arr[1] = 0x0; /* NO_SENSE in sense_key */
1067 arr[2] = LOW_POWER_COND_ON;
1068 arr[3] = 0x0; /* TEST set and MRIE==6 */
1069 } else {
1070 arr[0] = 0x70;
1071 arr[2] = 0x0; /* NO_SENSE in sense_key */
1072 arr[7] = 0xa; /* 18 byte sense buffer */
1073 arr[12] = LOW_POWER_COND_ON;
1074 arr[13] = 0x0; /* TEST set and MRIE==6 */
1075 }
1076 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001078 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1079 /* DESC bit set and sense_buff in fixed format */
1080 memset(arr, 0, sizeof(arr));
1081 arr[0] = 0x72;
1082 arr[1] = sbuff[2]; /* sense key */
1083 arr[2] = sbuff[12]; /* asc */
1084 arr[3] = sbuff[13]; /* ascq */
1085 len = 8;
1086 }
1087 }
1088 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 return fill_from_dev_buffer(scp, arr, len);
1090}
1091
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001092static int resp_start_stop(struct scsi_cmnd * scp,
1093 struct sdebug_dev_info * devip)
1094{
1095 unsigned char *cmd = (unsigned char *)scp->cmnd;
1096 int power_cond, errsts, start;
1097
1098 if ((errsts = check_readiness(scp, 1, devip)))
1099 return errsts;
1100 power_cond = (cmd[4] & 0xf0) >> 4;
1101 if (power_cond) {
1102 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1103 0);
1104 return check_condition_result;
1105 }
1106 start = cmd[4] & 1;
1107 if (start == devip->stopped)
1108 devip->stopped = !start;
1109 return 0;
1110}
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112#define SDEBUG_READCAP_ARR_SZ 8
1113static int resp_readcap(struct scsi_cmnd * scp,
1114 struct sdebug_dev_info * devip)
1115{
1116 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001117 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 int errsts;
1119
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001120 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001122 /* following just in case virtual_gb changed */
1123 if (scsi_debug_virtual_gb > 0) {
1124 sdebug_capacity = 2048 * 1024;
1125 sdebug_capacity *= scsi_debug_virtual_gb;
1126 } else
1127 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001129 if (sdebug_capacity < 0xffffffff) {
1130 capac = (unsigned int)sdebug_capacity - 1;
1131 arr[0] = (capac >> 24);
1132 arr[1] = (capac >> 16) & 0xff;
1133 arr[2] = (capac >> 8) & 0xff;
1134 arr[3] = capac & 0xff;
1135 } else {
1136 arr[0] = 0xff;
1137 arr[1] = 0xff;
1138 arr[2] = 0xff;
1139 arr[3] = 0xff;
1140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1142 arr[7] = SECT_SIZE_PER(target) & 0xff;
1143 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1144}
1145
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001146#define SDEBUG_READCAP16_ARR_SZ 32
1147static int resp_readcap16(struct scsi_cmnd * scp,
1148 struct sdebug_dev_info * devip)
1149{
1150 unsigned char *cmd = (unsigned char *)scp->cmnd;
1151 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1152 unsigned long long capac;
1153 int errsts, k, alloc_len;
1154
1155 if ((errsts = check_readiness(scp, 1, devip)))
1156 return errsts;
1157 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1158 + cmd[13]);
1159 /* following just in case virtual_gb changed */
1160 if (scsi_debug_virtual_gb > 0) {
1161 sdebug_capacity = 2048 * 1024;
1162 sdebug_capacity *= scsi_debug_virtual_gb;
1163 } else
1164 sdebug_capacity = sdebug_store_sectors;
1165 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1166 capac = sdebug_capacity - 1;
1167 for (k = 0; k < 8; ++k, capac >>= 8)
1168 arr[7 - k] = capac & 0xff;
1169 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1170 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1171 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1172 arr[11] = SECT_SIZE_PER(target) & 0xff;
1173 return fill_from_dev_buffer(scp, arr,
1174 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1175}
1176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177/* <<Following mode page info copied from ST318451LW>> */
1178
1179static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1180{ /* Read-Write Error Recovery page for mode_sense */
1181 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1182 5, 0, 0xff, 0xff};
1183
1184 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1185 if (1 == pcontrol)
1186 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1187 return sizeof(err_recov_pg);
1188}
1189
1190static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1191{ /* Disconnect-Reconnect page for mode_sense */
1192 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1193 0, 0, 0, 0, 0, 0, 0, 0};
1194
1195 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1196 if (1 == pcontrol)
1197 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1198 return sizeof(disconnect_pg);
1199}
1200
1201static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1202{ /* Format device page for mode_sense */
1203 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1204 0, 0, 0, 0, 0, 0, 0, 0,
1205 0, 0, 0, 0, 0x40, 0, 0, 0};
1206
1207 memcpy(p, format_pg, sizeof(format_pg));
1208 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1209 p[11] = sdebug_sectors_per & 0xff;
1210 p[12] = (SECT_SIZE >> 8) & 0xff;
1211 p[13] = SECT_SIZE & 0xff;
1212 if (DEV_REMOVEABLE(target))
1213 p[20] |= 0x20; /* should agree with INQUIRY */
1214 if (1 == pcontrol)
1215 memset(p + 2, 0, sizeof(format_pg) - 2);
1216 return sizeof(format_pg);
1217}
1218
1219static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1220{ /* Caching page for mode_sense */
1221 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1222 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1223
1224 memcpy(p, caching_pg, sizeof(caching_pg));
1225 if (1 == pcontrol)
1226 memset(p + 2, 0, sizeof(caching_pg) - 2);
1227 return sizeof(caching_pg);
1228}
1229
1230static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1231{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001232 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1233 0, 0, 0, 0};
1234 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 0, 0, 0x2, 0x4b};
1236
1237 if (scsi_debug_dsense)
1238 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001239 else
1240 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1242 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001243 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1244 else if (2 == pcontrol)
1245 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 return sizeof(ctrl_m_pg);
1247}
1248
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001249
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1251{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001252 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1253 0, 0, 0x0, 0x0};
1254 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1255 0, 0, 0x0, 0x0};
1256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1258 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001259 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1260 else if (2 == pcontrol)
1261 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 return sizeof(iec_m_pg);
1263}
1264
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001265static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1266{ /* SAS SSP mode page - short format for mode_sense */
1267 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1268 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1269
1270 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1271 if (1 == pcontrol)
1272 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1273 return sizeof(sas_sf_m_pg);
1274}
1275
1276
1277static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1278 int target_dev_id)
1279{ /* SAS phy control and discover mode page for mode_sense */
1280 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1281 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1282 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1283 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1284 0x2, 0, 0, 0, 0, 0, 0, 0,
1285 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1286 0, 0, 0, 0, 0, 0, 0, 0,
1287 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1288 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1289 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1290 0x3, 0, 0, 0, 0, 0, 0, 0,
1291 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1292 0, 0, 0, 0, 0, 0, 0, 0,
1293 };
1294 int port_a, port_b;
1295
1296 port_a = target_dev_id + 1;
1297 port_b = port_a + 1;
1298 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1299 p[20] = (port_a >> 24);
1300 p[21] = (port_a >> 16) & 0xff;
1301 p[22] = (port_a >> 8) & 0xff;
1302 p[23] = port_a & 0xff;
1303 p[48 + 20] = (port_b >> 24);
1304 p[48 + 21] = (port_b >> 16) & 0xff;
1305 p[48 + 22] = (port_b >> 8) & 0xff;
1306 p[48 + 23] = port_b & 0xff;
1307 if (1 == pcontrol)
1308 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1309 return sizeof(sas_pcd_m_pg);
1310}
1311
1312static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1313{ /* SAS SSP shared protocol specific port mode subpage */
1314 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1315 0, 0, 0, 0, 0, 0, 0, 0,
1316 };
1317
1318 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1319 if (1 == pcontrol)
1320 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1321 return sizeof(sas_sha_m_pg);
1322}
1323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324#define SDEBUG_MAX_MSENSE_SZ 256
1325
1326static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1327 struct sdebug_dev_info * devip)
1328{
1329 unsigned char dbd;
1330 int pcontrol, pcode, subpcode;
1331 unsigned char dev_spec;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001332 int alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 unsigned char * ap;
1334 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1335 unsigned char *cmd = (unsigned char *)scp->cmnd;
1336
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001337 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 return errsts;
1339 dbd = cmd[1] & 0x8;
1340 pcontrol = (cmd[2] & 0xc0) >> 6;
1341 pcode = cmd[2] & 0x3f;
1342 subpcode = cmd[3];
1343 msense_6 = (MODE_SENSE == cmd[0]);
1344 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1345 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1346 if (0x3 == pcontrol) { /* Saving values not supported */
1347 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1348 0);
1349 return check_condition_result;
1350 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001351 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1352 (devip->target * 1000) - 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
1354 if (msense_6) {
1355 arr[2] = dev_spec;
1356 offset = 4;
1357 } else {
1358 arr[3] = dev_spec;
1359 offset = 8;
1360 }
1361 ap = arr + offset;
1362
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001363 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1364 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1366 0);
1367 return check_condition_result;
1368 }
1369 switch (pcode) {
1370 case 0x1: /* Read-Write error recovery page, direct access */
1371 len = resp_err_recov_pg(ap, pcontrol, target);
1372 offset += len;
1373 break;
1374 case 0x2: /* Disconnect-Reconnect page, all devices */
1375 len = resp_disconnect_pg(ap, pcontrol, target);
1376 offset += len;
1377 break;
1378 case 0x3: /* Format device page, direct access */
1379 len = resp_format_pg(ap, pcontrol, target);
1380 offset += len;
1381 break;
1382 case 0x8: /* Caching page, direct access */
1383 len = resp_caching_pg(ap, pcontrol, target);
1384 offset += len;
1385 break;
1386 case 0xa: /* Control Mode page, all devices */
1387 len = resp_ctrl_m_pg(ap, pcontrol, target);
1388 offset += len;
1389 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001390 case 0x19: /* if spc==1 then sas phy, control+discover */
1391 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1392 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1393 INVALID_FIELD_IN_CDB, 0);
1394 return check_condition_result;
1395 }
1396 len = 0;
1397 if ((0x0 == subpcode) || (0xff == subpcode))
1398 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1399 if ((0x1 == subpcode) || (0xff == subpcode))
1400 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1401 target_dev_id);
1402 if ((0x2 == subpcode) || (0xff == subpcode))
1403 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1404 offset += len;
1405 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 case 0x1c: /* Informational Exceptions Mode page, all devices */
1407 len = resp_iec_m_pg(ap, pcontrol, target);
1408 offset += len;
1409 break;
1410 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001411 if ((0 == subpcode) || (0xff == subpcode)) {
1412 len = resp_err_recov_pg(ap, pcontrol, target);
1413 len += resp_disconnect_pg(ap + len, pcontrol, target);
1414 len += resp_format_pg(ap + len, pcontrol, target);
1415 len += resp_caching_pg(ap + len, pcontrol, target);
1416 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1417 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1418 if (0xff == subpcode) {
1419 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1420 target, target_dev_id);
1421 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1422 }
1423 len += resp_iec_m_pg(ap + len, pcontrol, target);
1424 } else {
1425 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1426 INVALID_FIELD_IN_CDB, 0);
1427 return check_condition_result;
1428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 offset += len;
1430 break;
1431 default:
1432 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1433 0);
1434 return check_condition_result;
1435 }
1436 if (msense_6)
1437 arr[0] = offset - 1;
1438 else {
1439 arr[0] = ((offset - 2) >> 8) & 0xff;
1440 arr[1] = (offset - 2) & 0xff;
1441 }
1442 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1443}
1444
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001445#define SDEBUG_MAX_MSELECT_SZ 512
1446
1447static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1448 struct sdebug_dev_info * devip)
1449{
1450 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1451 int param_len, res, errsts, mpage;
1452 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1453 unsigned char *cmd = (unsigned char *)scp->cmnd;
1454
1455 if ((errsts = check_readiness(scp, 1, devip)))
1456 return errsts;
1457 memset(arr, 0, sizeof(arr));
1458 pf = cmd[1] & 0x10;
1459 sp = cmd[1] & 0x1;
1460 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1461 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1462 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1463 INVALID_FIELD_IN_CDB, 0);
1464 return check_condition_result;
1465 }
1466 res = fetch_to_dev_buffer(scp, arr, param_len);
1467 if (-1 == res)
1468 return (DID_ERROR << 16);
1469 else if ((res < param_len) &&
1470 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1471 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1472 " IO sent=%d bytes\n", param_len, res);
1473 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1474 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
1475 if ((md_len > 2) || (0 != bd_len)) {
1476 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1477 INVALID_FIELD_IN_PARAM_LIST, 0);
1478 return check_condition_result;
1479 }
1480 off = bd_len + (mselect6 ? 4 : 8);
1481 mpage = arr[off] & 0x3f;
1482 ps = !!(arr[off] & 0x80);
1483 if (ps) {
1484 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1485 INVALID_FIELD_IN_PARAM_LIST, 0);
1486 return check_condition_result;
1487 }
1488 spf = !!(arr[off] & 0x40);
1489 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1490 (arr[off + 1] + 2);
1491 if ((pg_len + off) > param_len) {
1492 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1493 PARAMETER_LIST_LENGTH_ERR, 0);
1494 return check_condition_result;
1495 }
1496 switch (mpage) {
1497 case 0xa: /* Control Mode page */
1498 if (ctrl_m_pg[1] == arr[off + 1]) {
1499 memcpy(ctrl_m_pg + 2, arr + off + 2,
1500 sizeof(ctrl_m_pg) - 2);
1501 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1502 return 0;
1503 }
1504 break;
1505 case 0x1c: /* Informational Exceptions Mode page */
1506 if (iec_m_pg[1] == arr[off + 1]) {
1507 memcpy(iec_m_pg + 2, arr + off + 2,
1508 sizeof(iec_m_pg) - 2);
1509 return 0;
1510 }
1511 break;
1512 default:
1513 break;
1514 }
1515 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1516 INVALID_FIELD_IN_PARAM_LIST, 0);
1517 return check_condition_result;
1518}
1519
1520static int resp_temp_l_pg(unsigned char * arr)
1521{
1522 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1523 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1524 };
1525
1526 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1527 return sizeof(temp_l_pg);
1528}
1529
1530static int resp_ie_l_pg(unsigned char * arr)
1531{
1532 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1533 };
1534
1535 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1536 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1537 arr[4] = THRESHOLD_EXCEEDED;
1538 arr[5] = 0xff;
1539 }
1540 return sizeof(ie_l_pg);
1541}
1542
1543#define SDEBUG_MAX_LSENSE_SZ 512
1544
1545static int resp_log_sense(struct scsi_cmnd * scp,
1546 struct sdebug_dev_info * devip)
1547{
1548 int ppc, sp, pcontrol, pcode, alloc_len, errsts, len, n;
1549 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1550 unsigned char *cmd = (unsigned char *)scp->cmnd;
1551
1552 if ((errsts = check_readiness(scp, 1, devip)))
1553 return errsts;
1554 memset(arr, 0, sizeof(arr));
1555 ppc = cmd[1] & 0x2;
1556 sp = cmd[1] & 0x1;
1557 if (ppc || sp) {
1558 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1559 INVALID_FIELD_IN_CDB, 0);
1560 return check_condition_result;
1561 }
1562 pcontrol = (cmd[2] & 0xc0) >> 6;
1563 pcode = cmd[2] & 0x3f;
1564 alloc_len = (cmd[7] << 8) + cmd[8];
1565 arr[0] = pcode;
1566 switch (pcode) {
1567 case 0x0: /* Supported log pages log page */
1568 n = 4;
1569 arr[n++] = 0x0; /* this page */
1570 arr[n++] = 0xd; /* Temperature */
1571 arr[n++] = 0x2f; /* Informational exceptions */
1572 arr[3] = n - 4;
1573 break;
1574 case 0xd: /* Temperature log page */
1575 arr[3] = resp_temp_l_pg(arr + 4);
1576 break;
1577 case 0x2f: /* Informational exceptions log page */
1578 arr[3] = resp_ie_l_pg(arr + 4);
1579 break;
1580 default:
1581 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1582 INVALID_FIELD_IN_CDB, 0);
1583 return check_condition_result;
1584 }
1585 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1586 return fill_from_dev_buffer(scp, arr,
1587 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1588}
1589
1590static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1591 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592{
1593 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001594 unsigned int block, from_bottom;
1595 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 int ret;
1597
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001598 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1600 0);
1601 return check_condition_result;
1602 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001603 /* transfer length excessive (tie in to block limits VPD page) */
1604 if (num > sdebug_store_sectors) {
1605 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1606 0);
1607 return check_condition_result;
1608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001610 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1611 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1612 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1614 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001615 /* set info field and valid bit for fixed descriptor */
1616 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1617 devip->sense_buff[0] |= 0x80; /* Valid bit */
1618 ret = OPT_MEDIUM_ERR_ADDR;
1619 devip->sense_buff[3] = (ret >> 24) & 0xff;
1620 devip->sense_buff[4] = (ret >> 16) & 0xff;
1621 devip->sense_buff[5] = (ret >> 8) & 0xff;
1622 devip->sense_buff[6] = ret & 0xff;
1623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 return check_condition_result;
1625 }
1626 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001627 if ((lba + num) <= sdebug_store_sectors)
1628 ret = fill_from_dev_buffer(SCpnt,
1629 fake_storep + (lba * SECT_SIZE),
1630 num * SECT_SIZE);
1631 else {
1632 /* modulo when one arg is 64 bits needs do_div() */
1633 u = lba;
1634 block = do_div(u, sdebug_store_sectors);
1635 from_bottom = 0;
1636 if ((block + num) > sdebug_store_sectors)
1637 from_bottom = (block + num) - sdebug_store_sectors;
1638 ret = fill_from_dev_buffer(SCpnt,
1639 fake_storep + (block * SECT_SIZE),
1640 (num - from_bottom) * SECT_SIZE);
1641 if ((0 == ret) && (from_bottom > 0))
1642 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1643 from_bottom * SECT_SIZE);
1644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 read_unlock_irqrestore(&atomic_rw, iflags);
1646 return ret;
1647}
1648
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001649static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1650 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651{
1652 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001653 unsigned int block, to_bottom;
1654 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 int res;
1656
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001657 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1659 0);
1660 return check_condition_result;
1661 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001662 /* transfer length excessive (tie in to block limits VPD page) */
1663 if (num > sdebug_store_sectors) {
1664 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1665 0);
1666 return check_condition_result;
1667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
1669 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001670 if ((lba + num) <= sdebug_store_sectors)
1671 res = fetch_to_dev_buffer(SCpnt,
1672 fake_storep + (lba * SECT_SIZE),
1673 num * SECT_SIZE);
1674 else {
1675 /* modulo when one arg is 64 bits needs do_div() */
1676 u = lba;
1677 block = do_div(u, sdebug_store_sectors);
1678 to_bottom = 0;
1679 if ((block + num) > sdebug_store_sectors)
1680 to_bottom = (block + num) - sdebug_store_sectors;
1681 res = fetch_to_dev_buffer(SCpnt,
1682 fake_storep + (block * SECT_SIZE),
1683 (num - to_bottom) * SECT_SIZE);
1684 if ((0 == res) && (to_bottom > 0))
1685 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1686 to_bottom * SECT_SIZE);
1687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 write_unlock_irqrestore(&atomic_rw, iflags);
1689 if (-1 == res)
1690 return (DID_ERROR << 16);
1691 else if ((res < (num * SECT_SIZE)) &&
1692 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001693 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1695 return 0;
1696}
1697
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001698#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699
1700static int resp_report_luns(struct scsi_cmnd * scp,
1701 struct sdebug_dev_info * devip)
1702{
1703 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001704 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 unsigned char *cmd = (unsigned char *)scp->cmnd;
1706 int select_report = (int)cmd[2];
1707 struct scsi_lun *one_lun;
1708 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001709 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
1711 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001712 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1714 0);
1715 return check_condition_result;
1716 }
1717 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1718 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1719 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001720 if (1 == select_report)
1721 lun_cnt = 0;
1722 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1723 --lun_cnt;
1724 wlun = (select_report > 0) ? 1 : 0;
1725 num = lun_cnt + wlun;
1726 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1727 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1728 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1729 sizeof(struct scsi_lun)), num);
1730 if (n < num) {
1731 wlun = 0;
1732 lun_cnt = n;
1733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001735 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1736 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1737 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1738 i++, lun++) {
1739 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 if (upper)
1741 one_lun[i].scsi_lun[0] =
1742 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001743 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001745 if (wlun) {
1746 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1747 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1748 i++;
1749 }
1750 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 return fill_from_dev_buffer(scp, arr,
1752 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1753}
1754
1755/* When timer goes off this function is called. */
1756static void timer_intr_handler(unsigned long indx)
1757{
1758 struct sdebug_queued_cmd * sqcp;
1759 unsigned long iflags;
1760
1761 if (indx >= SCSI_DEBUG_CANQUEUE) {
1762 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1763 "large\n");
1764 return;
1765 }
1766 spin_lock_irqsave(&queued_arr_lock, iflags);
1767 sqcp = &queued_arr[(int)indx];
1768 if (! sqcp->in_use) {
1769 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1770 "interrupt\n");
1771 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1772 return;
1773 }
1774 sqcp->in_use = 0;
1775 if (sqcp->done_funct) {
1776 sqcp->a_cmnd->result = sqcp->scsi_result;
1777 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1778 }
1779 sqcp->done_funct = NULL;
1780 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1781}
1782
1783static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1784{
1785 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001786 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1787 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 return 0;
1789}
1790
1791static int scsi_debug_slave_configure(struct scsi_device * sdp)
1792{
1793 struct sdebug_dev_info * devip;
1794
1795 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001796 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1797 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1799 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1800 devip = devInfoReg(sdp);
1801 sdp->hostdata = devip;
1802 if (sdp->host->cmd_per_lun)
1803 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1804 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001805 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 return 0;
1807}
1808
1809static void scsi_debug_slave_destroy(struct scsi_device * sdp)
1810{
1811 struct sdebug_dev_info * devip =
1812 (struct sdebug_dev_info *)sdp->hostdata;
1813
1814 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001815 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1816 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 if (devip) {
1818 /* make this slot avaliable for re-use */
1819 devip->used = 0;
1820 sdp->hostdata = NULL;
1821 }
1822}
1823
1824static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1825{
1826 struct sdebug_host_info * sdbg_host;
1827 struct sdebug_dev_info * open_devip = NULL;
1828 struct sdebug_dev_info * devip =
1829 (struct sdebug_dev_info *)sdev->hostdata;
1830
1831 if (devip)
1832 return devip;
1833 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
1834 if(! sdbg_host) {
1835 printk(KERN_ERR "Host info NULL\n");
1836 return NULL;
1837 }
1838 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1839 if ((devip->used) && (devip->channel == sdev->channel) &&
1840 (devip->target == sdev->id) &&
1841 (devip->lun == sdev->lun))
1842 return devip;
1843 else {
1844 if ((!devip->used) && (!open_devip))
1845 open_devip = devip;
1846 }
1847 }
1848 if (NULL == open_devip) { /* try and make a new one */
Jes Sorensen24669f752006-01-16 10:31:18 -05001849 open_devip = kzalloc(sizeof(*open_devip),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 if (NULL == open_devip) {
1851 printk(KERN_ERR "%s: out of memory at line %d\n",
1852 __FUNCTION__, __LINE__);
1853 return NULL;
1854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 open_devip->sdbg_host = sdbg_host;
1856 list_add_tail(&open_devip->dev_list,
1857 &sdbg_host->dev_info_list);
1858 }
1859 if (open_devip) {
1860 open_devip->channel = sdev->channel;
1861 open_devip->target = sdev->id;
1862 open_devip->lun = sdev->lun;
1863 open_devip->sdbg_host = sdbg_host;
1864 open_devip->reset = 1;
1865 open_devip->used = 1;
1866 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1867 if (scsi_debug_dsense)
1868 open_devip->sense_buff[0] = 0x72;
1869 else {
1870 open_devip->sense_buff[0] = 0x70;
1871 open_devip->sense_buff[7] = 0xa;
1872 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001873 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1874 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 return open_devip;
1876 }
1877 return NULL;
1878}
1879
1880static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
1881 int asc, int asq)
1882{
1883 unsigned char * sbuff;
1884
1885 sbuff = devip->sense_buff;
1886 memset(sbuff, 0, SDEBUG_SENSE_LEN);
1887 if (scsi_debug_dsense) {
1888 sbuff[0] = 0x72; /* descriptor, current */
1889 sbuff[1] = key;
1890 sbuff[2] = asc;
1891 sbuff[3] = asq;
1892 } else {
1893 sbuff[0] = 0x70; /* fixed, current */
1894 sbuff[2] = key;
1895 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
1896 sbuff[12] = asc;
1897 sbuff[13] = asq;
1898 }
1899 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1900 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
1901 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
1902}
1903
1904static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1905{
1906 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1907 printk(KERN_INFO "scsi_debug: abort\n");
1908 ++num_aborts;
1909 stop_queued_cmnd(SCpnt);
1910 return SUCCESS;
1911}
1912
1913static int scsi_debug_biosparam(struct scsi_device *sdev,
1914 struct block_device * bdev, sector_t capacity, int *info)
1915{
1916 int res;
1917 unsigned char *buf;
1918
1919 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1920 printk(KERN_INFO "scsi_debug: biosparam\n");
1921 buf = scsi_bios_ptable(bdev);
1922 if (buf) {
1923 res = scsi_partsize(buf, capacity,
1924 &info[2], &info[0], &info[1]);
1925 kfree(buf);
1926 if (! res)
1927 return res;
1928 }
1929 info[0] = sdebug_heads;
1930 info[1] = sdebug_sectors_per;
1931 info[2] = sdebug_cylinders_per;
1932 return 0;
1933}
1934
1935static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1936{
1937 struct sdebug_dev_info * devip;
1938
1939 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1940 printk(KERN_INFO "scsi_debug: device_reset\n");
1941 ++num_dev_resets;
1942 if (SCpnt) {
1943 devip = devInfoReg(SCpnt->device);
1944 if (devip)
1945 devip->reset = 1;
1946 }
1947 return SUCCESS;
1948}
1949
1950static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1951{
1952 struct sdebug_host_info *sdbg_host;
1953 struct sdebug_dev_info * dev_info;
1954 struct scsi_device * sdp;
1955 struct Scsi_Host * hp;
1956
1957 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1958 printk(KERN_INFO "scsi_debug: bus_reset\n");
1959 ++num_bus_resets;
1960 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
1961 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
1962 if (sdbg_host) {
1963 list_for_each_entry(dev_info,
1964 &sdbg_host->dev_info_list,
1965 dev_list)
1966 dev_info->reset = 1;
1967 }
1968 }
1969 return SUCCESS;
1970}
1971
1972static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1973{
1974 struct sdebug_host_info * sdbg_host;
1975 struct sdebug_dev_info * dev_info;
1976
1977 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1978 printk(KERN_INFO "scsi_debug: host_reset\n");
1979 ++num_host_resets;
1980 spin_lock(&sdebug_host_list_lock);
1981 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1982 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1983 dev_list)
1984 dev_info->reset = 1;
1985 }
1986 spin_unlock(&sdebug_host_list_lock);
1987 stop_all_queued();
1988 return SUCCESS;
1989}
1990
1991/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1992static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
1993{
1994 unsigned long iflags;
1995 int k;
1996 struct sdebug_queued_cmd * sqcp;
1997
1998 spin_lock_irqsave(&queued_arr_lock, iflags);
1999 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2000 sqcp = &queued_arr[k];
2001 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2002 del_timer_sync(&sqcp->cmnd_timer);
2003 sqcp->in_use = 0;
2004 sqcp->a_cmnd = NULL;
2005 break;
2006 }
2007 }
2008 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2009 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2010}
2011
2012/* Deletes (stops) timers of all queued commands */
2013static void stop_all_queued(void)
2014{
2015 unsigned long iflags;
2016 int k;
2017 struct sdebug_queued_cmd * sqcp;
2018
2019 spin_lock_irqsave(&queued_arr_lock, iflags);
2020 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2021 sqcp = &queued_arr[k];
2022 if (sqcp->in_use && sqcp->a_cmnd) {
2023 del_timer_sync(&sqcp->cmnd_timer);
2024 sqcp->in_use = 0;
2025 sqcp->a_cmnd = NULL;
2026 }
2027 }
2028 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2029}
2030
2031/* Initializes timers in queued array */
2032static void __init init_all_queued(void)
2033{
2034 unsigned long iflags;
2035 int k;
2036 struct sdebug_queued_cmd * sqcp;
2037
2038 spin_lock_irqsave(&queued_arr_lock, iflags);
2039 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2040 sqcp = &queued_arr[k];
2041 init_timer(&sqcp->cmnd_timer);
2042 sqcp->in_use = 0;
2043 sqcp->a_cmnd = NULL;
2044 }
2045 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2046}
2047
2048static void __init sdebug_build_parts(unsigned char * ramp)
2049{
2050 struct partition * pp;
2051 int starts[SDEBUG_MAX_PARTS + 2];
2052 int sectors_per_part, num_sectors, k;
2053 int heads_by_sects, start_sec, end_sec;
2054
2055 /* assume partition table already zeroed */
2056 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2057 return;
2058 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2059 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2060 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2061 "partitions to %d\n", SDEBUG_MAX_PARTS);
2062 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002063 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 sectors_per_part = (num_sectors - sdebug_sectors_per)
2065 / scsi_debug_num_parts;
2066 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2067 starts[0] = sdebug_sectors_per;
2068 for (k = 1; k < scsi_debug_num_parts; ++k)
2069 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2070 * heads_by_sects;
2071 starts[scsi_debug_num_parts] = num_sectors;
2072 starts[scsi_debug_num_parts + 1] = 0;
2073
2074 ramp[510] = 0x55; /* magic partition markings */
2075 ramp[511] = 0xAA;
2076 pp = (struct partition *)(ramp + 0x1be);
2077 for (k = 0; starts[k + 1]; ++k, ++pp) {
2078 start_sec = starts[k];
2079 end_sec = starts[k + 1] - 1;
2080 pp->boot_ind = 0;
2081
2082 pp->cyl = start_sec / heads_by_sects;
2083 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2084 / sdebug_sectors_per;
2085 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2086
2087 pp->end_cyl = end_sec / heads_by_sects;
2088 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2089 / sdebug_sectors_per;
2090 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2091
2092 pp->start_sect = start_sec;
2093 pp->nr_sects = end_sec - start_sec + 1;
2094 pp->sys_ind = 0x83; /* plain Linux partition */
2095 }
2096}
2097
2098static int schedule_resp(struct scsi_cmnd * cmnd,
2099 struct sdebug_dev_info * devip,
2100 done_funct_t done, int scsi_result, int delta_jiff)
2101{
2102 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2103 if (scsi_result) {
2104 struct scsi_device * sdp = cmnd->device;
2105
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002106 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2107 "non-zero result=0x%x\n", sdp->host->host_no,
2108 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 }
2110 }
2111 if (cmnd && devip) {
2112 /* simulate autosense by this driver */
2113 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2114 memcpy(cmnd->sense_buffer, devip->sense_buff,
2115 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2116 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2117 }
2118 if (delta_jiff <= 0) {
2119 if (cmnd)
2120 cmnd->result = scsi_result;
2121 if (done)
2122 done(cmnd);
2123 return 0;
2124 } else {
2125 unsigned long iflags;
2126 int k;
2127 struct sdebug_queued_cmd * sqcp = NULL;
2128
2129 spin_lock_irqsave(&queued_arr_lock, iflags);
2130 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2131 sqcp = &queued_arr[k];
2132 if (! sqcp->in_use)
2133 break;
2134 }
2135 if (k >= SCSI_DEBUG_CANQUEUE) {
2136 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2137 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2138 return 1; /* report busy to mid level */
2139 }
2140 sqcp->in_use = 1;
2141 sqcp->a_cmnd = cmnd;
2142 sqcp->scsi_result = scsi_result;
2143 sqcp->done_funct = done;
2144 sqcp->cmnd_timer.function = timer_intr_handler;
2145 sqcp->cmnd_timer.data = k;
2146 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2147 add_timer(&sqcp->cmnd_timer);
2148 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2149 if (cmnd)
2150 cmnd->result = 0;
2151 return 0;
2152 }
2153}
2154
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002155module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2156module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2157module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2158module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2159module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
2160module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2161module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2162module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2163module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2164module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2165module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2166module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2167module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
2169MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2170MODULE_DESCRIPTION("SCSI debug adapter driver");
2171MODULE_LICENSE("GPL");
2172MODULE_VERSION(SCSI_DEBUG_VERSION);
2173
2174MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2175MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002176MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2177MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002179MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2180MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002182MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
2183MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2185MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002186MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
2188
2189static char sdebug_info[256];
2190
2191static const char * scsi_debug_info(struct Scsi_Host * shp)
2192{
2193 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2194 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2195 scsi_debug_version_date, scsi_debug_dev_size_mb,
2196 scsi_debug_opts);
2197 return sdebug_info;
2198}
2199
2200/* scsi_debug_proc_info
2201 * Used if the driver currently has no own support for /proc/scsi
2202 */
2203static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2204 int length, int inout)
2205{
2206 int len, pos, begin;
2207 int orig_length;
2208
2209 orig_length = length;
2210
2211 if (inout == 1) {
2212 char arr[16];
2213 int minLen = length > 15 ? 15 : length;
2214
2215 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2216 return -EACCES;
2217 memcpy(arr, buffer, minLen);
2218 arr[minLen] = '\0';
2219 if (1 != sscanf(arr, "%d", &pos))
2220 return -EINVAL;
2221 scsi_debug_opts = pos;
2222 if (scsi_debug_every_nth != 0)
2223 scsi_debug_cmnd_count = 0;
2224 return length;
2225 }
2226 begin = 0;
2227 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2228 "%s [%s]\n"
2229 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2230 "every_nth=%d(curr:%d)\n"
2231 "delay=%d, max_luns=%d, scsi_level=%d\n"
2232 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2233 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2234 "host_resets=%d\n",
2235 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2236 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2237 scsi_debug_cmnd_count, scsi_debug_delay,
2238 scsi_debug_max_luns, scsi_debug_scsi_level,
2239 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2240 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2241 if (pos < offset) {
2242 len = 0;
2243 begin = pos;
2244 }
2245 *start = buffer + (offset - begin); /* Start of wanted data */
2246 len -= (offset - begin);
2247 if (len > length)
2248 len = length;
2249 return len;
2250}
2251
2252static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2253{
2254 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2255}
2256
2257static ssize_t sdebug_delay_store(struct device_driver * ddp,
2258 const char * buf, size_t count)
2259{
2260 int delay;
2261 char work[20];
2262
2263 if (1 == sscanf(buf, "%10s", work)) {
2264 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2265 scsi_debug_delay = delay;
2266 return count;
2267 }
2268 }
2269 return -EINVAL;
2270}
2271DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2272 sdebug_delay_store);
2273
2274static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2275{
2276 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2277}
2278
2279static ssize_t sdebug_opts_store(struct device_driver * ddp,
2280 const char * buf, size_t count)
2281{
2282 int opts;
2283 char work[20];
2284
2285 if (1 == sscanf(buf, "%10s", work)) {
2286 if (0 == strnicmp(work,"0x", 2)) {
2287 if (1 == sscanf(&work[2], "%x", &opts))
2288 goto opts_done;
2289 } else {
2290 if (1 == sscanf(work, "%d", &opts))
2291 goto opts_done;
2292 }
2293 }
2294 return -EINVAL;
2295opts_done:
2296 scsi_debug_opts = opts;
2297 scsi_debug_cmnd_count = 0;
2298 return count;
2299}
2300DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2301 sdebug_opts_store);
2302
2303static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2304{
2305 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2306}
2307static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2308 const char * buf, size_t count)
2309{
2310 int n;
2311
2312 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2313 scsi_debug_ptype = n;
2314 return count;
2315 }
2316 return -EINVAL;
2317}
2318DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2319
2320static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2321{
2322 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2323}
2324static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2325 const char * buf, size_t count)
2326{
2327 int n;
2328
2329 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2330 scsi_debug_dsense = n;
2331 return count;
2332 }
2333 return -EINVAL;
2334}
2335DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2336 sdebug_dsense_store);
2337
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002338static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2339{
2340 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2341}
2342static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2343 const char * buf, size_t count)
2344{
2345 int n;
2346
2347 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2348 scsi_debug_no_lun_0 = n;
2349 return count;
2350 }
2351 return -EINVAL;
2352}
2353DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2354 sdebug_no_lun_0_store);
2355
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2357{
2358 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2359}
2360static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2361 const char * buf, size_t count)
2362{
2363 int n;
2364
2365 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2366 scsi_debug_num_tgts = n;
2367 sdebug_max_tgts_luns();
2368 return count;
2369 }
2370 return -EINVAL;
2371}
2372DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2373 sdebug_num_tgts_store);
2374
2375static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2376{
2377 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2378}
2379DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2380
2381static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2382{
2383 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2384}
2385DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2386
2387static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2388{
2389 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2390}
2391static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2392 const char * buf, size_t count)
2393{
2394 int nth;
2395
2396 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2397 scsi_debug_every_nth = nth;
2398 scsi_debug_cmnd_count = 0;
2399 return count;
2400 }
2401 return -EINVAL;
2402}
2403DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2404 sdebug_every_nth_store);
2405
2406static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2407{
2408 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2409}
2410static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2411 const char * buf, size_t count)
2412{
2413 int n;
2414
2415 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2416 scsi_debug_max_luns = n;
2417 sdebug_max_tgts_luns();
2418 return count;
2419 }
2420 return -EINVAL;
2421}
2422DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2423 sdebug_max_luns_store);
2424
2425static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2426{
2427 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2428}
2429DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2430
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002431static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2432{
2433 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2434}
2435static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2436 const char * buf, size_t count)
2437{
2438 int n;
2439
2440 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2441 scsi_debug_virtual_gb = n;
2442 if (scsi_debug_virtual_gb > 0) {
2443 sdebug_capacity = 2048 * 1024;
2444 sdebug_capacity *= scsi_debug_virtual_gb;
2445 } else
2446 sdebug_capacity = sdebug_store_sectors;
2447 return count;
2448 }
2449 return -EINVAL;
2450}
2451DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2452 sdebug_virtual_gb_store);
2453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2455{
2456 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2457}
2458
2459static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2460 const char * buf, size_t count)
2461{
2462 int delta_hosts;
2463 char work[20];
2464
2465 if (1 != sscanf(buf, "%10s", work))
2466 return -EINVAL;
2467 { /* temporary hack around sscanf() problem with -ve nums */
2468 int neg = 0;
2469
2470 if ('-' == *work)
2471 neg = 1;
2472 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2473 return -EINVAL;
2474 if (neg)
2475 delta_hosts = -delta_hosts;
2476 }
2477 if (delta_hosts > 0) {
2478 do {
2479 sdebug_add_adapter();
2480 } while (--delta_hosts);
2481 } else if (delta_hosts < 0) {
2482 do {
2483 sdebug_remove_adapter();
2484 } while (++delta_hosts);
2485 }
2486 return count;
2487}
2488DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2489 sdebug_add_host_store);
2490
2491static void do_create_driverfs_files(void)
2492{
2493 driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2494 driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2495 driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2496 driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2497 driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2498 driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
2499 driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
2500 driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2501 driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2502 driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2503 driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2504}
2505
2506static void do_remove_driverfs_files(void)
2507{
2508 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2509 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2510 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2511 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2512 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
2513 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
2514 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2515 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2516 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2517 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2518 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2519}
2520
2521static int __init scsi_debug_init(void)
2522{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002523 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 int host_to_add;
2525 int k;
2526
2527 if (scsi_debug_dev_size_mb < 1)
2528 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002529 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2530 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2531 if (scsi_debug_virtual_gb > 0) {
2532 sdebug_capacity = 2048 * 1024;
2533 sdebug_capacity *= scsi_debug_virtual_gb;
2534 } else
2535 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
2537 /* play around with geometry, don't waste too much on track 0 */
2538 sdebug_heads = 8;
2539 sdebug_sectors_per = 32;
2540 if (scsi_debug_dev_size_mb >= 16)
2541 sdebug_heads = 32;
2542 else if (scsi_debug_dev_size_mb >= 256)
2543 sdebug_heads = 64;
2544 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2545 (sdebug_sectors_per * sdebug_heads);
2546 if (sdebug_cylinders_per >= 1024) {
2547 /* other LLDs do this; implies >= 1GB ram disk ... */
2548 sdebug_heads = 255;
2549 sdebug_sectors_per = 63;
2550 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2551 (sdebug_sectors_per * sdebug_heads);
2552 }
2553
2554 sz = sdebug_store_size;
2555 fake_storep = vmalloc(sz);
2556 if (NULL == fake_storep) {
2557 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2558 return -ENOMEM;
2559 }
2560 memset(fake_storep, 0, sz);
2561 if (scsi_debug_num_parts > 0)
2562 sdebug_build_parts(fake_storep);
2563
2564 init_all_queued();
2565
2566 device_register(&pseudo_primary);
2567 bus_register(&pseudo_lld_bus);
2568 driver_register(&sdebug_driverfs_driver);
2569 do_create_driverfs_files();
2570
2571 sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
2572
2573 host_to_add = scsi_debug_add_host;
2574 scsi_debug_add_host = 0;
2575
2576 for (k = 0; k < host_to_add; k++) {
2577 if (sdebug_add_adapter()) {
2578 printk(KERN_ERR "scsi_debug_init: "
2579 "sdebug_add_adapter failed k=%d\n", k);
2580 break;
2581 }
2582 }
2583
2584 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2585 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2586 scsi_debug_add_host);
2587 }
2588 return 0;
2589}
2590
2591static void __exit scsi_debug_exit(void)
2592{
2593 int k = scsi_debug_add_host;
2594
2595 stop_all_queued();
2596 for (; k; k--)
2597 sdebug_remove_adapter();
2598 do_remove_driverfs_files();
2599 driver_unregister(&sdebug_driverfs_driver);
2600 bus_unregister(&pseudo_lld_bus);
2601 device_unregister(&pseudo_primary);
2602
2603 vfree(fake_storep);
2604}
2605
2606device_initcall(scsi_debug_init);
2607module_exit(scsi_debug_exit);
2608
Adrian Bunk52c1da32005-06-23 22:05:33 -07002609static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610{
2611 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2612 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2613}
2614
2615static struct device pseudo_primary = {
2616 .bus_id = "pseudo_0",
2617 .release = pseudo_0_release,
2618};
2619
2620static int pseudo_lld_bus_match(struct device *dev,
2621 struct device_driver *dev_driver)
2622{
2623 return 1;
2624}
2625
2626static struct bus_type pseudo_lld_bus = {
2627 .name = "pseudo",
2628 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002629 .probe = sdebug_driver_probe,
2630 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631};
2632
2633static void sdebug_release_adapter(struct device * dev)
2634{
2635 struct sdebug_host_info *sdbg_host;
2636
2637 sdbg_host = to_sdebug_host(dev);
2638 kfree(sdbg_host);
2639}
2640
2641static int sdebug_add_adapter(void)
2642{
2643 int k, devs_per_host;
2644 int error = 0;
2645 struct sdebug_host_info *sdbg_host;
2646 struct sdebug_dev_info *sdbg_devinfo;
2647 struct list_head *lh, *lh_sf;
2648
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002649 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650
2651 if (NULL == sdbg_host) {
2652 printk(KERN_ERR "%s: out of memory at line %d\n",
2653 __FUNCTION__, __LINE__);
2654 return -ENOMEM;
2655 }
2656
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2658
2659 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2660 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002661 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 if (NULL == sdbg_devinfo) {
2663 printk(KERN_ERR "%s: out of memory at line %d\n",
2664 __FUNCTION__, __LINE__);
2665 error = -ENOMEM;
2666 goto clean;
2667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 sdbg_devinfo->sdbg_host = sdbg_host;
2669 list_add_tail(&sdbg_devinfo->dev_list,
2670 &sdbg_host->dev_info_list);
2671 }
2672
2673 spin_lock(&sdebug_host_list_lock);
2674 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2675 spin_unlock(&sdebug_host_list_lock);
2676
2677 sdbg_host->dev.bus = &pseudo_lld_bus;
2678 sdbg_host->dev.parent = &pseudo_primary;
2679 sdbg_host->dev.release = &sdebug_release_adapter;
2680 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2681
2682 error = device_register(&sdbg_host->dev);
2683
2684 if (error)
2685 goto clean;
2686
2687 ++scsi_debug_add_host;
2688 return error;
2689
2690clean:
2691 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
2692 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
2693 dev_list);
2694 list_del(&sdbg_devinfo->dev_list);
2695 kfree(sdbg_devinfo);
2696 }
2697
2698 kfree(sdbg_host);
2699 return error;
2700}
2701
2702static void sdebug_remove_adapter(void)
2703{
2704 struct sdebug_host_info * sdbg_host = NULL;
2705
2706 spin_lock(&sdebug_host_list_lock);
2707 if (!list_empty(&sdebug_host_list)) {
2708 sdbg_host = list_entry(sdebug_host_list.prev,
2709 struct sdebug_host_info, host_list);
2710 list_del(&sdbg_host->host_list);
2711 }
2712 spin_unlock(&sdebug_host_list_lock);
2713
2714 if (!sdbg_host)
2715 return;
2716
2717 device_unregister(&sdbg_host->dev);
2718 --scsi_debug_add_host;
2719}
2720
2721static int sdebug_driver_probe(struct device * dev)
2722{
2723 int error = 0;
2724 struct sdebug_host_info *sdbg_host;
2725 struct Scsi_Host *hpnt;
2726
2727 sdbg_host = to_sdebug_host(dev);
2728
2729 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2730 if (NULL == hpnt) {
2731 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2732 error = -ENODEV;
2733 return error;
2734 }
2735
2736 sdbg_host->shost = hpnt;
2737 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2738 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2739 hpnt->max_id = scsi_debug_num_tgts + 1;
2740 else
2741 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002742 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
2744 error = scsi_add_host(hpnt, &sdbg_host->dev);
2745 if (error) {
2746 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
2747 error = -ENODEV;
2748 scsi_host_put(hpnt);
2749 } else
2750 scsi_scan_host(hpnt);
2751
2752
2753 return error;
2754}
2755
2756static int sdebug_driver_remove(struct device * dev)
2757{
2758 struct list_head *lh, *lh_sf;
2759 struct sdebug_host_info *sdbg_host;
2760 struct sdebug_dev_info *sdbg_devinfo;
2761
2762 sdbg_host = to_sdebug_host(dev);
2763
2764 if (!sdbg_host) {
2765 printk(KERN_ERR "%s: Unable to locate host info\n",
2766 __FUNCTION__);
2767 return -ENODEV;
2768 }
2769
2770 scsi_remove_host(sdbg_host->shost);
2771
2772 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
2773 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
2774 dev_list);
2775 list_del(&sdbg_devinfo->dev_list);
2776 kfree(sdbg_devinfo);
2777 }
2778
2779 scsi_host_put(sdbg_host->shost);
2780 return 0;
2781}
2782
2783static void sdebug_max_tgts_luns(void)
2784{
2785 struct sdebug_host_info * sdbg_host;
2786 struct Scsi_Host *hpnt;
2787
2788 spin_lock(&sdebug_host_list_lock);
2789 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2790 hpnt = sdbg_host->shost;
2791 if ((hpnt->this_id >= 0) &&
2792 (scsi_debug_num_tgts > hpnt->this_id))
2793 hpnt->max_id = scsi_debug_num_tgts + 1;
2794 else
2795 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002796 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 }
2798 spin_unlock(&sdebug_host_list_lock);
2799}