blob: 9c63b00773c43c9be0a4df3b9fc0c055954ae5d3 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/module.h>
28
29#include <linux/kernel.h>
30#include <linux/sched.h>
31#include <linux/errno.h>
32#include <linux/timer.h>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/genhd.h>
36#include <linux/fs.h>
37#include <linux/init.h>
38#include <linux/proc_fs.h>
39#include <linux/smp_lock.h>
40#include <linux/vmalloc.h>
41#include <linux/moduleparam.h>
42
43#include <linux/blkdev.h>
44#include "scsi.h"
45#include <scsi/scsi_host.h>
46#include <scsi/scsicam.h>
47
48#include <linux/stat.h>
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include "scsi_logging.h"
51#include "scsi_debug.h"
52
Douglas Gilbertc65b1442006-06-06 00:11:24 -040053#define SCSI_DEBUG_VERSION "1.79"
54static const char * scsi_debug_version_date = "20060604";
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56/* Additional Sense Code (ASC) used */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040057#define NO_ADDITIONAL_SENSE 0x0
58#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040060#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#define INVALID_OPCODE 0x20
62#define ADDR_OUT_OF_RANGE 0x21
63#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040064#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define POWERON_RESET 0x29
66#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbertc65b1442006-06-06 00:11:24 -040067#define THRESHOLD_EXCEEDED 0x5d
68#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
71
72/* Default values for driver parameters */
73#define DEF_NUM_HOST 1
74#define DEF_NUM_TGTS 1
75#define DEF_MAX_LUNS 1
76/* With these defaults, this driver will make 1 host with 1 target
77 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
78 */
79#define DEF_DELAY 1
80#define DEF_DEV_SIZE_MB 8
81#define DEF_EVERY_NTH 0
82#define DEF_NUM_PARTS 0
83#define DEF_OPTS 0
84#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
85#define DEF_PTYPE 0
86#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040087#define DEF_NO_LUN_0 0
88#define DEF_VIRTUAL_GB 0
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90/* bit mask values for scsi_debug_opts */
91#define SCSI_DEBUG_OPT_NOISE 1
92#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
93#define SCSI_DEBUG_OPT_TIMEOUT 4
94#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
95/* When "every_nth" > 0 then modulo "every_nth" commands:
96 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
97 * - a RECOVERED_ERROR is simulated on successful read and write
98 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
99 *
100 * When "every_nth" < 0 then after "- every_nth" commands:
101 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
102 * - a RECOVERED_ERROR is simulated on successful read and write
103 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
104 * This will continue until some other action occurs (e.g. the user
105 * writing a new value (other than -1 or 1) to every_nth via sysfs).
106 */
107
108/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
109 * sector on read commands: */
110#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
111
112/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
113 * or "peripheral device" addressing (value 0) */
114#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400115#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117static int scsi_debug_add_host = DEF_NUM_HOST;
118static int scsi_debug_delay = DEF_DELAY;
119static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
120static int scsi_debug_every_nth = DEF_EVERY_NTH;
121static int scsi_debug_max_luns = DEF_MAX_LUNS;
122static int scsi_debug_num_parts = DEF_NUM_PARTS;
123static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
124static int scsi_debug_opts = DEF_OPTS;
125static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
126static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
127static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400128static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
129static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131static int scsi_debug_cmnd_count = 0;
132
133#define DEV_READONLY(TGT) (0)
134#define DEV_REMOVEABLE(TGT) (0)
135
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400136static unsigned int sdebug_store_size; /* in bytes */
137static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138static sector_t sdebug_capacity; /* in sectors */
139
140/* old BIOS stuff, kernel may get rid of them but some mode sense pages
141 may still need them */
142static int sdebug_heads; /* heads per disk */
143static int sdebug_cylinders_per; /* cylinders per surface */
144static int sdebug_sectors_per; /* sectors per cylinder */
145
146/* default sector size is 512 bytes, 2**9 bytes */
147#define POW2_SECT_SIZE 9
148#define SECT_SIZE (1 << POW2_SECT_SIZE)
149#define SECT_SIZE_PER(TGT) SECT_SIZE
150
151#define SDEBUG_MAX_PARTS 4
152
153#define SDEBUG_SENSE_LEN 32
154
155struct sdebug_dev_info {
156 struct list_head dev_list;
157 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
158 unsigned int channel;
159 unsigned int target;
160 unsigned int lun;
161 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400162 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400164 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 char used;
166};
167
168struct sdebug_host_info {
169 struct list_head host_list;
170 struct Scsi_Host *shost;
171 struct device dev;
172 struct list_head dev_info_list;
173};
174
175#define to_sdebug_host(d) \
176 container_of(d, struct sdebug_host_info, dev)
177
178static LIST_HEAD(sdebug_host_list);
179static DEFINE_SPINLOCK(sdebug_host_list_lock);
180
181typedef void (* done_funct_t) (struct scsi_cmnd *);
182
183struct sdebug_queued_cmd {
184 int in_use;
185 struct timer_list cmnd_timer;
186 done_funct_t done_funct;
187 struct scsi_cmnd * a_cmnd;
188 int scsi_result;
189};
190static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
191
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100192static struct scsi_host_template sdebug_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 .proc_info = scsi_debug_proc_info,
194 .name = "SCSI DEBUG",
195 .info = scsi_debug_info,
196 .slave_alloc = scsi_debug_slave_alloc,
197 .slave_configure = scsi_debug_slave_configure,
198 .slave_destroy = scsi_debug_slave_destroy,
199 .ioctl = scsi_debug_ioctl,
200 .queuecommand = scsi_debug_queuecommand,
201 .eh_abort_handler = scsi_debug_abort,
202 .eh_bus_reset_handler = scsi_debug_bus_reset,
203 .eh_device_reset_handler = scsi_debug_device_reset,
204 .eh_host_reset_handler = scsi_debug_host_reset,
205 .bios_param = scsi_debug_biosparam,
206 .can_queue = SCSI_DEBUG_CANQUEUE,
207 .this_id = 7,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400208 .sg_tablesize = 256,
209 .cmd_per_lun = 16,
210 .max_sectors = 0xffff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 .unchecked_isa_dma = 0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400212 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 .module = THIS_MODULE,
214};
215
216static unsigned char * fake_storep; /* ramdisk storage */
217
218static int num_aborts = 0;
219static int num_dev_resets = 0;
220static int num_bus_resets = 0;
221static int num_host_resets = 0;
222
223static DEFINE_SPINLOCK(queued_arr_lock);
224static DEFINE_RWLOCK(atomic_rw);
225
226static char sdebug_proc_name[] = "scsi_debug";
227
228static int sdebug_driver_probe(struct device *);
229static int sdebug_driver_remove(struct device *);
230static struct bus_type pseudo_lld_bus;
231
232static struct device_driver sdebug_driverfs_driver = {
233 .name = sdebug_proc_name,
234 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235};
236
237static const int check_condition_result =
238 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
239
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400240static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
241 0, 0, 0x2, 0x4b};
242static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
243 0, 0, 0x0, 0x0};
244
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245/* function declarations */
246static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
247 struct sdebug_dev_info * devip);
248static int resp_requests(struct scsi_cmnd * SCpnt,
249 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400250static int resp_start_stop(struct scsi_cmnd * scp,
251 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252static int resp_readcap(struct scsi_cmnd * SCpnt,
253 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400254static int resp_readcap16(struct scsi_cmnd * SCpnt,
255 struct sdebug_dev_info * devip);
256static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400258static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
259 struct sdebug_dev_info * devip);
260static int resp_log_sense(struct scsi_cmnd * scp,
261 struct sdebug_dev_info * devip);
262static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
263 unsigned int num, struct sdebug_dev_info * devip);
264static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
265 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266static int resp_report_luns(struct scsi_cmnd * SCpnt,
267 struct sdebug_dev_info * devip);
268static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
269 int arr_len);
270static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
271 int max_arr_len);
272static void timer_intr_handler(unsigned long);
273static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
274static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
275 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400276static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
277 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278static int schedule_resp(struct scsi_cmnd * cmnd,
279 struct sdebug_dev_info * devip,
280 done_funct_t done, int scsi_result, int delta_jiff);
281static void __init sdebug_build_parts(unsigned char * ramp);
282static void __init init_all_queued(void);
283static void stop_all_queued(void);
284static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400285static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
286 int dev_id_num, const char * dev_id_str,
287 int dev_id_str_len);
288static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289static void do_create_driverfs_files(void);
290static void do_remove_driverfs_files(void);
291
292static int sdebug_add_adapter(void);
293static void sdebug_remove_adapter(void);
294static void sdebug_max_tgts_luns(void);
295
296static struct device pseudo_primary;
297static struct bus_type pseudo_lld_bus;
298
299
300static
301int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
302{
303 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400304 int len, k, j;
305 unsigned int num;
306 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400308 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 struct sdebug_dev_info * devip = NULL;
310 int inj_recovered = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400311 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 if (done == NULL)
314 return 0; /* assume mid level reprocessing command */
315
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400316 SCpnt->resid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
318 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400319 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 printk("%02x ", (int)cmd[k]);
321 printk("\n");
322 }
323 if(target == sdebug_driver_template.this_id) {
324 printk(KERN_INFO "scsi_debug: initiator's id used as "
325 "target!\n");
326 return schedule_resp(SCpnt, NULL, done,
327 DID_NO_CONNECT << 16, 0);
328 }
329
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400330 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
331 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 return schedule_resp(SCpnt, NULL, done,
333 DID_NO_CONNECT << 16, 0);
334 devip = devInfoReg(SCpnt->device);
335 if (NULL == devip)
336 return schedule_resp(SCpnt, NULL, done,
337 DID_NO_CONNECT << 16, 0);
338
339 if ((scsi_debug_every_nth != 0) &&
340 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
341 scsi_debug_cmnd_count = 0;
342 if (scsi_debug_every_nth < -1)
343 scsi_debug_every_nth = -1;
344 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
345 return 0; /* ignore command causing timeout */
346 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
347 inj_recovered = 1; /* to reads and writes below */
348 }
349
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400350 if (devip->wlun) {
351 switch (*cmd) {
352 case INQUIRY:
353 case REQUEST_SENSE:
354 case TEST_UNIT_READY:
355 case REPORT_LUNS:
356 break; /* only allowable wlun commands */
357 default:
358 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
359 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
360 "not supported for wlun\n", *cmd);
361 mk_sense_buffer(devip, ILLEGAL_REQUEST,
362 INVALID_OPCODE, 0);
363 errsts = check_condition_result;
364 return schedule_resp(SCpnt, devip, done, errsts,
365 0);
366 }
367 }
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 switch (*cmd) {
370 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400371 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 errsts = resp_inquiry(SCpnt, target, devip);
373 break;
374 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400375 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 errsts = resp_requests(SCpnt, devip);
377 break;
378 case REZERO_UNIT: /* actually this is REWIND for SSC */
379 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400380 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 break;
382 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400383 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 break;
385 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
386 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
387 cmd[4] ? "inhibited" : "enabled");
388 break;
389 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400390 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 break;
392 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400393 delay_override = 1;
394 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 break;
396 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400397 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 break;
399 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400400 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 break;
402 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400403 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 break;
405 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400406 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 break;
408 case READ_CAPACITY:
409 errsts = resp_readcap(SCpnt, devip);
410 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400411 case SERVICE_ACTION_IN:
412 if (SAI_READ_CAPACITY_16 != cmd[1]) {
413 mk_sense_buffer(devip, ILLEGAL_REQUEST,
414 INVALID_OPCODE, 0);
415 errsts = check_condition_result;
416 break;
417 }
418 errsts = resp_readcap16(SCpnt, devip);
419 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 case READ_16:
421 case READ_12:
422 case READ_10:
423 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 if ((*cmd) == READ_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400427 for (lba = 0, j = 0; j < 8; ++j) {
428 if (j > 0)
429 lba <<= 8;
430 lba += cmd[2 + j];
431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 num = cmd[13] + (cmd[12] << 8) +
433 (cmd[11] << 16) + (cmd[10] << 24);
434 } else if ((*cmd) == READ_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400435 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 (cmd[3] << 16) + (cmd[2] << 24);
437 num = cmd[9] + (cmd[8] << 8) +
438 (cmd[7] << 16) + (cmd[6] << 24);
439 } else if ((*cmd) == READ_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400440 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 (cmd[3] << 16) + (cmd[2] << 24);
442 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400443 } else { /* READ (6) */
444 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400446 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400448 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 if (inj_recovered && (0 == errsts)) {
450 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400451 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 errsts = check_condition_result;
453 }
454 break;
455 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400456 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 errsts = resp_report_luns(SCpnt, devip);
458 break;
459 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400460 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 break;
462 case WRITE_16:
463 case WRITE_12:
464 case WRITE_10:
465 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400466 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 if ((*cmd) == WRITE_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400469 for (lba = 0, j = 0; j < 8; ++j) {
470 if (j > 0)
471 lba <<= 8;
472 lba += cmd[2 + j];
473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 num = cmd[13] + (cmd[12] << 8) +
475 (cmd[11] << 16) + (cmd[10] << 24);
476 } else if ((*cmd) == WRITE_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400477 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 (cmd[3] << 16) + (cmd[2] << 24);
479 num = cmd[9] + (cmd[8] << 8) +
480 (cmd[7] << 16) + (cmd[6] << 24);
481 } else if ((*cmd) == WRITE_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400482 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 (cmd[3] << 16) + (cmd[2] << 24);
484 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400485 } else { /* WRITE (6) */
486 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400488 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400490 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 if (inj_recovered && (0 == errsts)) {
492 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400493 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 errsts = check_condition_result;
495 }
496 break;
497 case MODE_SENSE:
498 case MODE_SENSE_10:
499 errsts = resp_mode_sense(SCpnt, target, devip);
500 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400501 case MODE_SELECT:
502 errsts = resp_mode_select(SCpnt, 1, devip);
503 break;
504 case MODE_SELECT_10:
505 errsts = resp_mode_select(SCpnt, 0, devip);
506 break;
507 case LOG_SENSE:
508 errsts = resp_log_sense(SCpnt, devip);
509 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400511 delay_override = 1;
512 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 break;
514 default:
515 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
516 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
517 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400518 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 break; /* Unit attention takes precedence */
520 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
521 errsts = check_condition_result;
522 break;
523 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400524 return schedule_resp(SCpnt, devip, done, errsts,
525 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526}
527
528static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
529{
530 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
531 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
532 }
533 return -EINVAL;
534 /* return -ENOTTY; // correct return but upsets fdisk */
535}
536
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400537static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
538 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539{
540 if (devip->reset) {
541 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
542 printk(KERN_INFO "scsi_debug: Reporting Unit "
543 "attention: power on reset\n");
544 devip->reset = 0;
545 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
546 return check_condition_result;
547 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400548 if ((0 == reset_only) && devip->stopped) {
549 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
550 printk(KERN_INFO "scsi_debug: Reporting Not "
551 "ready: initializing command required\n");
552 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
553 0x2);
554 return check_condition_result;
555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 return 0;
557}
558
559/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
560static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
561 int arr_len)
562{
563 int k, req_len, act_len, len, active;
564 void * kaddr;
565 void * kaddr_off;
566 struct scatterlist * sgpnt;
567
568 if (0 == scp->request_bufflen)
569 return 0;
570 if (NULL == scp->request_buffer)
571 return (DID_ERROR << 16);
572 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
573 (scp->sc_data_direction == DMA_FROM_DEVICE)))
574 return (DID_ERROR << 16);
575 if (0 == scp->use_sg) {
576 req_len = scp->request_bufflen;
577 act_len = (req_len < arr_len) ? req_len : arr_len;
578 memcpy(scp->request_buffer, arr, act_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400579 if (scp->resid)
580 scp->resid -= act_len;
581 else
582 scp->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 return 0;
584 }
585 sgpnt = (struct scatterlist *)scp->request_buffer;
586 active = 1;
587 for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) {
588 if (active) {
589 kaddr = (unsigned char *)
590 kmap_atomic(sgpnt->page, KM_USER0);
591 if (NULL == kaddr)
592 return (DID_ERROR << 16);
593 kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
594 len = sgpnt->length;
595 if ((req_len + len) > arr_len) {
596 active = 0;
597 len = arr_len - req_len;
598 }
599 memcpy(kaddr_off, arr + req_len, len);
600 kunmap_atomic(kaddr, KM_USER0);
601 act_len += len;
602 }
603 req_len += sgpnt->length;
604 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400605 if (scp->resid)
606 scp->resid -= act_len;
607 else
608 scp->resid = req_len - act_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 return 0;
610}
611
612/* Returns number of bytes fetched into 'arr' or -1 if error. */
613static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
614 int max_arr_len)
615{
616 int k, req_len, len, fin;
617 void * kaddr;
618 void * kaddr_off;
619 struct scatterlist * sgpnt;
620
621 if (0 == scp->request_bufflen)
622 return 0;
623 if (NULL == scp->request_buffer)
624 return -1;
625 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
626 (scp->sc_data_direction == DMA_TO_DEVICE)))
627 return -1;
628 if (0 == scp->use_sg) {
629 req_len = scp->request_bufflen;
630 len = (req_len < max_arr_len) ? req_len : max_arr_len;
631 memcpy(arr, scp->request_buffer, len);
632 return len;
633 }
634 sgpnt = (struct scatterlist *)scp->request_buffer;
635 for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) {
636 kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0);
637 if (NULL == kaddr)
638 return -1;
639 kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
640 len = sgpnt->length;
641 if ((req_len + len) > max_arr_len) {
642 len = max_arr_len - req_len;
643 fin = 1;
644 }
645 memcpy(arr + req_len, kaddr_off, len);
646 kunmap_atomic(kaddr, KM_USER0);
647 if (fin)
648 return req_len + len;
649 req_len += sgpnt->length;
650 }
651 return req_len;
652}
653
654
655static const char * inq_vendor_id = "Linux ";
656static const char * inq_product_id = "scsi_debug ";
657static const char * inq_product_rev = "0004";
658
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400659static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
660 int dev_id_num, const char * dev_id_str,
661 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400663 int num, port_a;
664 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400666 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 /* T10 vendor identifier field format (faked) */
668 arr[0] = 0x2; /* ASCII */
669 arr[1] = 0x1;
670 arr[2] = 0x0;
671 memcpy(&arr[4], inq_vendor_id, 8);
672 memcpy(&arr[12], inq_product_id, 16);
673 memcpy(&arr[28], dev_id_str, dev_id_str_len);
674 num = 8 + 16 + dev_id_str_len;
675 arr[3] = num;
676 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400677 if (dev_id_num >= 0) {
678 /* NAA-5, Logical unit identifier (binary) */
679 arr[num++] = 0x1; /* binary (not necessarily sas) */
680 arr[num++] = 0x3; /* PIV=0, lu, naa */
681 arr[num++] = 0x0;
682 arr[num++] = 0x8;
683 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
684 arr[num++] = 0x33;
685 arr[num++] = 0x33;
686 arr[num++] = 0x30;
687 arr[num++] = (dev_id_num >> 24);
688 arr[num++] = (dev_id_num >> 16) & 0xff;
689 arr[num++] = (dev_id_num >> 8) & 0xff;
690 arr[num++] = dev_id_num & 0xff;
691 /* Target relative port number */
692 arr[num++] = 0x61; /* proto=sas, binary */
693 arr[num++] = 0x94; /* PIV=1, target port, rel port */
694 arr[num++] = 0x0; /* reserved */
695 arr[num++] = 0x4; /* length */
696 arr[num++] = 0x0; /* reserved */
697 arr[num++] = 0x0; /* reserved */
698 arr[num++] = 0x0;
699 arr[num++] = 0x1; /* relative port A */
700 }
701 /* NAA-5, Target port identifier */
702 arr[num++] = 0x61; /* proto=sas, binary */
703 arr[num++] = 0x93; /* piv=1, target port, naa */
704 arr[num++] = 0x0;
705 arr[num++] = 0x8;
706 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
707 arr[num++] = 0x22;
708 arr[num++] = 0x22;
709 arr[num++] = 0x20;
710 arr[num++] = (port_a >> 24);
711 arr[num++] = (port_a >> 16) & 0xff;
712 arr[num++] = (port_a >> 8) & 0xff;
713 arr[num++] = port_a & 0xff;
714 /* NAA-5, Target device identifier */
715 arr[num++] = 0x61; /* proto=sas, binary */
716 arr[num++] = 0xa3; /* piv=1, target device, naa */
717 arr[num++] = 0x0;
718 arr[num++] = 0x8;
719 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
720 arr[num++] = 0x22;
721 arr[num++] = 0x22;
722 arr[num++] = 0x20;
723 arr[num++] = (target_dev_id >> 24);
724 arr[num++] = (target_dev_id >> 16) & 0xff;
725 arr[num++] = (target_dev_id >> 8) & 0xff;
726 arr[num++] = target_dev_id & 0xff;
727 /* SCSI name string: Target device identifier */
728 arr[num++] = 0x63; /* proto=sas, UTF-8 */
729 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
730 arr[num++] = 0x0;
731 arr[num++] = 24;
732 memcpy(arr + num, "naa.52222220", 12);
733 num += 12;
734 snprintf(b, sizeof(b), "%08X", target_dev_id);
735 memcpy(arr + num, b, 8);
736 num += 8;
737 memset(arr + num, 0, 4);
738 num += 4;
739 return num;
740}
741
742
743static unsigned char vpd84_data[] = {
744/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
745 0x22,0x22,0x22,0x0,0xbb,0x1,
746 0x22,0x22,0x22,0x0,0xbb,0x2,
747};
748
749static int inquiry_evpd_84(unsigned char * arr)
750{
751 memcpy(arr, vpd84_data, sizeof(vpd84_data));
752 return sizeof(vpd84_data);
753}
754
755static int inquiry_evpd_85(unsigned char * arr)
756{
757 int num = 0;
758 const char * na1 = "https://www.kernel.org/config";
759 const char * na2 = "http://www.kernel.org/log";
760 int plen, olen;
761
762 arr[num++] = 0x1; /* lu, storage config */
763 arr[num++] = 0x0; /* reserved */
764 arr[num++] = 0x0;
765 olen = strlen(na1);
766 plen = olen + 1;
767 if (plen % 4)
768 plen = ((plen / 4) + 1) * 4;
769 arr[num++] = plen; /* length, null termianted, padded */
770 memcpy(arr + num, na1, olen);
771 memset(arr + num + olen, 0, plen - olen);
772 num += plen;
773
774 arr[num++] = 0x4; /* lu, logging */
775 arr[num++] = 0x0; /* reserved */
776 arr[num++] = 0x0;
777 olen = strlen(na2);
778 plen = olen + 1;
779 if (plen % 4)
780 plen = ((plen / 4) + 1) * 4;
781 arr[num++] = plen; /* length, null terminated, padded */
782 memcpy(arr + num, na2, olen);
783 memset(arr + num + olen, 0, plen - olen);
784 num += plen;
785
786 return num;
787}
788
789/* SCSI ports VPD page */
790static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
791{
792 int num = 0;
793 int port_a, port_b;
794
795 port_a = target_dev_id + 1;
796 port_b = port_a + 1;
797 arr[num++] = 0x0; /* reserved */
798 arr[num++] = 0x0; /* reserved */
799 arr[num++] = 0x0;
800 arr[num++] = 0x1; /* relative port 1 (primary) */
801 memset(arr + num, 0, 6);
802 num += 6;
803 arr[num++] = 0x0;
804 arr[num++] = 12; /* length tp descriptor */
805 /* naa-5 target port identifier (A) */
806 arr[num++] = 0x61; /* proto=sas, binary */
807 arr[num++] = 0x93; /* PIV=1, target port, NAA */
808 arr[num++] = 0x0; /* reserved */
809 arr[num++] = 0x8; /* length */
810 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
811 arr[num++] = 0x22;
812 arr[num++] = 0x22;
813 arr[num++] = 0x20;
814 arr[num++] = (port_a >> 24);
815 arr[num++] = (port_a >> 16) & 0xff;
816 arr[num++] = (port_a >> 8) & 0xff;
817 arr[num++] = port_a & 0xff;
818
819 arr[num++] = 0x0; /* reserved */
820 arr[num++] = 0x0; /* reserved */
821 arr[num++] = 0x0;
822 arr[num++] = 0x2; /* relative port 2 (secondary) */
823 memset(arr + num, 0, 6);
824 num += 6;
825 arr[num++] = 0x0;
826 arr[num++] = 12; /* length tp descriptor */
827 /* naa-5 target port identifier (B) */
828 arr[num++] = 0x61; /* proto=sas, binary */
829 arr[num++] = 0x93; /* PIV=1, target port, NAA */
830 arr[num++] = 0x0; /* reserved */
831 arr[num++] = 0x8; /* length */
832 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
833 arr[num++] = 0x22;
834 arr[num++] = 0x22;
835 arr[num++] = 0x20;
836 arr[num++] = (port_b >> 24);
837 arr[num++] = (port_b >> 16) & 0xff;
838 arr[num++] = (port_b >> 8) & 0xff;
839 arr[num++] = port_b & 0xff;
840
841 return num;
842}
843
844
845static unsigned char vpd89_data[] = {
846/* from 4th byte */ 0,0,0,0,
847'l','i','n','u','x',' ',' ',' ',
848'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
849'1','2','3','4',
8500x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8510xec,0,0,0,
8520x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
8530,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
8540x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
8550x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
8560x53,0x41,
8570x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8580x20,0x20,
8590x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8600x10,0x80,
8610,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8620x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8630x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8640,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8650x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8660x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8670,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
8680,0,0,0,0,0,0,0,0,0,0,0,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,
8710x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
8720,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
8730xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
8740,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
8750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51,
887};
888
889static int inquiry_evpd_89(unsigned char * arr)
890{
891 memcpy(arr, vpd89_data, sizeof(vpd89_data));
892 return sizeof(vpd89_data);
893}
894
895
896static unsigned char vpdb0_data[] = {
897 /* from 4th byte */ 0,0,0,4,
898 0,0,0x4,0,
899 0,0,0,64,
900};
901
902static int inquiry_evpd_b0(unsigned char * arr)
903{
904 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
905 if (sdebug_store_sectors > 0x400) {
906 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
907 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
908 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
909 arr[7] = sdebug_store_sectors & 0xff;
910 }
911 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912}
913
914
915#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400916#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
918static int resp_inquiry(struct scsi_cmnd * scp, int target,
919 struct sdebug_dev_info * devip)
920{
921 unsigned char pq_pdt;
922 unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
923 unsigned char *cmd = (unsigned char *)scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400924 int alloc_len, n;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 alloc_len = (cmd[3] << 8) + cmd[4];
927 memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400928 if (devip->wlun)
929 pq_pdt = 0x1e; /* present, wlun */
930 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
931 pq_pdt = 0x7f; /* not present, no device type */
932 else
933 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 arr[0] = pq_pdt;
935 if (0x2 & cmd[1]) { /* CMDDT bit set */
936 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
937 0);
938 return check_condition_result;
939 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400940 int lu_id_num, target_dev_id, len;
941 char lu_id_str[6];
942 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400944 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
945 (devip->target * 1000) + devip->lun);
946 target_dev_id = ((host_no + 1) * 2000) +
947 (devip->target * 1000) - 3;
948 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400950 arr[1] = cmd[2]; /*sanity */
951 n = 4;
952 arr[n++] = 0x0; /* this page */
953 arr[n++] = 0x80; /* unit serial number */
954 arr[n++] = 0x83; /* device identification */
955 arr[n++] = 0x84; /* software interface ident. */
956 arr[n++] = 0x85; /* management network addresses */
957 arr[n++] = 0x86; /* extended inquiry */
958 arr[n++] = 0x87; /* mode page policy */
959 arr[n++] = 0x88; /* SCSI ports */
960 arr[n++] = 0x89; /* ATA information */
961 arr[n++] = 0xb0; /* Block limits (SBC) */
962 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400964 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400966 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400968 arr[1] = cmd[2]; /*sanity */
969 arr[3] = inquiry_evpd_83(&arr[4], target_dev_id,
970 lu_id_num, lu_id_str, len);
971 } else if (0x84 == cmd[2]) { /* Software interface ident. */
972 arr[1] = cmd[2]; /*sanity */
973 arr[3] = inquiry_evpd_84(&arr[4]);
974 } else if (0x85 == cmd[2]) { /* Management network addresses */
975 arr[1] = cmd[2]; /*sanity */
976 arr[3] = inquiry_evpd_85(&arr[4]);
977 } else if (0x86 == cmd[2]) { /* extended inquiry */
978 arr[1] = cmd[2]; /*sanity */
979 arr[3] = 0x3c; /* number of following entries */
980 arr[4] = 0x0; /* no protection stuff */
981 arr[5] = 0x7; /* head of q, ordered + simple q's */
982 } else if (0x87 == cmd[2]) { /* mode page policy */
983 arr[1] = cmd[2]; /*sanity */
984 arr[3] = 0x8; /* number of following entries */
985 arr[4] = 0x2; /* disconnect-reconnect mp */
986 arr[6] = 0x80; /* mlus, shared */
987 arr[8] = 0x18; /* protocol specific lu */
988 arr[10] = 0x82; /* mlus, per initiator port */
989 } else if (0x88 == cmd[2]) { /* SCSI Ports */
990 arr[1] = cmd[2]; /*sanity */
991 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
992 } else if (0x89 == cmd[2]) { /* ATA information */
993 arr[1] = cmd[2]; /*sanity */
994 n = inquiry_evpd_89(&arr[4]);
995 arr[2] = (n >> 8);
996 arr[3] = (n & 0xff);
997 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
998 arr[1] = cmd[2]; /*sanity */
999 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 } else {
1001 /* Illegal request, invalid field in cdb */
1002 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1003 INVALID_FIELD_IN_CDB, 0);
1004 return check_condition_result;
1005 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001006 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 return fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001008 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 }
1010 /* drops through here for a standard inquiry */
1011 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1012 arr[2] = scsi_debug_scsi_level;
1013 arr[3] = 2; /* response_data_format==2 */
1014 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001015 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001017 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 memcpy(&arr[8], inq_vendor_id, 8);
1019 memcpy(&arr[16], inq_product_id, 16);
1020 memcpy(&arr[32], inq_product_rev, 4);
1021 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001022 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1023 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1024 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001026 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001028 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001030 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return fill_from_dev_buffer(scp, arr,
1032 min(alloc_len, SDEBUG_LONG_INQ_SZ));
1033}
1034
1035static int resp_requests(struct scsi_cmnd * scp,
1036 struct sdebug_dev_info * devip)
1037{
1038 unsigned char * sbuff;
1039 unsigned char *cmd = (unsigned char *)scp->cmnd;
1040 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001041 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 int len = 18;
1043
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001044 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001046 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1047 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001049 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1050 if (want_dsense) {
1051 arr[0] = 0x72;
1052 arr[1] = 0x0; /* NO_SENSE in sense_key */
1053 arr[2] = THRESHOLD_EXCEEDED;
1054 arr[3] = 0xff; /* TEST set and MRIE==6 */
1055 } else {
1056 arr[0] = 0x70;
1057 arr[2] = 0x0; /* NO_SENSE in sense_key */
1058 arr[7] = 0xa; /* 18 byte sense buffer */
1059 arr[12] = THRESHOLD_EXCEEDED;
1060 arr[13] = 0xff; /* TEST set and MRIE==6 */
1061 }
1062 } else if (devip->stopped) {
1063 if (want_dsense) {
1064 arr[0] = 0x72;
1065 arr[1] = 0x0; /* NO_SENSE in sense_key */
1066 arr[2] = LOW_POWER_COND_ON;
1067 arr[3] = 0x0; /* TEST set and MRIE==6 */
1068 } else {
1069 arr[0] = 0x70;
1070 arr[2] = 0x0; /* NO_SENSE in sense_key */
1071 arr[7] = 0xa; /* 18 byte sense buffer */
1072 arr[12] = LOW_POWER_COND_ON;
1073 arr[13] = 0x0; /* TEST set and MRIE==6 */
1074 }
1075 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001077 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1078 /* DESC bit set and sense_buff in fixed format */
1079 memset(arr, 0, sizeof(arr));
1080 arr[0] = 0x72;
1081 arr[1] = sbuff[2]; /* sense key */
1082 arr[2] = sbuff[12]; /* asc */
1083 arr[3] = sbuff[13]; /* ascq */
1084 len = 8;
1085 }
1086 }
1087 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 return fill_from_dev_buffer(scp, arr, len);
1089}
1090
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091static int resp_start_stop(struct scsi_cmnd * scp,
1092 struct sdebug_dev_info * devip)
1093{
1094 unsigned char *cmd = (unsigned char *)scp->cmnd;
1095 int power_cond, errsts, start;
1096
1097 if ((errsts = check_readiness(scp, 1, devip)))
1098 return errsts;
1099 power_cond = (cmd[4] & 0xf0) >> 4;
1100 if (power_cond) {
1101 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1102 0);
1103 return check_condition_result;
1104 }
1105 start = cmd[4] & 1;
1106 if (start == devip->stopped)
1107 devip->stopped = !start;
1108 return 0;
1109}
1110
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111#define SDEBUG_READCAP_ARR_SZ 8
1112static int resp_readcap(struct scsi_cmnd * scp,
1113 struct sdebug_dev_info * devip)
1114{
1115 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001116 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 int errsts;
1118
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001119 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001121 /* following just in case virtual_gb changed */
1122 if (scsi_debug_virtual_gb > 0) {
1123 sdebug_capacity = 2048 * 1024;
1124 sdebug_capacity *= scsi_debug_virtual_gb;
1125 } else
1126 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001128 if (sdebug_capacity < 0xffffffff) {
1129 capac = (unsigned int)sdebug_capacity - 1;
1130 arr[0] = (capac >> 24);
1131 arr[1] = (capac >> 16) & 0xff;
1132 arr[2] = (capac >> 8) & 0xff;
1133 arr[3] = capac & 0xff;
1134 } else {
1135 arr[0] = 0xff;
1136 arr[1] = 0xff;
1137 arr[2] = 0xff;
1138 arr[3] = 0xff;
1139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1141 arr[7] = SECT_SIZE_PER(target) & 0xff;
1142 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1143}
1144
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001145#define SDEBUG_READCAP16_ARR_SZ 32
1146static int resp_readcap16(struct scsi_cmnd * scp,
1147 struct sdebug_dev_info * devip)
1148{
1149 unsigned char *cmd = (unsigned char *)scp->cmnd;
1150 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1151 unsigned long long capac;
1152 int errsts, k, alloc_len;
1153
1154 if ((errsts = check_readiness(scp, 1, devip)))
1155 return errsts;
1156 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1157 + cmd[13]);
1158 /* following just in case virtual_gb changed */
1159 if (scsi_debug_virtual_gb > 0) {
1160 sdebug_capacity = 2048 * 1024;
1161 sdebug_capacity *= scsi_debug_virtual_gb;
1162 } else
1163 sdebug_capacity = sdebug_store_sectors;
1164 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1165 capac = sdebug_capacity - 1;
1166 for (k = 0; k < 8; ++k, capac >>= 8)
1167 arr[7 - k] = capac & 0xff;
1168 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1169 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1170 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1171 arr[11] = SECT_SIZE_PER(target) & 0xff;
1172 return fill_from_dev_buffer(scp, arr,
1173 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1174}
1175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176/* <<Following mode page info copied from ST318451LW>> */
1177
1178static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1179{ /* Read-Write Error Recovery page for mode_sense */
1180 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1181 5, 0, 0xff, 0xff};
1182
1183 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1184 if (1 == pcontrol)
1185 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1186 return sizeof(err_recov_pg);
1187}
1188
1189static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1190{ /* Disconnect-Reconnect page for mode_sense */
1191 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1192 0, 0, 0, 0, 0, 0, 0, 0};
1193
1194 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1195 if (1 == pcontrol)
1196 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1197 return sizeof(disconnect_pg);
1198}
1199
1200static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1201{ /* Format device page for mode_sense */
1202 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1203 0, 0, 0, 0, 0, 0, 0, 0,
1204 0, 0, 0, 0, 0x40, 0, 0, 0};
1205
1206 memcpy(p, format_pg, sizeof(format_pg));
1207 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1208 p[11] = sdebug_sectors_per & 0xff;
1209 p[12] = (SECT_SIZE >> 8) & 0xff;
1210 p[13] = SECT_SIZE & 0xff;
1211 if (DEV_REMOVEABLE(target))
1212 p[20] |= 0x20; /* should agree with INQUIRY */
1213 if (1 == pcontrol)
1214 memset(p + 2, 0, sizeof(format_pg) - 2);
1215 return sizeof(format_pg);
1216}
1217
1218static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1219{ /* Caching page for mode_sense */
1220 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1221 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1222
1223 memcpy(p, caching_pg, sizeof(caching_pg));
1224 if (1 == pcontrol)
1225 memset(p + 2, 0, sizeof(caching_pg) - 2);
1226 return sizeof(caching_pg);
1227}
1228
1229static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1230{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001231 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1232 0, 0, 0, 0};
1233 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 0, 0, 0x2, 0x4b};
1235
1236 if (scsi_debug_dsense)
1237 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001238 else
1239 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1241 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001242 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1243 else if (2 == pcontrol)
1244 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 return sizeof(ctrl_m_pg);
1246}
1247
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1250{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001251 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1252 0, 0, 0x0, 0x0};
1253 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1254 0, 0, 0x0, 0x0};
1255
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1257 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001258 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1259 else if (2 == pcontrol)
1260 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 return sizeof(iec_m_pg);
1262}
1263
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001264static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1265{ /* SAS SSP mode page - short format for mode_sense */
1266 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1267 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1268
1269 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1270 if (1 == pcontrol)
1271 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1272 return sizeof(sas_sf_m_pg);
1273}
1274
1275
1276static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1277 int target_dev_id)
1278{ /* SAS phy control and discover mode page for mode_sense */
1279 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1280 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1281 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1282 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1283 0x2, 0, 0, 0, 0, 0, 0, 0,
1284 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1285 0, 0, 0, 0, 0, 0, 0, 0,
1286 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1287 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1288 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1289 0x3, 0, 0, 0, 0, 0, 0, 0,
1290 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1291 0, 0, 0, 0, 0, 0, 0, 0,
1292 };
1293 int port_a, port_b;
1294
1295 port_a = target_dev_id + 1;
1296 port_b = port_a + 1;
1297 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1298 p[20] = (port_a >> 24);
1299 p[21] = (port_a >> 16) & 0xff;
1300 p[22] = (port_a >> 8) & 0xff;
1301 p[23] = port_a & 0xff;
1302 p[48 + 20] = (port_b >> 24);
1303 p[48 + 21] = (port_b >> 16) & 0xff;
1304 p[48 + 22] = (port_b >> 8) & 0xff;
1305 p[48 + 23] = port_b & 0xff;
1306 if (1 == pcontrol)
1307 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1308 return sizeof(sas_pcd_m_pg);
1309}
1310
1311static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1312{ /* SAS SSP shared protocol specific port mode subpage */
1313 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1314 0, 0, 0, 0, 0, 0, 0, 0,
1315 };
1316
1317 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1318 if (1 == pcontrol)
1319 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1320 return sizeof(sas_sha_m_pg);
1321}
1322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323#define SDEBUG_MAX_MSENSE_SZ 256
1324
1325static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1326 struct sdebug_dev_info * devip)
1327{
1328 unsigned char dbd;
1329 int pcontrol, pcode, subpcode;
1330 unsigned char dev_spec;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001331 int alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 unsigned char * ap;
1333 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1334 unsigned char *cmd = (unsigned char *)scp->cmnd;
1335
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001336 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 return errsts;
1338 dbd = cmd[1] & 0x8;
1339 pcontrol = (cmd[2] & 0xc0) >> 6;
1340 pcode = cmd[2] & 0x3f;
1341 subpcode = cmd[3];
1342 msense_6 = (MODE_SENSE == cmd[0]);
1343 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1344 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1345 if (0x3 == pcontrol) { /* Saving values not supported */
1346 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1347 0);
1348 return check_condition_result;
1349 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001350 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1351 (devip->target * 1000) - 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
1353 if (msense_6) {
1354 arr[2] = dev_spec;
1355 offset = 4;
1356 } else {
1357 arr[3] = dev_spec;
1358 offset = 8;
1359 }
1360 ap = arr + offset;
1361
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001362 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1363 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1365 0);
1366 return check_condition_result;
1367 }
1368 switch (pcode) {
1369 case 0x1: /* Read-Write error recovery page, direct access */
1370 len = resp_err_recov_pg(ap, pcontrol, target);
1371 offset += len;
1372 break;
1373 case 0x2: /* Disconnect-Reconnect page, all devices */
1374 len = resp_disconnect_pg(ap, pcontrol, target);
1375 offset += len;
1376 break;
1377 case 0x3: /* Format device page, direct access */
1378 len = resp_format_pg(ap, pcontrol, target);
1379 offset += len;
1380 break;
1381 case 0x8: /* Caching page, direct access */
1382 len = resp_caching_pg(ap, pcontrol, target);
1383 offset += len;
1384 break;
1385 case 0xa: /* Control Mode page, all devices */
1386 len = resp_ctrl_m_pg(ap, pcontrol, target);
1387 offset += len;
1388 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001389 case 0x19: /* if spc==1 then sas phy, control+discover */
1390 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1391 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1392 INVALID_FIELD_IN_CDB, 0);
1393 return check_condition_result;
1394 }
1395 len = 0;
1396 if ((0x0 == subpcode) || (0xff == subpcode))
1397 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1398 if ((0x1 == subpcode) || (0xff == subpcode))
1399 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1400 target_dev_id);
1401 if ((0x2 == subpcode) || (0xff == subpcode))
1402 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1403 offset += len;
1404 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 case 0x1c: /* Informational Exceptions Mode page, all devices */
1406 len = resp_iec_m_pg(ap, pcontrol, target);
1407 offset += len;
1408 break;
1409 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001410 if ((0 == subpcode) || (0xff == subpcode)) {
1411 len = resp_err_recov_pg(ap, pcontrol, target);
1412 len += resp_disconnect_pg(ap + len, pcontrol, target);
1413 len += resp_format_pg(ap + len, pcontrol, target);
1414 len += resp_caching_pg(ap + len, pcontrol, target);
1415 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1416 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1417 if (0xff == subpcode) {
1418 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1419 target, target_dev_id);
1420 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1421 }
1422 len += resp_iec_m_pg(ap + len, pcontrol, target);
1423 } else {
1424 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1425 INVALID_FIELD_IN_CDB, 0);
1426 return check_condition_result;
1427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 offset += len;
1429 break;
1430 default:
1431 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1432 0);
1433 return check_condition_result;
1434 }
1435 if (msense_6)
1436 arr[0] = offset - 1;
1437 else {
1438 arr[0] = ((offset - 2) >> 8) & 0xff;
1439 arr[1] = (offset - 2) & 0xff;
1440 }
1441 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1442}
1443
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001444#define SDEBUG_MAX_MSELECT_SZ 512
1445
1446static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1447 struct sdebug_dev_info * devip)
1448{
1449 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1450 int param_len, res, errsts, mpage;
1451 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1452 unsigned char *cmd = (unsigned char *)scp->cmnd;
1453
1454 if ((errsts = check_readiness(scp, 1, devip)))
1455 return errsts;
1456 memset(arr, 0, sizeof(arr));
1457 pf = cmd[1] & 0x10;
1458 sp = cmd[1] & 0x1;
1459 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1460 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1461 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1462 INVALID_FIELD_IN_CDB, 0);
1463 return check_condition_result;
1464 }
1465 res = fetch_to_dev_buffer(scp, arr, param_len);
1466 if (-1 == res)
1467 return (DID_ERROR << 16);
1468 else if ((res < param_len) &&
1469 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1470 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1471 " IO sent=%d bytes\n", param_len, res);
1472 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1473 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
1474 if ((md_len > 2) || (0 != bd_len)) {
1475 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1476 INVALID_FIELD_IN_PARAM_LIST, 0);
1477 return check_condition_result;
1478 }
1479 off = bd_len + (mselect6 ? 4 : 8);
1480 mpage = arr[off] & 0x3f;
1481 ps = !!(arr[off] & 0x80);
1482 if (ps) {
1483 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1484 INVALID_FIELD_IN_PARAM_LIST, 0);
1485 return check_condition_result;
1486 }
1487 spf = !!(arr[off] & 0x40);
1488 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1489 (arr[off + 1] + 2);
1490 if ((pg_len + off) > param_len) {
1491 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1492 PARAMETER_LIST_LENGTH_ERR, 0);
1493 return check_condition_result;
1494 }
1495 switch (mpage) {
1496 case 0xa: /* Control Mode page */
1497 if (ctrl_m_pg[1] == arr[off + 1]) {
1498 memcpy(ctrl_m_pg + 2, arr + off + 2,
1499 sizeof(ctrl_m_pg) - 2);
1500 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1501 return 0;
1502 }
1503 break;
1504 case 0x1c: /* Informational Exceptions Mode page */
1505 if (iec_m_pg[1] == arr[off + 1]) {
1506 memcpy(iec_m_pg + 2, arr + off + 2,
1507 sizeof(iec_m_pg) - 2);
1508 return 0;
1509 }
1510 break;
1511 default:
1512 break;
1513 }
1514 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1515 INVALID_FIELD_IN_PARAM_LIST, 0);
1516 return check_condition_result;
1517}
1518
1519static int resp_temp_l_pg(unsigned char * arr)
1520{
1521 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1522 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1523 };
1524
1525 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1526 return sizeof(temp_l_pg);
1527}
1528
1529static int resp_ie_l_pg(unsigned char * arr)
1530{
1531 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1532 };
1533
1534 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1535 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1536 arr[4] = THRESHOLD_EXCEEDED;
1537 arr[5] = 0xff;
1538 }
1539 return sizeof(ie_l_pg);
1540}
1541
1542#define SDEBUG_MAX_LSENSE_SZ 512
1543
1544static int resp_log_sense(struct scsi_cmnd * scp,
1545 struct sdebug_dev_info * devip)
1546{
1547 int ppc, sp, pcontrol, pcode, alloc_len, errsts, len, n;
1548 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1549 unsigned char *cmd = (unsigned char *)scp->cmnd;
1550
1551 if ((errsts = check_readiness(scp, 1, devip)))
1552 return errsts;
1553 memset(arr, 0, sizeof(arr));
1554 ppc = cmd[1] & 0x2;
1555 sp = cmd[1] & 0x1;
1556 if (ppc || sp) {
1557 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1558 INVALID_FIELD_IN_CDB, 0);
1559 return check_condition_result;
1560 }
1561 pcontrol = (cmd[2] & 0xc0) >> 6;
1562 pcode = cmd[2] & 0x3f;
1563 alloc_len = (cmd[7] << 8) + cmd[8];
1564 arr[0] = pcode;
1565 switch (pcode) {
1566 case 0x0: /* Supported log pages log page */
1567 n = 4;
1568 arr[n++] = 0x0; /* this page */
1569 arr[n++] = 0xd; /* Temperature */
1570 arr[n++] = 0x2f; /* Informational exceptions */
1571 arr[3] = n - 4;
1572 break;
1573 case 0xd: /* Temperature log page */
1574 arr[3] = resp_temp_l_pg(arr + 4);
1575 break;
1576 case 0x2f: /* Informational exceptions log page */
1577 arr[3] = resp_ie_l_pg(arr + 4);
1578 break;
1579 default:
1580 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1581 INVALID_FIELD_IN_CDB, 0);
1582 return check_condition_result;
1583 }
1584 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1585 return fill_from_dev_buffer(scp, arr,
1586 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1587}
1588
1589static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1590 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591{
1592 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001593 unsigned int block, from_bottom;
1594 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 int ret;
1596
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001597 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1599 0);
1600 return check_condition_result;
1601 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001602 /* transfer length excessive (tie in to block limits VPD page) */
1603 if (num > sdebug_store_sectors) {
1604 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1605 0);
1606 return check_condition_result;
1607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001609 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1610 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1611 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1613 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001614 /* set info field and valid bit for fixed descriptor */
1615 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1616 devip->sense_buff[0] |= 0x80; /* Valid bit */
1617 ret = OPT_MEDIUM_ERR_ADDR;
1618 devip->sense_buff[3] = (ret >> 24) & 0xff;
1619 devip->sense_buff[4] = (ret >> 16) & 0xff;
1620 devip->sense_buff[5] = (ret >> 8) & 0xff;
1621 devip->sense_buff[6] = ret & 0xff;
1622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 return check_condition_result;
1624 }
1625 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001626 if ((lba + num) <= sdebug_store_sectors)
1627 ret = fill_from_dev_buffer(SCpnt,
1628 fake_storep + (lba * SECT_SIZE),
1629 num * SECT_SIZE);
1630 else {
1631 /* modulo when one arg is 64 bits needs do_div() */
1632 u = lba;
1633 block = do_div(u, sdebug_store_sectors);
1634 from_bottom = 0;
1635 if ((block + num) > sdebug_store_sectors)
1636 from_bottom = (block + num) - sdebug_store_sectors;
1637 ret = fill_from_dev_buffer(SCpnt,
1638 fake_storep + (block * SECT_SIZE),
1639 (num - from_bottom) * SECT_SIZE);
1640 if ((0 == ret) && (from_bottom > 0))
1641 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1642 from_bottom * SECT_SIZE);
1643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 read_unlock_irqrestore(&atomic_rw, iflags);
1645 return ret;
1646}
1647
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001648static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1649 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650{
1651 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001652 unsigned int block, to_bottom;
1653 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 int res;
1655
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001656 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1658 0);
1659 return check_condition_result;
1660 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001661 /* transfer length excessive (tie in to block limits VPD page) */
1662 if (num > sdebug_store_sectors) {
1663 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1664 0);
1665 return check_condition_result;
1666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
1668 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001669 if ((lba + num) <= sdebug_store_sectors)
1670 res = fetch_to_dev_buffer(SCpnt,
1671 fake_storep + (lba * SECT_SIZE),
1672 num * SECT_SIZE);
1673 else {
1674 /* modulo when one arg is 64 bits needs do_div() */
1675 u = lba;
1676 block = do_div(u, sdebug_store_sectors);
1677 to_bottom = 0;
1678 if ((block + num) > sdebug_store_sectors)
1679 to_bottom = (block + num) - sdebug_store_sectors;
1680 res = fetch_to_dev_buffer(SCpnt,
1681 fake_storep + (block * SECT_SIZE),
1682 (num - to_bottom) * SECT_SIZE);
1683 if ((0 == res) && (to_bottom > 0))
1684 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1685 to_bottom * SECT_SIZE);
1686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 write_unlock_irqrestore(&atomic_rw, iflags);
1688 if (-1 == res)
1689 return (DID_ERROR << 16);
1690 else if ((res < (num * SECT_SIZE)) &&
1691 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001692 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1694 return 0;
1695}
1696
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001697#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698
1699static int resp_report_luns(struct scsi_cmnd * scp,
1700 struct sdebug_dev_info * devip)
1701{
1702 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001703 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 unsigned char *cmd = (unsigned char *)scp->cmnd;
1705 int select_report = (int)cmd[2];
1706 struct scsi_lun *one_lun;
1707 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001708 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
1710 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001711 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1713 0);
1714 return check_condition_result;
1715 }
1716 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1717 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1718 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001719 if (1 == select_report)
1720 lun_cnt = 0;
1721 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1722 --lun_cnt;
1723 wlun = (select_report > 0) ? 1 : 0;
1724 num = lun_cnt + wlun;
1725 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1726 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1727 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1728 sizeof(struct scsi_lun)), num);
1729 if (n < num) {
1730 wlun = 0;
1731 lun_cnt = n;
1732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001734 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1735 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1736 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1737 i++, lun++) {
1738 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 if (upper)
1740 one_lun[i].scsi_lun[0] =
1741 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001742 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001744 if (wlun) {
1745 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1746 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1747 i++;
1748 }
1749 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 return fill_from_dev_buffer(scp, arr,
1751 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1752}
1753
1754/* When timer goes off this function is called. */
1755static void timer_intr_handler(unsigned long indx)
1756{
1757 struct sdebug_queued_cmd * sqcp;
1758 unsigned long iflags;
1759
1760 if (indx >= SCSI_DEBUG_CANQUEUE) {
1761 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1762 "large\n");
1763 return;
1764 }
1765 spin_lock_irqsave(&queued_arr_lock, iflags);
1766 sqcp = &queued_arr[(int)indx];
1767 if (! sqcp->in_use) {
1768 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1769 "interrupt\n");
1770 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1771 return;
1772 }
1773 sqcp->in_use = 0;
1774 if (sqcp->done_funct) {
1775 sqcp->a_cmnd->result = sqcp->scsi_result;
1776 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1777 }
1778 sqcp->done_funct = NULL;
1779 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1780}
1781
1782static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1783{
1784 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001785 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1786 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 return 0;
1788}
1789
1790static int scsi_debug_slave_configure(struct scsi_device * sdp)
1791{
1792 struct sdebug_dev_info * devip;
1793
1794 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001795 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
1796 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
1798 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
1799 devip = devInfoReg(sdp);
1800 sdp->hostdata = devip;
1801 if (sdp->host->cmd_per_lun)
1802 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
1803 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001804 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 return 0;
1806}
1807
1808static void scsi_debug_slave_destroy(struct scsi_device * sdp)
1809{
1810 struct sdebug_dev_info * devip =
1811 (struct sdebug_dev_info *)sdp->hostdata;
1812
1813 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001814 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
1815 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 if (devip) {
1817 /* make this slot avaliable for re-use */
1818 devip->used = 0;
1819 sdp->hostdata = NULL;
1820 }
1821}
1822
1823static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
1824{
1825 struct sdebug_host_info * sdbg_host;
1826 struct sdebug_dev_info * open_devip = NULL;
1827 struct sdebug_dev_info * devip =
1828 (struct sdebug_dev_info *)sdev->hostdata;
1829
1830 if (devip)
1831 return devip;
1832 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
1833 if(! sdbg_host) {
1834 printk(KERN_ERR "Host info NULL\n");
1835 return NULL;
1836 }
1837 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
1838 if ((devip->used) && (devip->channel == sdev->channel) &&
1839 (devip->target == sdev->id) &&
1840 (devip->lun == sdev->lun))
1841 return devip;
1842 else {
1843 if ((!devip->used) && (!open_devip))
1844 open_devip = devip;
1845 }
1846 }
1847 if (NULL == open_devip) { /* try and make a new one */
Jes Sorensen24669f752006-01-16 10:31:18 -05001848 open_devip = kzalloc(sizeof(*open_devip),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 if (NULL == open_devip) {
1850 printk(KERN_ERR "%s: out of memory at line %d\n",
1851 __FUNCTION__, __LINE__);
1852 return NULL;
1853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 open_devip->sdbg_host = sdbg_host;
1855 list_add_tail(&open_devip->dev_list,
1856 &sdbg_host->dev_info_list);
1857 }
1858 if (open_devip) {
1859 open_devip->channel = sdev->channel;
1860 open_devip->target = sdev->id;
1861 open_devip->lun = sdev->lun;
1862 open_devip->sdbg_host = sdbg_host;
1863 open_devip->reset = 1;
1864 open_devip->used = 1;
1865 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
1866 if (scsi_debug_dsense)
1867 open_devip->sense_buff[0] = 0x72;
1868 else {
1869 open_devip->sense_buff[0] = 0x70;
1870 open_devip->sense_buff[7] = 0xa;
1871 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001872 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
1873 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 return open_devip;
1875 }
1876 return NULL;
1877}
1878
1879static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
1880 int asc, int asq)
1881{
1882 unsigned char * sbuff;
1883
1884 sbuff = devip->sense_buff;
1885 memset(sbuff, 0, SDEBUG_SENSE_LEN);
1886 if (scsi_debug_dsense) {
1887 sbuff[0] = 0x72; /* descriptor, current */
1888 sbuff[1] = key;
1889 sbuff[2] = asc;
1890 sbuff[3] = asq;
1891 } else {
1892 sbuff[0] = 0x70; /* fixed, current */
1893 sbuff[2] = key;
1894 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
1895 sbuff[12] = asc;
1896 sbuff[13] = asq;
1897 }
1898 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1899 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
1900 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
1901}
1902
1903static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
1904{
1905 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1906 printk(KERN_INFO "scsi_debug: abort\n");
1907 ++num_aborts;
1908 stop_queued_cmnd(SCpnt);
1909 return SUCCESS;
1910}
1911
1912static int scsi_debug_biosparam(struct scsi_device *sdev,
1913 struct block_device * bdev, sector_t capacity, int *info)
1914{
1915 int res;
1916 unsigned char *buf;
1917
1918 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1919 printk(KERN_INFO "scsi_debug: biosparam\n");
1920 buf = scsi_bios_ptable(bdev);
1921 if (buf) {
1922 res = scsi_partsize(buf, capacity,
1923 &info[2], &info[0], &info[1]);
1924 kfree(buf);
1925 if (! res)
1926 return res;
1927 }
1928 info[0] = sdebug_heads;
1929 info[1] = sdebug_sectors_per;
1930 info[2] = sdebug_cylinders_per;
1931 return 0;
1932}
1933
1934static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
1935{
1936 struct sdebug_dev_info * devip;
1937
1938 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1939 printk(KERN_INFO "scsi_debug: device_reset\n");
1940 ++num_dev_resets;
1941 if (SCpnt) {
1942 devip = devInfoReg(SCpnt->device);
1943 if (devip)
1944 devip->reset = 1;
1945 }
1946 return SUCCESS;
1947}
1948
1949static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
1950{
1951 struct sdebug_host_info *sdbg_host;
1952 struct sdebug_dev_info * dev_info;
1953 struct scsi_device * sdp;
1954 struct Scsi_Host * hp;
1955
1956 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1957 printk(KERN_INFO "scsi_debug: bus_reset\n");
1958 ++num_bus_resets;
1959 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
1960 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
1961 if (sdbg_host) {
1962 list_for_each_entry(dev_info,
1963 &sdbg_host->dev_info_list,
1964 dev_list)
1965 dev_info->reset = 1;
1966 }
1967 }
1968 return SUCCESS;
1969}
1970
1971static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
1972{
1973 struct sdebug_host_info * sdbg_host;
1974 struct sdebug_dev_info * dev_info;
1975
1976 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
1977 printk(KERN_INFO "scsi_debug: host_reset\n");
1978 ++num_host_resets;
1979 spin_lock(&sdebug_host_list_lock);
1980 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
1981 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
1982 dev_list)
1983 dev_info->reset = 1;
1984 }
1985 spin_unlock(&sdebug_host_list_lock);
1986 stop_all_queued();
1987 return SUCCESS;
1988}
1989
1990/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
1991static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
1992{
1993 unsigned long iflags;
1994 int k;
1995 struct sdebug_queued_cmd * sqcp;
1996
1997 spin_lock_irqsave(&queued_arr_lock, iflags);
1998 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
1999 sqcp = &queued_arr[k];
2000 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2001 del_timer_sync(&sqcp->cmnd_timer);
2002 sqcp->in_use = 0;
2003 sqcp->a_cmnd = NULL;
2004 break;
2005 }
2006 }
2007 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2008 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2009}
2010
2011/* Deletes (stops) timers of all queued commands */
2012static void stop_all_queued(void)
2013{
2014 unsigned long iflags;
2015 int k;
2016 struct sdebug_queued_cmd * sqcp;
2017
2018 spin_lock_irqsave(&queued_arr_lock, iflags);
2019 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2020 sqcp = &queued_arr[k];
2021 if (sqcp->in_use && sqcp->a_cmnd) {
2022 del_timer_sync(&sqcp->cmnd_timer);
2023 sqcp->in_use = 0;
2024 sqcp->a_cmnd = NULL;
2025 }
2026 }
2027 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2028}
2029
2030/* Initializes timers in queued array */
2031static void __init init_all_queued(void)
2032{
2033 unsigned long iflags;
2034 int k;
2035 struct sdebug_queued_cmd * sqcp;
2036
2037 spin_lock_irqsave(&queued_arr_lock, iflags);
2038 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2039 sqcp = &queued_arr[k];
2040 init_timer(&sqcp->cmnd_timer);
2041 sqcp->in_use = 0;
2042 sqcp->a_cmnd = NULL;
2043 }
2044 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2045}
2046
2047static void __init sdebug_build_parts(unsigned char * ramp)
2048{
2049 struct partition * pp;
2050 int starts[SDEBUG_MAX_PARTS + 2];
2051 int sectors_per_part, num_sectors, k;
2052 int heads_by_sects, start_sec, end_sec;
2053
2054 /* assume partition table already zeroed */
2055 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2056 return;
2057 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2058 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2059 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2060 "partitions to %d\n", SDEBUG_MAX_PARTS);
2061 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002062 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 sectors_per_part = (num_sectors - sdebug_sectors_per)
2064 / scsi_debug_num_parts;
2065 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2066 starts[0] = sdebug_sectors_per;
2067 for (k = 1; k < scsi_debug_num_parts; ++k)
2068 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2069 * heads_by_sects;
2070 starts[scsi_debug_num_parts] = num_sectors;
2071 starts[scsi_debug_num_parts + 1] = 0;
2072
2073 ramp[510] = 0x55; /* magic partition markings */
2074 ramp[511] = 0xAA;
2075 pp = (struct partition *)(ramp + 0x1be);
2076 for (k = 0; starts[k + 1]; ++k, ++pp) {
2077 start_sec = starts[k];
2078 end_sec = starts[k + 1] - 1;
2079 pp->boot_ind = 0;
2080
2081 pp->cyl = start_sec / heads_by_sects;
2082 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2083 / sdebug_sectors_per;
2084 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2085
2086 pp->end_cyl = end_sec / heads_by_sects;
2087 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2088 / sdebug_sectors_per;
2089 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2090
2091 pp->start_sect = start_sec;
2092 pp->nr_sects = end_sec - start_sec + 1;
2093 pp->sys_ind = 0x83; /* plain Linux partition */
2094 }
2095}
2096
2097static int schedule_resp(struct scsi_cmnd * cmnd,
2098 struct sdebug_dev_info * devip,
2099 done_funct_t done, int scsi_result, int delta_jiff)
2100{
2101 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2102 if (scsi_result) {
2103 struct scsi_device * sdp = cmnd->device;
2104
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002105 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2106 "non-zero result=0x%x\n", sdp->host->host_no,
2107 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 }
2109 }
2110 if (cmnd && devip) {
2111 /* simulate autosense by this driver */
2112 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2113 memcpy(cmnd->sense_buffer, devip->sense_buff,
2114 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2115 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2116 }
2117 if (delta_jiff <= 0) {
2118 if (cmnd)
2119 cmnd->result = scsi_result;
2120 if (done)
2121 done(cmnd);
2122 return 0;
2123 } else {
2124 unsigned long iflags;
2125 int k;
2126 struct sdebug_queued_cmd * sqcp = NULL;
2127
2128 spin_lock_irqsave(&queued_arr_lock, iflags);
2129 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2130 sqcp = &queued_arr[k];
2131 if (! sqcp->in_use)
2132 break;
2133 }
2134 if (k >= SCSI_DEBUG_CANQUEUE) {
2135 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2136 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2137 return 1; /* report busy to mid level */
2138 }
2139 sqcp->in_use = 1;
2140 sqcp->a_cmnd = cmnd;
2141 sqcp->scsi_result = scsi_result;
2142 sqcp->done_funct = done;
2143 sqcp->cmnd_timer.function = timer_intr_handler;
2144 sqcp->cmnd_timer.data = k;
2145 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2146 add_timer(&sqcp->cmnd_timer);
2147 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2148 if (cmnd)
2149 cmnd->result = 0;
2150 return 0;
2151 }
2152}
2153
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002154module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2155module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2156module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2157module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2158module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
2159module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2160module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2161module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2162module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2163module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2164module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2165module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2166module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
2168MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2169MODULE_DESCRIPTION("SCSI debug adapter driver");
2170MODULE_LICENSE("GPL");
2171MODULE_VERSION(SCSI_DEBUG_VERSION);
2172
2173MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2174MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002175MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2176MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002178MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2179MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002181MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
2182MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2184MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002185MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186
2187
2188static char sdebug_info[256];
2189
2190static const char * scsi_debug_info(struct Scsi_Host * shp)
2191{
2192 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2193 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2194 scsi_debug_version_date, scsi_debug_dev_size_mb,
2195 scsi_debug_opts);
2196 return sdebug_info;
2197}
2198
2199/* scsi_debug_proc_info
2200 * Used if the driver currently has no own support for /proc/scsi
2201 */
2202static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2203 int length, int inout)
2204{
2205 int len, pos, begin;
2206 int orig_length;
2207
2208 orig_length = length;
2209
2210 if (inout == 1) {
2211 char arr[16];
2212 int minLen = length > 15 ? 15 : length;
2213
2214 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2215 return -EACCES;
2216 memcpy(arr, buffer, minLen);
2217 arr[minLen] = '\0';
2218 if (1 != sscanf(arr, "%d", &pos))
2219 return -EINVAL;
2220 scsi_debug_opts = pos;
2221 if (scsi_debug_every_nth != 0)
2222 scsi_debug_cmnd_count = 0;
2223 return length;
2224 }
2225 begin = 0;
2226 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2227 "%s [%s]\n"
2228 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2229 "every_nth=%d(curr:%d)\n"
2230 "delay=%d, max_luns=%d, scsi_level=%d\n"
2231 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2232 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2233 "host_resets=%d\n",
2234 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2235 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2236 scsi_debug_cmnd_count, scsi_debug_delay,
2237 scsi_debug_max_luns, scsi_debug_scsi_level,
2238 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2239 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2240 if (pos < offset) {
2241 len = 0;
2242 begin = pos;
2243 }
2244 *start = buffer + (offset - begin); /* Start of wanted data */
2245 len -= (offset - begin);
2246 if (len > length)
2247 len = length;
2248 return len;
2249}
2250
2251static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2252{
2253 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2254}
2255
2256static ssize_t sdebug_delay_store(struct device_driver * ddp,
2257 const char * buf, size_t count)
2258{
2259 int delay;
2260 char work[20];
2261
2262 if (1 == sscanf(buf, "%10s", work)) {
2263 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2264 scsi_debug_delay = delay;
2265 return count;
2266 }
2267 }
2268 return -EINVAL;
2269}
2270DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2271 sdebug_delay_store);
2272
2273static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2274{
2275 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2276}
2277
2278static ssize_t sdebug_opts_store(struct device_driver * ddp,
2279 const char * buf, size_t count)
2280{
2281 int opts;
2282 char work[20];
2283
2284 if (1 == sscanf(buf, "%10s", work)) {
2285 if (0 == strnicmp(work,"0x", 2)) {
2286 if (1 == sscanf(&work[2], "%x", &opts))
2287 goto opts_done;
2288 } else {
2289 if (1 == sscanf(work, "%d", &opts))
2290 goto opts_done;
2291 }
2292 }
2293 return -EINVAL;
2294opts_done:
2295 scsi_debug_opts = opts;
2296 scsi_debug_cmnd_count = 0;
2297 return count;
2298}
2299DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2300 sdebug_opts_store);
2301
2302static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2303{
2304 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2305}
2306static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2307 const char * buf, size_t count)
2308{
2309 int n;
2310
2311 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2312 scsi_debug_ptype = n;
2313 return count;
2314 }
2315 return -EINVAL;
2316}
2317DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2318
2319static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2320{
2321 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2322}
2323static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2324 const char * buf, size_t count)
2325{
2326 int n;
2327
2328 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2329 scsi_debug_dsense = n;
2330 return count;
2331 }
2332 return -EINVAL;
2333}
2334DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2335 sdebug_dsense_store);
2336
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002337static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2338{
2339 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2340}
2341static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2342 const char * buf, size_t count)
2343{
2344 int n;
2345
2346 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2347 scsi_debug_no_lun_0 = n;
2348 return count;
2349 }
2350 return -EINVAL;
2351}
2352DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2353 sdebug_no_lun_0_store);
2354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2356{
2357 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2358}
2359static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2360 const char * buf, size_t count)
2361{
2362 int n;
2363
2364 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2365 scsi_debug_num_tgts = n;
2366 sdebug_max_tgts_luns();
2367 return count;
2368 }
2369 return -EINVAL;
2370}
2371DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2372 sdebug_num_tgts_store);
2373
2374static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2375{
2376 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2377}
2378DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2379
2380static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2381{
2382 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2383}
2384DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2385
2386static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2387{
2388 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2389}
2390static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2391 const char * buf, size_t count)
2392{
2393 int nth;
2394
2395 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2396 scsi_debug_every_nth = nth;
2397 scsi_debug_cmnd_count = 0;
2398 return count;
2399 }
2400 return -EINVAL;
2401}
2402DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2403 sdebug_every_nth_store);
2404
2405static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2406{
2407 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2408}
2409static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2410 const char * buf, size_t count)
2411{
2412 int n;
2413
2414 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2415 scsi_debug_max_luns = n;
2416 sdebug_max_tgts_luns();
2417 return count;
2418 }
2419 return -EINVAL;
2420}
2421DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2422 sdebug_max_luns_store);
2423
2424static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2425{
2426 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2427}
2428DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2429
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002430static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2431{
2432 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2433}
2434static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2435 const char * buf, size_t count)
2436{
2437 int n;
2438
2439 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2440 scsi_debug_virtual_gb = n;
2441 if (scsi_debug_virtual_gb > 0) {
2442 sdebug_capacity = 2048 * 1024;
2443 sdebug_capacity *= scsi_debug_virtual_gb;
2444 } else
2445 sdebug_capacity = sdebug_store_sectors;
2446 return count;
2447 }
2448 return -EINVAL;
2449}
2450DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2451 sdebug_virtual_gb_store);
2452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2454{
2455 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2456}
2457
2458static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2459 const char * buf, size_t count)
2460{
2461 int delta_hosts;
2462 char work[20];
2463
2464 if (1 != sscanf(buf, "%10s", work))
2465 return -EINVAL;
2466 { /* temporary hack around sscanf() problem with -ve nums */
2467 int neg = 0;
2468
2469 if ('-' == *work)
2470 neg = 1;
2471 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2472 return -EINVAL;
2473 if (neg)
2474 delta_hosts = -delta_hosts;
2475 }
2476 if (delta_hosts > 0) {
2477 do {
2478 sdebug_add_adapter();
2479 } while (--delta_hosts);
2480 } else if (delta_hosts < 0) {
2481 do {
2482 sdebug_remove_adapter();
2483 } while (++delta_hosts);
2484 }
2485 return count;
2486}
2487DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2488 sdebug_add_host_store);
2489
2490static void do_create_driverfs_files(void)
2491{
2492 driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2493 driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2494 driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2495 driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2496 driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2497 driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
2498 driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
2499 driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2500 driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2501 driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2502 driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2503}
2504
2505static void do_remove_driverfs_files(void)
2506{
2507 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2508 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2509 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2510 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2511 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
2512 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
2513 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2514 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2515 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2516 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2517 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2518}
2519
2520static int __init scsi_debug_init(void)
2521{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002522 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 int host_to_add;
2524 int k;
2525
2526 if (scsi_debug_dev_size_mb < 1)
2527 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002528 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2529 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2530 if (scsi_debug_virtual_gb > 0) {
2531 sdebug_capacity = 2048 * 1024;
2532 sdebug_capacity *= scsi_debug_virtual_gb;
2533 } else
2534 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535
2536 /* play around with geometry, don't waste too much on track 0 */
2537 sdebug_heads = 8;
2538 sdebug_sectors_per = 32;
2539 if (scsi_debug_dev_size_mb >= 16)
2540 sdebug_heads = 32;
2541 else if (scsi_debug_dev_size_mb >= 256)
2542 sdebug_heads = 64;
2543 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2544 (sdebug_sectors_per * sdebug_heads);
2545 if (sdebug_cylinders_per >= 1024) {
2546 /* other LLDs do this; implies >= 1GB ram disk ... */
2547 sdebug_heads = 255;
2548 sdebug_sectors_per = 63;
2549 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2550 (sdebug_sectors_per * sdebug_heads);
2551 }
2552
2553 sz = sdebug_store_size;
2554 fake_storep = vmalloc(sz);
2555 if (NULL == fake_storep) {
2556 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2557 return -ENOMEM;
2558 }
2559 memset(fake_storep, 0, sz);
2560 if (scsi_debug_num_parts > 0)
2561 sdebug_build_parts(fake_storep);
2562
2563 init_all_queued();
2564
2565 device_register(&pseudo_primary);
2566 bus_register(&pseudo_lld_bus);
2567 driver_register(&sdebug_driverfs_driver);
2568 do_create_driverfs_files();
2569
2570 sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
2571
2572 host_to_add = scsi_debug_add_host;
2573 scsi_debug_add_host = 0;
2574
2575 for (k = 0; k < host_to_add; k++) {
2576 if (sdebug_add_adapter()) {
2577 printk(KERN_ERR "scsi_debug_init: "
2578 "sdebug_add_adapter failed k=%d\n", k);
2579 break;
2580 }
2581 }
2582
2583 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2584 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2585 scsi_debug_add_host);
2586 }
2587 return 0;
2588}
2589
2590static void __exit scsi_debug_exit(void)
2591{
2592 int k = scsi_debug_add_host;
2593
2594 stop_all_queued();
2595 for (; k; k--)
2596 sdebug_remove_adapter();
2597 do_remove_driverfs_files();
2598 driver_unregister(&sdebug_driverfs_driver);
2599 bus_unregister(&pseudo_lld_bus);
2600 device_unregister(&pseudo_primary);
2601
2602 vfree(fake_storep);
2603}
2604
2605device_initcall(scsi_debug_init);
2606module_exit(scsi_debug_exit);
2607
Adrian Bunk52c1da32005-06-23 22:05:33 -07002608static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609{
2610 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2611 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2612}
2613
2614static struct device pseudo_primary = {
2615 .bus_id = "pseudo_0",
2616 .release = pseudo_0_release,
2617};
2618
2619static int pseudo_lld_bus_match(struct device *dev,
2620 struct device_driver *dev_driver)
2621{
2622 return 1;
2623}
2624
2625static struct bus_type pseudo_lld_bus = {
2626 .name = "pseudo",
2627 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002628 .probe = sdebug_driver_probe,
2629 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630};
2631
2632static void sdebug_release_adapter(struct device * dev)
2633{
2634 struct sdebug_host_info *sdbg_host;
2635
2636 sdbg_host = to_sdebug_host(dev);
2637 kfree(sdbg_host);
2638}
2639
2640static int sdebug_add_adapter(void)
2641{
2642 int k, devs_per_host;
2643 int error = 0;
2644 struct sdebug_host_info *sdbg_host;
2645 struct sdebug_dev_info *sdbg_devinfo;
2646 struct list_head *lh, *lh_sf;
2647
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002648 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 if (NULL == sdbg_host) {
2651 printk(KERN_ERR "%s: out of memory at line %d\n",
2652 __FUNCTION__, __LINE__);
2653 return -ENOMEM;
2654 }
2655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2657
2658 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2659 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002660 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 if (NULL == sdbg_devinfo) {
2662 printk(KERN_ERR "%s: out of memory at line %d\n",
2663 __FUNCTION__, __LINE__);
2664 error = -ENOMEM;
2665 goto clean;
2666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 sdbg_devinfo->sdbg_host = sdbg_host;
2668 list_add_tail(&sdbg_devinfo->dev_list,
2669 &sdbg_host->dev_info_list);
2670 }
2671
2672 spin_lock(&sdebug_host_list_lock);
2673 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2674 spin_unlock(&sdebug_host_list_lock);
2675
2676 sdbg_host->dev.bus = &pseudo_lld_bus;
2677 sdbg_host->dev.parent = &pseudo_primary;
2678 sdbg_host->dev.release = &sdebug_release_adapter;
2679 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2680
2681 error = device_register(&sdbg_host->dev);
2682
2683 if (error)
2684 goto clean;
2685
2686 ++scsi_debug_add_host;
2687 return error;
2688
2689clean:
2690 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
2691 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
2692 dev_list);
2693 list_del(&sdbg_devinfo->dev_list);
2694 kfree(sdbg_devinfo);
2695 }
2696
2697 kfree(sdbg_host);
2698 return error;
2699}
2700
2701static void sdebug_remove_adapter(void)
2702{
2703 struct sdebug_host_info * sdbg_host = NULL;
2704
2705 spin_lock(&sdebug_host_list_lock);
2706 if (!list_empty(&sdebug_host_list)) {
2707 sdbg_host = list_entry(sdebug_host_list.prev,
2708 struct sdebug_host_info, host_list);
2709 list_del(&sdbg_host->host_list);
2710 }
2711 spin_unlock(&sdebug_host_list_lock);
2712
2713 if (!sdbg_host)
2714 return;
2715
2716 device_unregister(&sdbg_host->dev);
2717 --scsi_debug_add_host;
2718}
2719
2720static int sdebug_driver_probe(struct device * dev)
2721{
2722 int error = 0;
2723 struct sdebug_host_info *sdbg_host;
2724 struct Scsi_Host *hpnt;
2725
2726 sdbg_host = to_sdebug_host(dev);
2727
2728 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
2729 if (NULL == hpnt) {
2730 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
2731 error = -ENODEV;
2732 return error;
2733 }
2734
2735 sdbg_host->shost = hpnt;
2736 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
2737 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
2738 hpnt->max_id = scsi_debug_num_tgts + 1;
2739 else
2740 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002741 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
2743 error = scsi_add_host(hpnt, &sdbg_host->dev);
2744 if (error) {
2745 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
2746 error = -ENODEV;
2747 scsi_host_put(hpnt);
2748 } else
2749 scsi_scan_host(hpnt);
2750
2751
2752 return error;
2753}
2754
2755static int sdebug_driver_remove(struct device * dev)
2756{
2757 struct list_head *lh, *lh_sf;
2758 struct sdebug_host_info *sdbg_host;
2759 struct sdebug_dev_info *sdbg_devinfo;
2760
2761 sdbg_host = to_sdebug_host(dev);
2762
2763 if (!sdbg_host) {
2764 printk(KERN_ERR "%s: Unable to locate host info\n",
2765 __FUNCTION__);
2766 return -ENODEV;
2767 }
2768
2769 scsi_remove_host(sdbg_host->shost);
2770
2771 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
2772 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
2773 dev_list);
2774 list_del(&sdbg_devinfo->dev_list);
2775 kfree(sdbg_devinfo);
2776 }
2777
2778 scsi_host_put(sdbg_host->shost);
2779 return 0;
2780}
2781
2782static void sdebug_max_tgts_luns(void)
2783{
2784 struct sdebug_host_info * sdbg_host;
2785 struct Scsi_Host *hpnt;
2786
2787 spin_lock(&sdebug_host_list_lock);
2788 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2789 hpnt = sdbg_host->shost;
2790 if ((hpnt->this_id >= 0) &&
2791 (scsi_debug_num_tgts > hpnt->this_id))
2792 hpnt->max_id = scsi_debug_num_tgts + 1;
2793 else
2794 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002795 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 }
2797 spin_unlock(&sdebug_host_list_lock);
2798}