blob: 82c06f0a9d0201ae42deb14bec2f2f0f4a239fa9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
9 * This version is more generic, simulating a variable number of disk
Douglas Gilbert23183912006-09-16 20:30:47 -040010 * (or disk like devices) sharing a common amount of RAM. To be more
11 * realistic, the simulated devices have the transport attributes of
12 * SAS disks.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
14 *
15 * For documentation see http://www.torque.net/sg/sdebug26.html
16 *
17 * D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
18 * dpg: work for devfs large number of disks [20010809]
19 * forked for lk 2.5 series [20011216, 20020101]
20 * use vmalloc() more inquiry+mode_sense [20020302]
21 * add timers for delayed responses [20020721]
22 * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
23 * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
24 * dpg: change style of boot options to "scsi_debug.num_tgts=2" and
25 * module options to "modprobe scsi_debug num_tgts=2" [20021221]
26 */
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/module.h>
29
30#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/errno.h>
32#include <linux/timer.h>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/genhd.h>
36#include <linux/fs.h>
37#include <linux/init.h>
38#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/vmalloc.h>
40#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020041#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include <linux/blkdev.h>
44#include "scsi.h"
45#include <scsi/scsi_host.h>
46#include <scsi/scsicam.h>
47
48#include <linux/stat.h>
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include "scsi_logging.h"
51#include "scsi_debug.h"
52
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050053#define SCSI_DEBUG_VERSION "1.81"
54static const char * scsi_debug_version_date = "20070104";
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050056/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040057#define NO_ADDITIONAL_SENSE 0x0
58#define LOGICAL_UNIT_NOT_READY 0x4
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040060#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#define INVALID_OPCODE 0x20
62#define ADDR_OUT_OF_RANGE 0x21
63#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040064#define INVALID_FIELD_IN_PARAM_LIST 0x26
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define POWERON_RESET 0x29
66#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050067#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040068#define THRESHOLD_EXCEEDED 0x5d
69#define LOW_POWER_COND_ON 0x5e
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050071/* Additional Sense Code Qualifier (ASCQ) */
72#define ACK_NAK_TO 0x3
73
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
75
76/* Default values for driver parameters */
77#define DEF_NUM_HOST 1
78#define DEF_NUM_TGTS 1
79#define DEF_MAX_LUNS 1
80/* With these defaults, this driver will make 1 host with 1 target
81 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
82 */
83#define DEF_DELAY 1
84#define DEF_DEV_SIZE_MB 8
85#define DEF_EVERY_NTH 0
86#define DEF_NUM_PARTS 0
87#define DEF_OPTS 0
88#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
89#define DEF_PTYPE 0
90#define DEF_D_SENSE 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define DEF_NO_LUN_0 0
92#define DEF_VIRTUAL_GB 0
Douglas Gilbert23183912006-09-16 20:30:47 -040093#define DEF_FAKE_RW 0
94#define DEF_VPD_USE_HOSTNO 1
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96/* bit mask values for scsi_debug_opts */
97#define SCSI_DEBUG_OPT_NOISE 1
98#define SCSI_DEBUG_OPT_MEDIUM_ERR 2
99#define SCSI_DEBUG_OPT_TIMEOUT 4
100#define SCSI_DEBUG_OPT_RECOVERED_ERR 8
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500101#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102/* When "every_nth" > 0 then modulo "every_nth" commands:
103 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
104 * - a RECOVERED_ERROR is simulated on successful read and write
105 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500106 * - a TRANSPORT_ERROR is simulated on successful read and write
107 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 *
109 * When "every_nth" < 0 then after "- every_nth" commands:
110 * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
111 * - a RECOVERED_ERROR is simulated on successful read and write
112 * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500113 * - a TRANSPORT_ERROR is simulated on successful read and write
114 * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 * This will continue until some other action occurs (e.g. the user
116 * writing a new value (other than -1 or 1) to every_nth via sysfs).
117 */
118
119/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
120 * sector on read commands: */
121#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
122
123/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
124 * or "peripheral device" addressing (value 0) */
125#define SAM2_LUN_ADDRESS_METHOD 0
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400126#define SAM2_WLUN_REPORT_LUNS 0xc101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128static int scsi_debug_add_host = DEF_NUM_HOST;
129static int scsi_debug_delay = DEF_DELAY;
130static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
131static int scsi_debug_every_nth = DEF_EVERY_NTH;
132static int scsi_debug_max_luns = DEF_MAX_LUNS;
133static int scsi_debug_num_parts = DEF_NUM_PARTS;
134static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
135static int scsi_debug_opts = DEF_OPTS;
136static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
137static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
138static int scsi_debug_dsense = DEF_D_SENSE;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400139static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
140static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
Douglas Gilbert23183912006-09-16 20:30:47 -0400141static int scsi_debug_fake_rw = DEF_FAKE_RW;
142static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144static int scsi_debug_cmnd_count = 0;
145
146#define DEV_READONLY(TGT) (0)
147#define DEV_REMOVEABLE(TGT) (0)
148
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400149static unsigned int sdebug_store_size; /* in bytes */
150static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static sector_t sdebug_capacity; /* in sectors */
152
153/* old BIOS stuff, kernel may get rid of them but some mode sense pages
154 may still need them */
155static int sdebug_heads; /* heads per disk */
156static int sdebug_cylinders_per; /* cylinders per surface */
157static int sdebug_sectors_per; /* sectors per cylinder */
158
159/* default sector size is 512 bytes, 2**9 bytes */
160#define POW2_SECT_SIZE 9
161#define SECT_SIZE (1 << POW2_SECT_SIZE)
162#define SECT_SIZE_PER(TGT) SECT_SIZE
163
164#define SDEBUG_MAX_PARTS 4
165
166#define SDEBUG_SENSE_LEN 32
167
168struct sdebug_dev_info {
169 struct list_head dev_list;
170 unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */
171 unsigned int channel;
172 unsigned int target;
173 unsigned int lun;
174 struct sdebug_host_info *sdbg_host;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400175 unsigned int wlun;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 char reset;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400177 char stopped;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 char used;
179};
180
181struct sdebug_host_info {
182 struct list_head host_list;
183 struct Scsi_Host *shost;
184 struct device dev;
185 struct list_head dev_info_list;
186};
187
188#define to_sdebug_host(d) \
189 container_of(d, struct sdebug_host_info, dev)
190
191static LIST_HEAD(sdebug_host_list);
192static DEFINE_SPINLOCK(sdebug_host_list_lock);
193
194typedef void (* done_funct_t) (struct scsi_cmnd *);
195
196struct sdebug_queued_cmd {
197 int in_use;
198 struct timer_list cmnd_timer;
199 done_funct_t done_funct;
200 struct scsi_cmnd * a_cmnd;
201 int scsi_result;
202};
203static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
204
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100205static struct scsi_host_template sdebug_driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 .proc_info = scsi_debug_proc_info,
207 .name = "SCSI DEBUG",
208 .info = scsi_debug_info,
209 .slave_alloc = scsi_debug_slave_alloc,
210 .slave_configure = scsi_debug_slave_configure,
211 .slave_destroy = scsi_debug_slave_destroy,
212 .ioctl = scsi_debug_ioctl,
213 .queuecommand = scsi_debug_queuecommand,
214 .eh_abort_handler = scsi_debug_abort,
215 .eh_bus_reset_handler = scsi_debug_bus_reset,
216 .eh_device_reset_handler = scsi_debug_device_reset,
217 .eh_host_reset_handler = scsi_debug_host_reset,
218 .bios_param = scsi_debug_biosparam,
219 .can_queue = SCSI_DEBUG_CANQUEUE,
220 .this_id = 7,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400221 .sg_tablesize = 256,
222 .cmd_per_lun = 16,
223 .max_sectors = 0xffff,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 .unchecked_isa_dma = 0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400225 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 .module = THIS_MODULE,
227};
228
229static unsigned char * fake_storep; /* ramdisk storage */
230
231static int num_aborts = 0;
232static int num_dev_resets = 0;
233static int num_bus_resets = 0;
234static int num_host_resets = 0;
235
236static DEFINE_SPINLOCK(queued_arr_lock);
237static DEFINE_RWLOCK(atomic_rw);
238
239static char sdebug_proc_name[] = "scsi_debug";
240
241static int sdebug_driver_probe(struct device *);
242static int sdebug_driver_remove(struct device *);
243static struct bus_type pseudo_lld_bus;
244
245static struct device_driver sdebug_driverfs_driver = {
246 .name = sdebug_proc_name,
247 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248};
249
250static const int check_condition_result =
251 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
252
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400253static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
254 0, 0, 0x2, 0x4b};
255static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
256 0, 0, 0x0, 0x0};
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258/* function declarations */
259static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
260 struct sdebug_dev_info * devip);
261static int resp_requests(struct scsi_cmnd * SCpnt,
262 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400263static int resp_start_stop(struct scsi_cmnd * scp,
264 struct sdebug_dev_info * devip);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200265static int resp_report_tgtpgs(struct scsi_cmnd * scp,
266 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267static int resp_readcap(struct scsi_cmnd * SCpnt,
268 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400269static int resp_readcap16(struct scsi_cmnd * SCpnt,
270 struct sdebug_dev_info * devip);
271static int resp_mode_sense(struct scsi_cmnd * scp, int target,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 struct sdebug_dev_info * devip);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400273static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
274 struct sdebug_dev_info * devip);
275static int resp_log_sense(struct scsi_cmnd * scp,
276 struct sdebug_dev_info * devip);
277static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
278 unsigned int num, struct sdebug_dev_info * devip);
279static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
280 unsigned int num, struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281static int resp_report_luns(struct scsi_cmnd * SCpnt,
282 struct sdebug_dev_info * devip);
283static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
284 int arr_len);
285static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
286 int max_arr_len);
287static void timer_intr_handler(unsigned long);
288static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
289static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
290 int asc, int asq);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400291static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
292 struct sdebug_dev_info * devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293static int schedule_resp(struct scsi_cmnd * cmnd,
294 struct sdebug_dev_info * devip,
295 done_funct_t done, int scsi_result, int delta_jiff);
296static void __init sdebug_build_parts(unsigned char * ramp);
297static void __init init_all_queued(void);
298static void stop_all_queued(void);
299static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200300static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
301 int target_dev_id, int dev_id_num,
302 const char * dev_id_str, int dev_id_str_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400303static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
Randy Dunlap6ecaff72006-07-11 20:53:22 -0700304static int do_create_driverfs_files(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305static void do_remove_driverfs_files(void);
306
307static int sdebug_add_adapter(void);
308static void sdebug_remove_adapter(void);
309static void sdebug_max_tgts_luns(void);
310
311static struct device pseudo_primary;
312static struct bus_type pseudo_lld_bus;
313
314
315static
316int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
317{
318 unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400319 int len, k, j;
320 unsigned int num;
321 unsigned long long lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 int errsts = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400323 int target = SCpnt->device->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 struct sdebug_dev_info * devip = NULL;
325 int inj_recovered = 0;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500326 int inj_transport = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400327 int delay_override = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 if (done == NULL)
330 return 0; /* assume mid level reprocessing command */
331
Boaz Harroshc73961e2007-09-07 06:50:20 +0900332 scsi_set_resid(SCpnt, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
334 printk(KERN_INFO "scsi_debug: cmd ");
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400335 for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 printk("%02x ", (int)cmd[k]);
337 printk("\n");
338 }
339 if(target == sdebug_driver_template.this_id) {
340 printk(KERN_INFO "scsi_debug: initiator's id used as "
341 "target!\n");
342 return schedule_resp(SCpnt, NULL, done,
343 DID_NO_CONNECT << 16, 0);
344 }
345
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400346 if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
347 (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return schedule_resp(SCpnt, NULL, done,
349 DID_NO_CONNECT << 16, 0);
350 devip = devInfoReg(SCpnt->device);
351 if (NULL == devip)
352 return schedule_resp(SCpnt, NULL, done,
353 DID_NO_CONNECT << 16, 0);
354
355 if ((scsi_debug_every_nth != 0) &&
356 (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
357 scsi_debug_cmnd_count = 0;
358 if (scsi_debug_every_nth < -1)
359 scsi_debug_every_nth = -1;
360 if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
361 return 0; /* ignore command causing timeout */
362 else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
363 inj_recovered = 1; /* to reads and writes below */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500364 else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
365 inj_transport = 1; /* to reads and writes below */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 }
367
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400368 if (devip->wlun) {
369 switch (*cmd) {
370 case INQUIRY:
371 case REQUEST_SENSE:
372 case TEST_UNIT_READY:
373 case REPORT_LUNS:
374 break; /* only allowable wlun commands */
375 default:
376 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
377 printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
378 "not supported for wlun\n", *cmd);
379 mk_sense_buffer(devip, ILLEGAL_REQUEST,
380 INVALID_OPCODE, 0);
381 errsts = check_condition_result;
382 return schedule_resp(SCpnt, devip, done, errsts,
383 0);
384 }
385 }
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 switch (*cmd) {
388 case INQUIRY: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400389 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 errsts = resp_inquiry(SCpnt, target, devip);
391 break;
392 case REQUEST_SENSE: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400393 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 errsts = resp_requests(SCpnt, devip);
395 break;
396 case REZERO_UNIT: /* actually this is REWIND for SSC */
397 case START_STOP:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400398 errsts = resp_start_stop(SCpnt, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 break;
400 case ALLOW_MEDIUM_REMOVAL:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400401 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 break;
403 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
404 printk(KERN_INFO "scsi_debug: Medium removal %s\n",
405 cmd[4] ? "inhibited" : "enabled");
406 break;
407 case SEND_DIAGNOSTIC: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400408 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 break;
410 case TEST_UNIT_READY: /* mandatory */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400411 delay_override = 1;
412 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 break;
414 case RESERVE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400415 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 break;
417 case RESERVE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400418 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 break;
420 case RELEASE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400421 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 break;
423 case RELEASE_10:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400424 errsts = check_readiness(SCpnt, 1, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 break;
426 case READ_CAPACITY:
427 errsts = resp_readcap(SCpnt, devip);
428 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400429 case SERVICE_ACTION_IN:
430 if (SAI_READ_CAPACITY_16 != cmd[1]) {
431 mk_sense_buffer(devip, ILLEGAL_REQUEST,
432 INVALID_OPCODE, 0);
433 errsts = check_condition_result;
434 break;
435 }
436 errsts = resp_readcap16(SCpnt, devip);
437 break;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200438 case MAINTENANCE_IN:
439 if (MI_REPORT_TARGET_PGS != cmd[1]) {
440 mk_sense_buffer(devip, ILLEGAL_REQUEST,
441 INVALID_OPCODE, 0);
442 errsts = check_condition_result;
443 break;
444 }
445 errsts = resp_report_tgtpgs(SCpnt, devip);
446 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 case READ_16:
448 case READ_12:
449 case READ_10:
450 case READ_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400451 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400453 if (scsi_debug_fake_rw)
454 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 if ((*cmd) == READ_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400456 for (lba = 0, j = 0; j < 8; ++j) {
457 if (j > 0)
458 lba <<= 8;
459 lba += cmd[2 + j];
460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 num = cmd[13] + (cmd[12] << 8) +
462 (cmd[11] << 16) + (cmd[10] << 24);
463 } else if ((*cmd) == READ_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400464 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 (cmd[3] << 16) + (cmd[2] << 24);
466 num = cmd[9] + (cmd[8] << 8) +
467 (cmd[7] << 16) + (cmd[6] << 24);
468 } else if ((*cmd) == READ_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400469 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 (cmd[3] << 16) + (cmd[2] << 24);
471 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400472 } else { /* READ (6) */
473 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400475 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400477 errsts = resp_read(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 if (inj_recovered && (0 == errsts)) {
479 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400480 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 errsts = check_condition_result;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500482 } else if (inj_transport && (0 == errsts)) {
483 mk_sense_buffer(devip, ABORTED_COMMAND,
484 TRANSPORT_PROBLEM, ACK_NAK_TO);
485 errsts = check_condition_result;
486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 break;
488 case REPORT_LUNS: /* mandatory, ignore unit attention */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400489 delay_override = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 errsts = resp_report_luns(SCpnt, devip);
491 break;
492 case VERIFY: /* 10 byte SBC-2 command */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400493 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 break;
495 case WRITE_16:
496 case WRITE_12:
497 case WRITE_10:
498 case WRITE_6:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400499 if ((errsts = check_readiness(SCpnt, 0, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 break;
Douglas Gilbert23183912006-09-16 20:30:47 -0400501 if (scsi_debug_fake_rw)
502 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 if ((*cmd) == WRITE_16) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400504 for (lba = 0, j = 0; j < 8; ++j) {
505 if (j > 0)
506 lba <<= 8;
507 lba += cmd[2 + j];
508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 num = cmd[13] + (cmd[12] << 8) +
510 (cmd[11] << 16) + (cmd[10] << 24);
511 } else if ((*cmd) == WRITE_12) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400512 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 (cmd[3] << 16) + (cmd[2] << 24);
514 num = cmd[9] + (cmd[8] << 8) +
515 (cmd[7] << 16) + (cmd[6] << 24);
516 } else if ((*cmd) == WRITE_10) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400517 lba = cmd[5] + (cmd[4] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 (cmd[3] << 16) + (cmd[2] << 24);
519 num = cmd[8] + (cmd[7] << 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400520 } else { /* WRITE (6) */
521 lba = cmd[3] + (cmd[2] << 8) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 ((cmd[1] & 0x1f) << 16);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400523 num = (0 == cmd[4]) ? 256 : cmd[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400525 errsts = resp_write(SCpnt, lba, num, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 if (inj_recovered && (0 == errsts)) {
527 mk_sense_buffer(devip, RECOVERED_ERROR,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400528 THRESHOLD_EXCEEDED, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 errsts = check_condition_result;
530 }
531 break;
532 case MODE_SENSE:
533 case MODE_SENSE_10:
534 errsts = resp_mode_sense(SCpnt, target, devip);
535 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400536 case MODE_SELECT:
537 errsts = resp_mode_select(SCpnt, 1, devip);
538 break;
539 case MODE_SELECT_10:
540 errsts = resp_mode_select(SCpnt, 0, devip);
541 break;
542 case LOG_SENSE:
543 errsts = resp_log_sense(SCpnt, devip);
544 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 case SYNCHRONIZE_CACHE:
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400546 delay_override = 1;
547 errsts = check_readiness(SCpnt, 0, devip);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 break;
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500549 case WRITE_BUFFER:
550 errsts = check_readiness(SCpnt, 1, devip);
551 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 default:
553 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
554 printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
555 "supported\n", *cmd);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400556 if ((errsts = check_readiness(SCpnt, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 break; /* Unit attention takes precedence */
558 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
559 errsts = check_condition_result;
560 break;
561 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400562 return schedule_resp(SCpnt, devip, done, errsts,
563 (delay_override ? 0 : scsi_debug_delay));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564}
565
566static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
567{
568 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
569 printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
570 }
571 return -EINVAL;
572 /* return -ENOTTY; // correct return but upsets fdisk */
573}
574
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400575static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
576 struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 if (devip->reset) {
579 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
580 printk(KERN_INFO "scsi_debug: Reporting Unit "
581 "attention: power on reset\n");
582 devip->reset = 0;
583 mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
584 return check_condition_result;
585 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400586 if ((0 == reset_only) && devip->stopped) {
587 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
588 printk(KERN_INFO "scsi_debug: Reporting Not "
589 "ready: initializing command required\n");
590 mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
591 0x2);
592 return check_condition_result;
593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return 0;
595}
596
597/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
598static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
599 int arr_len)
600{
601 int k, req_len, act_len, len, active;
602 void * kaddr;
603 void * kaddr_off;
Jens Axboe852e0342007-07-16 10:19:24 +0200604 struct scatterlist * sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Boaz Harroshc73961e2007-09-07 06:50:20 +0900606 if (0 == scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 return 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900608 if (NULL == scsi_sglist(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 return (DID_ERROR << 16);
610 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
611 (scp->sc_data_direction == DMA_FROM_DEVICE)))
612 return (DID_ERROR << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 active = 1;
Jens Axboe852e0342007-07-16 10:19:24 +0200614 req_len = act_len = 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900615 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 if (active) {
617 kaddr = (unsigned char *)
Jens Axboe45711f12007-10-22 21:19:53 +0200618 kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 if (NULL == kaddr)
620 return (DID_ERROR << 16);
Jens Axboe852e0342007-07-16 10:19:24 +0200621 kaddr_off = (unsigned char *)kaddr + sg->offset;
622 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if ((req_len + len) > arr_len) {
624 active = 0;
625 len = arr_len - req_len;
626 }
627 memcpy(kaddr_off, arr + req_len, len);
628 kunmap_atomic(kaddr, KM_USER0);
629 act_len += len;
630 }
Jens Axboe852e0342007-07-16 10:19:24 +0200631 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 }
Boaz Harroshc73961e2007-09-07 06:50:20 +0900633 if (scsi_get_resid(scp))
634 scsi_set_resid(scp, scsi_get_resid(scp) - act_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400635 else
Boaz Harroshc73961e2007-09-07 06:50:20 +0900636 scsi_set_resid(scp, req_len - act_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 return 0;
638}
639
640/* Returns number of bytes fetched into 'arr' or -1 if error. */
641static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
642 int max_arr_len)
643{
644 int k, req_len, len, fin;
645 void * kaddr;
646 void * kaddr_off;
Jens Axboe852e0342007-07-16 10:19:24 +0200647 struct scatterlist * sg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Boaz Harroshc73961e2007-09-07 06:50:20 +0900649 if (0 == scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900651 if (NULL == scsi_sglist(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 return -1;
653 if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
654 (scp->sc_data_direction == DMA_TO_DEVICE)))
655 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200656 req_len = fin = 0;
Boaz Harroshc73961e2007-09-07 06:50:20 +0900657 scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) {
Jens Axboe45711f12007-10-22 21:19:53 +0200658 kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 if (NULL == kaddr)
660 return -1;
Jens Axboe852e0342007-07-16 10:19:24 +0200661 kaddr_off = (unsigned char *)kaddr + sg->offset;
662 len = sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 if ((req_len + len) > max_arr_len) {
664 len = max_arr_len - req_len;
665 fin = 1;
666 }
667 memcpy(arr + req_len, kaddr_off, len);
668 kunmap_atomic(kaddr, KM_USER0);
669 if (fin)
670 return req_len + len;
Jens Axboe852e0342007-07-16 10:19:24 +0200671 req_len += sg->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 }
673 return req_len;
674}
675
676
677static const char * inq_vendor_id = "Linux ";
678static const char * inq_product_id = "scsi_debug ";
679static const char * inq_product_rev = "0004";
680
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200681static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
682 int target_dev_id, int dev_id_num,
683 const char * dev_id_str,
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400684 int dev_id_str_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400686 int num, port_a;
687 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400689 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 /* T10 vendor identifier field format (faked) */
691 arr[0] = 0x2; /* ASCII */
692 arr[1] = 0x1;
693 arr[2] = 0x0;
694 memcpy(&arr[4], inq_vendor_id, 8);
695 memcpy(&arr[12], inq_product_id, 16);
696 memcpy(&arr[28], dev_id_str, dev_id_str_len);
697 num = 8 + 16 + dev_id_str_len;
698 arr[3] = num;
699 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400700 if (dev_id_num >= 0) {
701 /* NAA-5, Logical unit identifier (binary) */
702 arr[num++] = 0x1; /* binary (not necessarily sas) */
703 arr[num++] = 0x3; /* PIV=0, lu, naa */
704 arr[num++] = 0x0;
705 arr[num++] = 0x8;
706 arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
707 arr[num++] = 0x33;
708 arr[num++] = 0x33;
709 arr[num++] = 0x30;
710 arr[num++] = (dev_id_num >> 24);
711 arr[num++] = (dev_id_num >> 16) & 0xff;
712 arr[num++] = (dev_id_num >> 8) & 0xff;
713 arr[num++] = dev_id_num & 0xff;
714 /* Target relative port number */
715 arr[num++] = 0x61; /* proto=sas, binary */
716 arr[num++] = 0x94; /* PIV=1, target port, rel port */
717 arr[num++] = 0x0; /* reserved */
718 arr[num++] = 0x4; /* length */
719 arr[num++] = 0x0; /* reserved */
720 arr[num++] = 0x0; /* reserved */
721 arr[num++] = 0x0;
722 arr[num++] = 0x1; /* relative port A */
723 }
724 /* NAA-5, Target port identifier */
725 arr[num++] = 0x61; /* proto=sas, binary */
726 arr[num++] = 0x93; /* piv=1, target port, naa */
727 arr[num++] = 0x0;
728 arr[num++] = 0x8;
729 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
730 arr[num++] = 0x22;
731 arr[num++] = 0x22;
732 arr[num++] = 0x20;
733 arr[num++] = (port_a >> 24);
734 arr[num++] = (port_a >> 16) & 0xff;
735 arr[num++] = (port_a >> 8) & 0xff;
736 arr[num++] = port_a & 0xff;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200737 /* NAA-5, Target port group identifier */
738 arr[num++] = 0x61; /* proto=sas, binary */
739 arr[num++] = 0x95; /* piv=1, target port group id */
740 arr[num++] = 0x0;
741 arr[num++] = 0x4;
742 arr[num++] = 0;
743 arr[num++] = 0;
744 arr[num++] = (port_group_id >> 8) & 0xff;
745 arr[num++] = port_group_id & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400746 /* NAA-5, Target device identifier */
747 arr[num++] = 0x61; /* proto=sas, binary */
748 arr[num++] = 0xa3; /* piv=1, target device, naa */
749 arr[num++] = 0x0;
750 arr[num++] = 0x8;
751 arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
752 arr[num++] = 0x22;
753 arr[num++] = 0x22;
754 arr[num++] = 0x20;
755 arr[num++] = (target_dev_id >> 24);
756 arr[num++] = (target_dev_id >> 16) & 0xff;
757 arr[num++] = (target_dev_id >> 8) & 0xff;
758 arr[num++] = target_dev_id & 0xff;
759 /* SCSI name string: Target device identifier */
760 arr[num++] = 0x63; /* proto=sas, UTF-8 */
761 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
762 arr[num++] = 0x0;
763 arr[num++] = 24;
764 memcpy(arr + num, "naa.52222220", 12);
765 num += 12;
766 snprintf(b, sizeof(b), "%08X", target_dev_id);
767 memcpy(arr + num, b, 8);
768 num += 8;
769 memset(arr + num, 0, 4);
770 num += 4;
771 return num;
772}
773
774
775static unsigned char vpd84_data[] = {
776/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
777 0x22,0x22,0x22,0x0,0xbb,0x1,
778 0x22,0x22,0x22,0x0,0xbb,0x2,
779};
780
781static int inquiry_evpd_84(unsigned char * arr)
782{
783 memcpy(arr, vpd84_data, sizeof(vpd84_data));
784 return sizeof(vpd84_data);
785}
786
787static int inquiry_evpd_85(unsigned char * arr)
788{
789 int num = 0;
790 const char * na1 = "https://www.kernel.org/config";
791 const char * na2 = "http://www.kernel.org/log";
792 int plen, olen;
793
794 arr[num++] = 0x1; /* lu, storage config */
795 arr[num++] = 0x0; /* reserved */
796 arr[num++] = 0x0;
797 olen = strlen(na1);
798 plen = olen + 1;
799 if (plen % 4)
800 plen = ((plen / 4) + 1) * 4;
801 arr[num++] = plen; /* length, null termianted, padded */
802 memcpy(arr + num, na1, olen);
803 memset(arr + num + olen, 0, plen - olen);
804 num += plen;
805
806 arr[num++] = 0x4; /* lu, logging */
807 arr[num++] = 0x0; /* reserved */
808 arr[num++] = 0x0;
809 olen = strlen(na2);
810 plen = olen + 1;
811 if (plen % 4)
812 plen = ((plen / 4) + 1) * 4;
813 arr[num++] = plen; /* length, null terminated, padded */
814 memcpy(arr + num, na2, olen);
815 memset(arr + num + olen, 0, plen - olen);
816 num += plen;
817
818 return num;
819}
820
821/* SCSI ports VPD page */
822static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
823{
824 int num = 0;
825 int port_a, port_b;
826
827 port_a = target_dev_id + 1;
828 port_b = port_a + 1;
829 arr[num++] = 0x0; /* reserved */
830 arr[num++] = 0x0; /* reserved */
831 arr[num++] = 0x0;
832 arr[num++] = 0x1; /* relative port 1 (primary) */
833 memset(arr + num, 0, 6);
834 num += 6;
835 arr[num++] = 0x0;
836 arr[num++] = 12; /* length tp descriptor */
837 /* naa-5 target port identifier (A) */
838 arr[num++] = 0x61; /* proto=sas, binary */
839 arr[num++] = 0x93; /* PIV=1, target port, NAA */
840 arr[num++] = 0x0; /* reserved */
841 arr[num++] = 0x8; /* length */
842 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
843 arr[num++] = 0x22;
844 arr[num++] = 0x22;
845 arr[num++] = 0x20;
846 arr[num++] = (port_a >> 24);
847 arr[num++] = (port_a >> 16) & 0xff;
848 arr[num++] = (port_a >> 8) & 0xff;
849 arr[num++] = port_a & 0xff;
850
851 arr[num++] = 0x0; /* reserved */
852 arr[num++] = 0x0; /* reserved */
853 arr[num++] = 0x0;
854 arr[num++] = 0x2; /* relative port 2 (secondary) */
855 memset(arr + num, 0, 6);
856 num += 6;
857 arr[num++] = 0x0;
858 arr[num++] = 12; /* length tp descriptor */
859 /* naa-5 target port identifier (B) */
860 arr[num++] = 0x61; /* proto=sas, binary */
861 arr[num++] = 0x93; /* PIV=1, target port, NAA */
862 arr[num++] = 0x0; /* reserved */
863 arr[num++] = 0x8; /* length */
864 arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
865 arr[num++] = 0x22;
866 arr[num++] = 0x22;
867 arr[num++] = 0x20;
868 arr[num++] = (port_b >> 24);
869 arr[num++] = (port_b >> 16) & 0xff;
870 arr[num++] = (port_b >> 8) & 0xff;
871 arr[num++] = port_b & 0xff;
872
873 return num;
874}
875
876
877static unsigned char vpd89_data[] = {
878/* from 4th byte */ 0,0,0,0,
879'l','i','n','u','x',' ',' ',' ',
880'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
881'1','2','3','4',
8820x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
8830xec,0,0,0,
8840x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
8850,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
8860x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
8870x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
8880x53,0x41,
8890x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8900x20,0x20,
8910x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8920x10,0x80,
8930,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
8940x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
8950x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
8960,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
8970x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
8980x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
8990,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
9000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9020,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9030x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
9040,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
9050xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
9060,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
9070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9090,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9140,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
9180,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
919};
920
921static int inquiry_evpd_89(unsigned char * arr)
922{
923 memcpy(arr, vpd89_data, sizeof(vpd89_data));
924 return sizeof(vpd89_data);
925}
926
927
928static unsigned char vpdb0_data[] = {
929 /* from 4th byte */ 0,0,0,4,
930 0,0,0x4,0,
931 0,0,0,64,
932};
933
934static int inquiry_evpd_b0(unsigned char * arr)
935{
936 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
937 if (sdebug_store_sectors > 0x400) {
938 arr[4] = (sdebug_store_sectors >> 24) & 0xff;
939 arr[5] = (sdebug_store_sectors >> 16) & 0xff;
940 arr[6] = (sdebug_store_sectors >> 8) & 0xff;
941 arr[7] = sdebug_store_sectors & 0xff;
942 }
943 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944}
945
946
947#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400948#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
950static int resp_inquiry(struct scsi_cmnd * scp, int target,
951 struct sdebug_dev_info * devip)
952{
953 unsigned char pq_pdt;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200954 unsigned char * arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 unsigned char *cmd = (unsigned char *)scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200956 int alloc_len, n, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 alloc_len = (cmd[3] << 8) + cmd[4];
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500959 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
960 if (! arr)
961 return DID_REQUEUE << 16;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400962 if (devip->wlun)
963 pq_pdt = 0x1e; /* present, wlun */
964 else if (scsi_debug_no_lun_0 && (0 == devip->lun))
965 pq_pdt = 0x7f; /* not present, no device type */
966 else
967 pq_pdt = (scsi_debug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 arr[0] = pq_pdt;
969 if (0x2 & cmd[1]) { /* CMDDT bit set */
970 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
971 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200972 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return check_condition_result;
974 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200975 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400976 char lu_id_str[6];
977 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Hannes Reinecke5a09e392006-10-20 09:58:47 +0200979 port_group_id = (((host_no + 1) & 0x7f) << 8) +
980 (devip->channel & 0x7f);
Douglas Gilbert23183912006-09-16 20:30:47 -0400981 if (0 == scsi_debug_vpd_use_hostno)
982 host_no = 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400983 lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
984 (devip->target * 1000) + devip->lun);
985 target_dev_id = ((host_no + 1) * 2000) +
986 (devip->target * 1000) - 3;
987 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400989 arr[1] = cmd[2]; /*sanity */
990 n = 4;
991 arr[n++] = 0x0; /* this page */
992 arr[n++] = 0x80; /* unit serial number */
993 arr[n++] = 0x83; /* device identification */
994 arr[n++] = 0x84; /* software interface ident. */
995 arr[n++] = 0x85; /* management network addresses */
996 arr[n++] = 0x86; /* extended inquiry */
997 arr[n++] = 0x87; /* mode page policy */
998 arr[n++] = 0x88; /* SCSI ports */
999 arr[n++] = 0x89; /* ATA information */
1000 arr[n++] = 0xb0; /* Block limits (SBC) */
1001 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001003 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001005 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001007 arr[1] = cmd[2]; /*sanity */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001008 arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
1009 target_dev_id, lu_id_num,
1010 lu_id_str, len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001011 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1012 arr[1] = cmd[2]; /*sanity */
1013 arr[3] = inquiry_evpd_84(&arr[4]);
1014 } else if (0x85 == cmd[2]) { /* Management network addresses */
1015 arr[1] = cmd[2]; /*sanity */
1016 arr[3] = inquiry_evpd_85(&arr[4]);
1017 } else if (0x86 == cmd[2]) { /* extended inquiry */
1018 arr[1] = cmd[2]; /*sanity */
1019 arr[3] = 0x3c; /* number of following entries */
1020 arr[4] = 0x0; /* no protection stuff */
1021 arr[5] = 0x7; /* head of q, ordered + simple q's */
1022 } else if (0x87 == cmd[2]) { /* mode page policy */
1023 arr[1] = cmd[2]; /*sanity */
1024 arr[3] = 0x8; /* number of following entries */
1025 arr[4] = 0x2; /* disconnect-reconnect mp */
1026 arr[6] = 0x80; /* mlus, shared */
1027 arr[8] = 0x18; /* protocol specific lu */
1028 arr[10] = 0x82; /* mlus, per initiator port */
1029 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1030 arr[1] = cmd[2]; /*sanity */
1031 arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
1032 } else if (0x89 == cmd[2]) { /* ATA information */
1033 arr[1] = cmd[2]; /*sanity */
1034 n = inquiry_evpd_89(&arr[4]);
1035 arr[2] = (n >> 8);
1036 arr[3] = (n & 0xff);
1037 } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
1038 arr[1] = cmd[2]; /*sanity */
1039 arr[3] = inquiry_evpd_b0(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 } else {
1041 /* Illegal request, invalid field in cdb */
1042 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1043 INVALID_FIELD_IN_CDB, 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001044 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 return check_condition_result;
1046 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001047 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001048 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001049 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001050 kfree(arr);
1051 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
1053 /* drops through here for a standard inquiry */
1054 arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
1055 arr[2] = scsi_debug_scsi_level;
1056 arr[3] = 2; /* response_data_format==2 */
1057 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001058 if (0 == scsi_debug_vpd_use_hostno)
1059 arr[5] = 0x10; /* claim: implicit TGPS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001060 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001062 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 memcpy(&arr[8], inq_vendor_id, 8);
1064 memcpy(&arr[16], inq_product_id, 16);
1065 memcpy(&arr[32], inq_product_rev, 4);
1066 /* version descriptors (2 bytes each) follow */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001067 arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
1068 arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
1069 n = 62;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 if (scsi_debug_ptype == 0) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001071 arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 } else if (scsi_debug_ptype == 1) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001073 arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001075 arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001076 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001078 kfree(arr);
1079 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080}
1081
1082static int resp_requests(struct scsi_cmnd * scp,
1083 struct sdebug_dev_info * devip)
1084{
1085 unsigned char * sbuff;
1086 unsigned char *cmd = (unsigned char *)scp->cmnd;
1087 unsigned char arr[SDEBUG_SENSE_LEN];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001088 int want_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 int len = 18;
1090
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001091 memset(arr, 0, sizeof(arr));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 if (devip->reset == 1)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001093 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
1094 want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 sbuff = devip->sense_buff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001096 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
1097 if (want_dsense) {
1098 arr[0] = 0x72;
1099 arr[1] = 0x0; /* NO_SENSE in sense_key */
1100 arr[2] = THRESHOLD_EXCEEDED;
1101 arr[3] = 0xff; /* TEST set and MRIE==6 */
1102 } else {
1103 arr[0] = 0x70;
1104 arr[2] = 0x0; /* NO_SENSE in sense_key */
1105 arr[7] = 0xa; /* 18 byte sense buffer */
1106 arr[12] = THRESHOLD_EXCEEDED;
1107 arr[13] = 0xff; /* TEST set and MRIE==6 */
1108 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001109 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001111 if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
1112 /* DESC bit set and sense_buff in fixed format */
1113 memset(arr, 0, sizeof(arr));
1114 arr[0] = 0x72;
1115 arr[1] = sbuff[2]; /* sense key */
1116 arr[2] = sbuff[12]; /* asc */
1117 arr[3] = sbuff[13]; /* ascq */
1118 len = 8;
1119 }
1120 }
1121 mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 return fill_from_dev_buffer(scp, arr, len);
1123}
1124
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001125static int resp_start_stop(struct scsi_cmnd * scp,
1126 struct sdebug_dev_info * devip)
1127{
1128 unsigned char *cmd = (unsigned char *)scp->cmnd;
1129 int power_cond, errsts, start;
1130
1131 if ((errsts = check_readiness(scp, 1, devip)))
1132 return errsts;
1133 power_cond = (cmd[4] & 0xf0) >> 4;
1134 if (power_cond) {
1135 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1136 0);
1137 return check_condition_result;
1138 }
1139 start = cmd[4] & 1;
1140 if (start == devip->stopped)
1141 devip->stopped = !start;
1142 return 0;
1143}
1144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145#define SDEBUG_READCAP_ARR_SZ 8
1146static int resp_readcap(struct scsi_cmnd * scp,
1147 struct sdebug_dev_info * devip)
1148{
1149 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001150 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 int errsts;
1152
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001153 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 return errsts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001155 /* following just in case virtual_gb changed */
1156 if (scsi_debug_virtual_gb > 0) {
1157 sdebug_capacity = 2048 * 1024;
1158 sdebug_capacity *= scsi_debug_virtual_gb;
1159 } else
1160 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001162 if (sdebug_capacity < 0xffffffff) {
1163 capac = (unsigned int)sdebug_capacity - 1;
1164 arr[0] = (capac >> 24);
1165 arr[1] = (capac >> 16) & 0xff;
1166 arr[2] = (capac >> 8) & 0xff;
1167 arr[3] = capac & 0xff;
1168 } else {
1169 arr[0] = 0xff;
1170 arr[1] = 0xff;
1171 arr[2] = 0xff;
1172 arr[3] = 0xff;
1173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1175 arr[7] = SECT_SIZE_PER(target) & 0xff;
1176 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1177}
1178
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001179#define SDEBUG_READCAP16_ARR_SZ 32
1180static int resp_readcap16(struct scsi_cmnd * scp,
1181 struct sdebug_dev_info * devip)
1182{
1183 unsigned char *cmd = (unsigned char *)scp->cmnd;
1184 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
1185 unsigned long long capac;
1186 int errsts, k, alloc_len;
1187
1188 if ((errsts = check_readiness(scp, 1, devip)))
1189 return errsts;
1190 alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
1191 + cmd[13]);
1192 /* following just in case virtual_gb changed */
1193 if (scsi_debug_virtual_gb > 0) {
1194 sdebug_capacity = 2048 * 1024;
1195 sdebug_capacity *= scsi_debug_virtual_gb;
1196 } else
1197 sdebug_capacity = sdebug_store_sectors;
1198 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
1199 capac = sdebug_capacity - 1;
1200 for (k = 0; k < 8; ++k, capac >>= 8)
1201 arr[7 - k] = capac & 0xff;
1202 arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1203 arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1204 arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1205 arr[11] = SECT_SIZE_PER(target) & 0xff;
1206 return fill_from_dev_buffer(scp, arr,
1207 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1208}
1209
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001210#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1211
1212static int resp_report_tgtpgs(struct scsi_cmnd * scp,
1213 struct sdebug_dev_info * devip)
1214{
1215 unsigned char *cmd = (unsigned char *)scp->cmnd;
1216 unsigned char * arr;
1217 int host_no = devip->sdbg_host->shost->host_no;
1218 int n, ret, alen, rlen;
1219 int port_group_a, port_group_b, port_a, port_b;
1220
1221 alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
1222 + cmd[9]);
1223
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001224 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1225 if (! arr)
1226 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001227 /*
1228 * EVPD page 0x88 states we have two ports, one
1229 * real and a fake port with no device connected.
1230 * So we create two port groups with one port each
1231 * and set the group with port B to unavailable.
1232 */
1233 port_a = 0x1; /* relative port A */
1234 port_b = 0x2; /* relative port B */
1235 port_group_a = (((host_no + 1) & 0x7f) << 8) +
1236 (devip->channel & 0x7f);
1237 port_group_b = (((host_no + 1) & 0x7f) << 8) +
1238 (devip->channel & 0x7f) + 0x80;
1239
1240 /*
1241 * The asymmetric access state is cycled according to the host_id.
1242 */
1243 n = 4;
1244 if (0 == scsi_debug_vpd_use_hostno) {
1245 arr[n++] = host_no % 3; /* Asymm access state */
1246 arr[n++] = 0x0F; /* claim: all states are supported */
1247 } else {
1248 arr[n++] = 0x0; /* Active/Optimized path */
1249 arr[n++] = 0x01; /* claim: only support active/optimized paths */
1250 }
1251 arr[n++] = (port_group_a >> 8) & 0xff;
1252 arr[n++] = port_group_a & 0xff;
1253 arr[n++] = 0; /* Reserved */
1254 arr[n++] = 0; /* Status code */
1255 arr[n++] = 0; /* Vendor unique */
1256 arr[n++] = 0x1; /* One port per group */
1257 arr[n++] = 0; /* Reserved */
1258 arr[n++] = 0; /* Reserved */
1259 arr[n++] = (port_a >> 8) & 0xff;
1260 arr[n++] = port_a & 0xff;
1261 arr[n++] = 3; /* Port unavailable */
1262 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
1263 arr[n++] = (port_group_b >> 8) & 0xff;
1264 arr[n++] = port_group_b & 0xff;
1265 arr[n++] = 0; /* Reserved */
1266 arr[n++] = 0; /* Status code */
1267 arr[n++] = 0; /* Vendor unique */
1268 arr[n++] = 0x1; /* One port per group */
1269 arr[n++] = 0; /* Reserved */
1270 arr[n++] = 0; /* Reserved */
1271 arr[n++] = (port_b >> 8) & 0xff;
1272 arr[n++] = port_b & 0xff;
1273
1274 rlen = n - 4;
1275 arr[0] = (rlen >> 24) & 0xff;
1276 arr[1] = (rlen >> 16) & 0xff;
1277 arr[2] = (rlen >> 8) & 0xff;
1278 arr[3] = rlen & 0xff;
1279
1280 /*
1281 * Return the smallest value of either
1282 * - The allocated length
1283 * - The constructed command length
1284 * - The maximum array size
1285 */
1286 rlen = min(alen,n);
1287 ret = fill_from_dev_buffer(scp, arr,
1288 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1289 kfree(arr);
1290 return ret;
1291}
1292
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293/* <<Following mode page info copied from ST318451LW>> */
1294
1295static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
1296{ /* Read-Write Error Recovery page for mode_sense */
1297 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1298 5, 0, 0xff, 0xff};
1299
1300 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1301 if (1 == pcontrol)
1302 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1303 return sizeof(err_recov_pg);
1304}
1305
1306static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
1307{ /* Disconnect-Reconnect page for mode_sense */
1308 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1309 0, 0, 0, 0, 0, 0, 0, 0};
1310
1311 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1312 if (1 == pcontrol)
1313 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1314 return sizeof(disconnect_pg);
1315}
1316
1317static int resp_format_pg(unsigned char * p, int pcontrol, int target)
1318{ /* Format device page for mode_sense */
1319 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1320 0, 0, 0, 0, 0, 0, 0, 0,
1321 0, 0, 0, 0, 0x40, 0, 0, 0};
1322
1323 memcpy(p, format_pg, sizeof(format_pg));
1324 p[10] = (sdebug_sectors_per >> 8) & 0xff;
1325 p[11] = sdebug_sectors_per & 0xff;
1326 p[12] = (SECT_SIZE >> 8) & 0xff;
1327 p[13] = SECT_SIZE & 0xff;
1328 if (DEV_REMOVEABLE(target))
1329 p[20] |= 0x20; /* should agree with INQUIRY */
1330 if (1 == pcontrol)
1331 memset(p + 2, 0, sizeof(format_pg) - 2);
1332 return sizeof(format_pg);
1333}
1334
1335static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
1336{ /* Caching page for mode_sense */
1337 unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1338 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1339
1340 memcpy(p, caching_pg, sizeof(caching_pg));
1341 if (1 == pcontrol)
1342 memset(p + 2, 0, sizeof(caching_pg) - 2);
1343 return sizeof(caching_pg);
1344}
1345
1346static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
1347{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001348 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
1349 0, 0, 0, 0};
1350 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 0, 0, 0x2, 0x4b};
1352
1353 if (scsi_debug_dsense)
1354 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001355 else
1356 ctrl_m_pg[2] &= ~0x4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
1358 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001359 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
1360 else if (2 == pcontrol)
1361 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 return sizeof(ctrl_m_pg);
1363}
1364
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001365
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
1367{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001368 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
1369 0, 0, 0x0, 0x0};
1370 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1371 0, 0, 0x0, 0x0};
1372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
1374 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001375 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
1376 else if (2 == pcontrol)
1377 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 return sizeof(iec_m_pg);
1379}
1380
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001381static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
1382{ /* SAS SSP mode page - short format for mode_sense */
1383 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
1384 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
1385
1386 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
1387 if (1 == pcontrol)
1388 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
1389 return sizeof(sas_sf_m_pg);
1390}
1391
1392
1393static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
1394 int target_dev_id)
1395{ /* SAS phy control and discover mode page for mode_sense */
1396 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
1397 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
1398 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1399 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1400 0x2, 0, 0, 0, 0, 0, 0, 0,
1401 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1402 0, 0, 0, 0, 0, 0, 0, 0,
1403 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
1404 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
1405 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
1406 0x3, 0, 0, 0, 0, 0, 0, 0,
1407 0x88, 0x99, 0, 0, 0, 0, 0, 0,
1408 0, 0, 0, 0, 0, 0, 0, 0,
1409 };
1410 int port_a, port_b;
1411
1412 port_a = target_dev_id + 1;
1413 port_b = port_a + 1;
1414 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
1415 p[20] = (port_a >> 24);
1416 p[21] = (port_a >> 16) & 0xff;
1417 p[22] = (port_a >> 8) & 0xff;
1418 p[23] = port_a & 0xff;
1419 p[48 + 20] = (port_b >> 24);
1420 p[48 + 21] = (port_b >> 16) & 0xff;
1421 p[48 + 22] = (port_b >> 8) & 0xff;
1422 p[48 + 23] = port_b & 0xff;
1423 if (1 == pcontrol)
1424 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
1425 return sizeof(sas_pcd_m_pg);
1426}
1427
1428static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
1429{ /* SAS SSP shared protocol specific port mode subpage */
1430 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
1431 0, 0, 0, 0, 0, 0, 0, 0,
1432 };
1433
1434 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
1435 if (1 == pcontrol)
1436 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
1437 return sizeof(sas_sha_m_pg);
1438}
1439
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440#define SDEBUG_MAX_MSENSE_SZ 256
1441
1442static int resp_mode_sense(struct scsi_cmnd * scp, int target,
1443 struct sdebug_dev_info * devip)
1444{
Douglas Gilbert23183912006-09-16 20:30:47 -04001445 unsigned char dbd, llbaa;
1446 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 unsigned char dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001448 int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 unsigned char * ap;
1450 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
1451 unsigned char *cmd = (unsigned char *)scp->cmnd;
1452
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001453 if ((errsts = check_readiness(scp, 1, devip)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 return errsts;
Douglas Gilbert23183912006-09-16 20:30:47 -04001455 dbd = !!(cmd[1] & 0x8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 pcontrol = (cmd[2] & 0xc0) >> 6;
1457 pcode = cmd[2] & 0x3f;
1458 subpcode = cmd[3];
1459 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001460 llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
1461 if ((0 == scsi_debug_ptype) && (0 == dbd))
1462 bd_len = llbaa ? 16 : 8;
1463 else
1464 bd_len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
1466 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
1467 if (0x3 == pcontrol) { /* Saving values not supported */
1468 mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
1469 0);
1470 return check_condition_result;
1471 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001472 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
1473 (devip->target * 1000) - 3;
Douglas Gilbert23183912006-09-16 20:30:47 -04001474 /* set DPOFUA bit for disks */
1475 if (0 == scsi_debug_ptype)
1476 dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
1477 else
1478 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 if (msense_6) {
1480 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001481 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 offset = 4;
1483 } else {
1484 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04001485 if (16 == bd_len)
1486 arr[4] = 0x1; /* set LONGLBA bit */
1487 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 offset = 8;
1489 }
1490 ap = arr + offset;
Douglas Gilbert23183912006-09-16 20:30:47 -04001491 if ((bd_len > 0) && (0 == sdebug_capacity)) {
1492 if (scsi_debug_virtual_gb > 0) {
1493 sdebug_capacity = 2048 * 1024;
1494 sdebug_capacity *= scsi_debug_virtual_gb;
1495 } else
1496 sdebug_capacity = sdebug_store_sectors;
1497 }
1498 if (8 == bd_len) {
1499 if (sdebug_capacity > 0xfffffffe) {
1500 ap[0] = 0xff;
1501 ap[1] = 0xff;
1502 ap[2] = 0xff;
1503 ap[3] = 0xff;
1504 } else {
1505 ap[0] = (sdebug_capacity >> 24) & 0xff;
1506 ap[1] = (sdebug_capacity >> 16) & 0xff;
1507 ap[2] = (sdebug_capacity >> 8) & 0xff;
1508 ap[3] = sdebug_capacity & 0xff;
1509 }
1510 ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1511 ap[7] = SECT_SIZE_PER(target) & 0xff;
1512 offset += bd_len;
1513 ap = arr + offset;
1514 } else if (16 == bd_len) {
1515 unsigned long long capac = sdebug_capacity;
1516
1517 for (k = 0; k < 8; ++k, capac >>= 8)
1518 ap[7 - k] = capac & 0xff;
1519 ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
1520 ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
1521 ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
1522 ap[15] = SECT_SIZE_PER(target) & 0xff;
1523 offset += bd_len;
1524 ap = arr + offset;
1525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001527 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
1528 /* TODO: Control Extension page */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1530 0);
1531 return check_condition_result;
1532 }
1533 switch (pcode) {
1534 case 0x1: /* Read-Write error recovery page, direct access */
1535 len = resp_err_recov_pg(ap, pcontrol, target);
1536 offset += len;
1537 break;
1538 case 0x2: /* Disconnect-Reconnect page, all devices */
1539 len = resp_disconnect_pg(ap, pcontrol, target);
1540 offset += len;
1541 break;
1542 case 0x3: /* Format device page, direct access */
1543 len = resp_format_pg(ap, pcontrol, target);
1544 offset += len;
1545 break;
1546 case 0x8: /* Caching page, direct access */
1547 len = resp_caching_pg(ap, pcontrol, target);
1548 offset += len;
1549 break;
1550 case 0xa: /* Control Mode page, all devices */
1551 len = resp_ctrl_m_pg(ap, pcontrol, target);
1552 offset += len;
1553 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001554 case 0x19: /* if spc==1 then sas phy, control+discover */
1555 if ((subpcode > 0x2) && (subpcode < 0xff)) {
1556 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1557 INVALID_FIELD_IN_CDB, 0);
1558 return check_condition_result;
1559 }
1560 len = 0;
1561 if ((0x0 == subpcode) || (0xff == subpcode))
1562 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1563 if ((0x1 == subpcode) || (0xff == subpcode))
1564 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
1565 target_dev_id);
1566 if ((0x2 == subpcode) || (0xff == subpcode))
1567 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1568 offset += len;
1569 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 case 0x1c: /* Informational Exceptions Mode page, all devices */
1571 len = resp_iec_m_pg(ap, pcontrol, target);
1572 offset += len;
1573 break;
1574 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001575 if ((0 == subpcode) || (0xff == subpcode)) {
1576 len = resp_err_recov_pg(ap, pcontrol, target);
1577 len += resp_disconnect_pg(ap + len, pcontrol, target);
1578 len += resp_format_pg(ap + len, pcontrol, target);
1579 len += resp_caching_pg(ap + len, pcontrol, target);
1580 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
1581 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
1582 if (0xff == subpcode) {
1583 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
1584 target, target_dev_id);
1585 len += resp_sas_sha_m_spg(ap + len, pcontrol);
1586 }
1587 len += resp_iec_m_pg(ap + len, pcontrol, target);
1588 } else {
1589 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1590 INVALID_FIELD_IN_CDB, 0);
1591 return check_condition_result;
1592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 offset += len;
1594 break;
1595 default:
1596 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1597 0);
1598 return check_condition_result;
1599 }
1600 if (msense_6)
1601 arr[0] = offset - 1;
1602 else {
1603 arr[0] = ((offset - 2) >> 8) & 0xff;
1604 arr[1] = (offset - 2) & 0xff;
1605 }
1606 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
1607}
1608
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001609#define SDEBUG_MAX_MSELECT_SZ 512
1610
1611static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
1612 struct sdebug_dev_info * devip)
1613{
1614 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
1615 int param_len, res, errsts, mpage;
1616 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
1617 unsigned char *cmd = (unsigned char *)scp->cmnd;
1618
1619 if ((errsts = check_readiness(scp, 1, devip)))
1620 return errsts;
1621 memset(arr, 0, sizeof(arr));
1622 pf = cmd[1] & 0x10;
1623 sp = cmd[1] & 0x1;
1624 param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
1625 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
1626 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1627 INVALID_FIELD_IN_CDB, 0);
1628 return check_condition_result;
1629 }
1630 res = fetch_to_dev_buffer(scp, arr, param_len);
1631 if (-1 == res)
1632 return (DID_ERROR << 16);
1633 else if ((res < param_len) &&
1634 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
1635 printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
1636 " IO sent=%d bytes\n", param_len, res);
1637 md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
1638 bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
Douglas Gilbert23183912006-09-16 20:30:47 -04001639 if (md_len > 2) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001640 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1641 INVALID_FIELD_IN_PARAM_LIST, 0);
1642 return check_condition_result;
1643 }
1644 off = bd_len + (mselect6 ? 4 : 8);
1645 mpage = arr[off] & 0x3f;
1646 ps = !!(arr[off] & 0x80);
1647 if (ps) {
1648 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1649 INVALID_FIELD_IN_PARAM_LIST, 0);
1650 return check_condition_result;
1651 }
1652 spf = !!(arr[off] & 0x40);
1653 pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
1654 (arr[off + 1] + 2);
1655 if ((pg_len + off) > param_len) {
1656 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1657 PARAMETER_LIST_LENGTH_ERR, 0);
1658 return check_condition_result;
1659 }
1660 switch (mpage) {
1661 case 0xa: /* Control Mode page */
1662 if (ctrl_m_pg[1] == arr[off + 1]) {
1663 memcpy(ctrl_m_pg + 2, arr + off + 2,
1664 sizeof(ctrl_m_pg) - 2);
1665 scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
1666 return 0;
1667 }
1668 break;
1669 case 0x1c: /* Informational Exceptions Mode page */
1670 if (iec_m_pg[1] == arr[off + 1]) {
1671 memcpy(iec_m_pg + 2, arr + off + 2,
1672 sizeof(iec_m_pg) - 2);
1673 return 0;
1674 }
1675 break;
1676 default:
1677 break;
1678 }
1679 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1680 INVALID_FIELD_IN_PARAM_LIST, 0);
1681 return check_condition_result;
1682}
1683
1684static int resp_temp_l_pg(unsigned char * arr)
1685{
1686 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
1687 0x0, 0x1, 0x3, 0x2, 0x0, 65,
1688 };
1689
1690 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
1691 return sizeof(temp_l_pg);
1692}
1693
1694static int resp_ie_l_pg(unsigned char * arr)
1695{
1696 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
1697 };
1698
1699 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
1700 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
1701 arr[4] = THRESHOLD_EXCEEDED;
1702 arr[5] = 0xff;
1703 }
1704 return sizeof(ie_l_pg);
1705}
1706
1707#define SDEBUG_MAX_LSENSE_SZ 512
1708
1709static int resp_log_sense(struct scsi_cmnd * scp,
1710 struct sdebug_dev_info * devip)
1711{
Douglas Gilbert23183912006-09-16 20:30:47 -04001712 int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001713 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
1714 unsigned char *cmd = (unsigned char *)scp->cmnd;
1715
1716 if ((errsts = check_readiness(scp, 1, devip)))
1717 return errsts;
1718 memset(arr, 0, sizeof(arr));
1719 ppc = cmd[1] & 0x2;
1720 sp = cmd[1] & 0x1;
1721 if (ppc || sp) {
1722 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1723 INVALID_FIELD_IN_CDB, 0);
1724 return check_condition_result;
1725 }
1726 pcontrol = (cmd[2] & 0xc0) >> 6;
1727 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04001728 subpcode = cmd[3] & 0xff;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001729 alloc_len = (cmd[7] << 8) + cmd[8];
1730 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04001731 if (0 == subpcode) {
1732 switch (pcode) {
1733 case 0x0: /* Supported log pages log page */
1734 n = 4;
1735 arr[n++] = 0x0; /* this page */
1736 arr[n++] = 0xd; /* Temperature */
1737 arr[n++] = 0x2f; /* Informational exceptions */
1738 arr[3] = n - 4;
1739 break;
1740 case 0xd: /* Temperature log page */
1741 arr[3] = resp_temp_l_pg(arr + 4);
1742 break;
1743 case 0x2f: /* Informational exceptions log page */
1744 arr[3] = resp_ie_l_pg(arr + 4);
1745 break;
1746 default:
1747 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1748 INVALID_FIELD_IN_CDB, 0);
1749 return check_condition_result;
1750 }
1751 } else if (0xff == subpcode) {
1752 arr[0] |= 0x40;
1753 arr[1] = subpcode;
1754 switch (pcode) {
1755 case 0x0: /* Supported log pages and subpages log page */
1756 n = 4;
1757 arr[n++] = 0x0;
1758 arr[n++] = 0x0; /* 0,0 page */
1759 arr[n++] = 0x0;
1760 arr[n++] = 0xff; /* this page */
1761 arr[n++] = 0xd;
1762 arr[n++] = 0x0; /* Temperature */
1763 arr[n++] = 0x2f;
1764 arr[n++] = 0x0; /* Informational exceptions */
1765 arr[3] = n - 4;
1766 break;
1767 case 0xd: /* Temperature subpages */
1768 n = 4;
1769 arr[n++] = 0xd;
1770 arr[n++] = 0x0; /* Temperature */
1771 arr[3] = n - 4;
1772 break;
1773 case 0x2f: /* Informational exceptions subpages */
1774 n = 4;
1775 arr[n++] = 0x2f;
1776 arr[n++] = 0x0; /* Informational exceptions */
1777 arr[3] = n - 4;
1778 break;
1779 default:
1780 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1781 INVALID_FIELD_IN_CDB, 0);
1782 return check_condition_result;
1783 }
1784 } else {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001785 mk_sense_buffer(devip, ILLEGAL_REQUEST,
1786 INVALID_FIELD_IN_CDB, 0);
1787 return check_condition_result;
1788 }
1789 len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
1790 return fill_from_dev_buffer(scp, arr,
1791 min(len, SDEBUG_MAX_INQ_ARR_SZ));
1792}
1793
1794static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
1795 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796{
1797 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001798 unsigned int block, from_bottom;
1799 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 int ret;
1801
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001802 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1804 0);
1805 return check_condition_result;
1806 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001807 /* transfer length excessive (tie in to block limits VPD page) */
1808 if (num > sdebug_store_sectors) {
1809 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1810 0);
1811 return check_condition_result;
1812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001814 (lba <= OPT_MEDIUM_ERR_ADDR) &&
1815 ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
1816 /* claim unrecoverable read error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
1818 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001819 /* set info field and valid bit for fixed descriptor */
1820 if (0x70 == (devip->sense_buff[0] & 0x7f)) {
1821 devip->sense_buff[0] |= 0x80; /* Valid bit */
1822 ret = OPT_MEDIUM_ERR_ADDR;
1823 devip->sense_buff[3] = (ret >> 24) & 0xff;
1824 devip->sense_buff[4] = (ret >> 16) & 0xff;
1825 devip->sense_buff[5] = (ret >> 8) & 0xff;
1826 devip->sense_buff[6] = ret & 0xff;
1827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 return check_condition_result;
1829 }
1830 read_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001831 if ((lba + num) <= sdebug_store_sectors)
1832 ret = fill_from_dev_buffer(SCpnt,
1833 fake_storep + (lba * SECT_SIZE),
1834 num * SECT_SIZE);
1835 else {
1836 /* modulo when one arg is 64 bits needs do_div() */
1837 u = lba;
1838 block = do_div(u, sdebug_store_sectors);
1839 from_bottom = 0;
1840 if ((block + num) > sdebug_store_sectors)
1841 from_bottom = (block + num) - sdebug_store_sectors;
1842 ret = fill_from_dev_buffer(SCpnt,
1843 fake_storep + (block * SECT_SIZE),
1844 (num - from_bottom) * SECT_SIZE);
1845 if ((0 == ret) && (from_bottom > 0))
1846 ret = fill_from_dev_buffer(SCpnt, fake_storep,
1847 from_bottom * SECT_SIZE);
1848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 read_unlock_irqrestore(&atomic_rw, iflags);
1850 return ret;
1851}
1852
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001853static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
1854 unsigned int num, struct sdebug_dev_info * devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855{
1856 unsigned long iflags;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001857 unsigned int block, to_bottom;
1858 unsigned long long u;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 int res;
1860
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001861 if (lba + num > sdebug_capacity) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
1863 0);
1864 return check_condition_result;
1865 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001866 /* transfer length excessive (tie in to block limits VPD page) */
1867 if (num > sdebug_store_sectors) {
1868 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1869 0);
1870 return check_condition_result;
1871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
1873 write_lock_irqsave(&atomic_rw, iflags);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001874 if ((lba + num) <= sdebug_store_sectors)
1875 res = fetch_to_dev_buffer(SCpnt,
1876 fake_storep + (lba * SECT_SIZE),
1877 num * SECT_SIZE);
1878 else {
1879 /* modulo when one arg is 64 bits needs do_div() */
1880 u = lba;
1881 block = do_div(u, sdebug_store_sectors);
1882 to_bottom = 0;
1883 if ((block + num) > sdebug_store_sectors)
1884 to_bottom = (block + num) - sdebug_store_sectors;
1885 res = fetch_to_dev_buffer(SCpnt,
1886 fake_storep + (block * SECT_SIZE),
1887 (num - to_bottom) * SECT_SIZE);
1888 if ((0 == res) && (to_bottom > 0))
1889 res = fetch_to_dev_buffer(SCpnt, fake_storep,
1890 to_bottom * SECT_SIZE);
1891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 write_unlock_irqrestore(&atomic_rw, iflags);
1893 if (-1 == res)
1894 return (DID_ERROR << 16);
1895 else if ((res < (num * SECT_SIZE)) &&
1896 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001897 printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 " IO sent=%d bytes\n", num * SECT_SIZE, res);
1899 return 0;
1900}
1901
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001902#define SDEBUG_RLUN_ARR_SZ 256
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904static int resp_report_luns(struct scsi_cmnd * scp,
1905 struct sdebug_dev_info * devip)
1906{
1907 unsigned int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001908 int lun_cnt, i, upper, num, n, wlun, lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 unsigned char *cmd = (unsigned char *)scp->cmnd;
1910 int select_report = (int)cmd[2];
1911 struct scsi_lun *one_lun;
1912 unsigned char arr[SDEBUG_RLUN_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001913 unsigned char * max_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
1915 alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001916 if ((alloc_len < 4) || (select_report > 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
1918 0);
1919 return check_condition_result;
1920 }
1921 /* can produce response with up to 16k luns (lun 0 to lun 16383) */
1922 memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
1923 lun_cnt = scsi_debug_max_luns;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001924 if (1 == select_report)
1925 lun_cnt = 0;
1926 else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
1927 --lun_cnt;
1928 wlun = (select_report > 0) ? 1 : 0;
1929 num = lun_cnt + wlun;
1930 arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
1931 arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
1932 n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
1933 sizeof(struct scsi_lun)), num);
1934 if (n < num) {
1935 wlun = 0;
1936 lun_cnt = n;
1937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 one_lun = (struct scsi_lun *) &arr[8];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001939 max_addr = arr + SDEBUG_RLUN_ARR_SZ;
1940 for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
1941 ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
1942 i++, lun++) {
1943 upper = (lun >> 8) & 0x3f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 if (upper)
1945 one_lun[i].scsi_lun[0] =
1946 (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001947 one_lun[i].scsi_lun[1] = lun & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001949 if (wlun) {
1950 one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
1951 one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
1952 i++;
1953 }
1954 alloc_len = (unsigned char *)(one_lun + i) - arr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 return fill_from_dev_buffer(scp, arr,
1956 min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
1957}
1958
1959/* When timer goes off this function is called. */
1960static void timer_intr_handler(unsigned long indx)
1961{
1962 struct sdebug_queued_cmd * sqcp;
1963 unsigned long iflags;
1964
1965 if (indx >= SCSI_DEBUG_CANQUEUE) {
1966 printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
1967 "large\n");
1968 return;
1969 }
1970 spin_lock_irqsave(&queued_arr_lock, iflags);
1971 sqcp = &queued_arr[(int)indx];
1972 if (! sqcp->in_use) {
1973 printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
1974 "interrupt\n");
1975 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1976 return;
1977 }
1978 sqcp->in_use = 0;
1979 if (sqcp->done_funct) {
1980 sqcp->a_cmnd->result = sqcp->scsi_result;
1981 sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
1982 }
1983 sqcp->done_funct = NULL;
1984 spin_unlock_irqrestore(&queued_arr_lock, iflags);
1985}
1986
1987static int scsi_debug_slave_alloc(struct scsi_device * sdp)
1988{
1989 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001990 printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
1991 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 return 0;
1993}
1994
1995static int scsi_debug_slave_configure(struct scsi_device * sdp)
1996{
1997 struct sdebug_dev_info * devip;
1998
1999 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002000 printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
2001 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
2003 sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
2004 devip = devInfoReg(sdp);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002005 if (NULL == devip)
2006 return 1; /* no resources, will be marked offline */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 sdp->hostdata = devip;
2008 if (sdp->host->cmd_per_lun)
2009 scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
2010 sdp->host->cmd_per_lun);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002011 blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 return 0;
2013}
2014
2015static void scsi_debug_slave_destroy(struct scsi_device * sdp)
2016{
2017 struct sdebug_dev_info * devip =
2018 (struct sdebug_dev_info *)sdp->hostdata;
2019
2020 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002021 printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
2022 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 if (devip) {
2024 /* make this slot avaliable for re-use */
2025 devip->used = 0;
2026 sdp->hostdata = NULL;
2027 }
2028}
2029
2030static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
2031{
2032 struct sdebug_host_info * sdbg_host;
2033 struct sdebug_dev_info * open_devip = NULL;
2034 struct sdebug_dev_info * devip =
2035 (struct sdebug_dev_info *)sdev->hostdata;
2036
2037 if (devip)
2038 return devip;
2039 sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
2040 if(! sdbg_host) {
2041 printk(KERN_ERR "Host info NULL\n");
2042 return NULL;
2043 }
2044 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
2045 if ((devip->used) && (devip->channel == sdev->channel) &&
2046 (devip->target == sdev->id) &&
2047 (devip->lun == sdev->lun))
2048 return devip;
2049 else {
2050 if ((!devip->used) && (!open_devip))
2051 open_devip = devip;
2052 }
2053 }
2054 if (NULL == open_devip) { /* try and make a new one */
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002055 open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 if (NULL == open_devip) {
2057 printk(KERN_ERR "%s: out of memory at line %d\n",
2058 __FUNCTION__, __LINE__);
2059 return NULL;
2060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 open_devip->sdbg_host = sdbg_host;
2062 list_add_tail(&open_devip->dev_list,
2063 &sdbg_host->dev_info_list);
2064 }
2065 if (open_devip) {
2066 open_devip->channel = sdev->channel;
2067 open_devip->target = sdev->id;
2068 open_devip->lun = sdev->lun;
2069 open_devip->sdbg_host = sdbg_host;
2070 open_devip->reset = 1;
2071 open_devip->used = 1;
2072 memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
2073 if (scsi_debug_dsense)
2074 open_devip->sense_buff[0] = 0x72;
2075 else {
2076 open_devip->sense_buff[0] = 0x70;
2077 open_devip->sense_buff[7] = 0xa;
2078 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002079 if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
2080 open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 return open_devip;
2082 }
2083 return NULL;
2084}
2085
2086static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
2087 int asc, int asq)
2088{
2089 unsigned char * sbuff;
2090
2091 sbuff = devip->sense_buff;
2092 memset(sbuff, 0, SDEBUG_SENSE_LEN);
2093 if (scsi_debug_dsense) {
2094 sbuff[0] = 0x72; /* descriptor, current */
2095 sbuff[1] = key;
2096 sbuff[2] = asc;
2097 sbuff[3] = asq;
2098 } else {
2099 sbuff[0] = 0x70; /* fixed, current */
2100 sbuff[2] = key;
2101 sbuff[7] = 0xa; /* implies 18 byte sense buffer */
2102 sbuff[12] = asc;
2103 sbuff[13] = asq;
2104 }
2105 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2106 printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: "
2107 "[0x%x,0x%x,0x%x]\n", key, asc, asq);
2108}
2109
2110static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
2111{
2112 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2113 printk(KERN_INFO "scsi_debug: abort\n");
2114 ++num_aborts;
2115 stop_queued_cmnd(SCpnt);
2116 return SUCCESS;
2117}
2118
2119static int scsi_debug_biosparam(struct scsi_device *sdev,
2120 struct block_device * bdev, sector_t capacity, int *info)
2121{
2122 int res;
2123 unsigned char *buf;
2124
2125 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2126 printk(KERN_INFO "scsi_debug: biosparam\n");
2127 buf = scsi_bios_ptable(bdev);
2128 if (buf) {
2129 res = scsi_partsize(buf, capacity,
2130 &info[2], &info[0], &info[1]);
2131 kfree(buf);
2132 if (! res)
2133 return res;
2134 }
2135 info[0] = sdebug_heads;
2136 info[1] = sdebug_sectors_per;
2137 info[2] = sdebug_cylinders_per;
2138 return 0;
2139}
2140
2141static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
2142{
2143 struct sdebug_dev_info * devip;
2144
2145 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2146 printk(KERN_INFO "scsi_debug: device_reset\n");
2147 ++num_dev_resets;
2148 if (SCpnt) {
2149 devip = devInfoReg(SCpnt->device);
2150 if (devip)
2151 devip->reset = 1;
2152 }
2153 return SUCCESS;
2154}
2155
2156static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
2157{
2158 struct sdebug_host_info *sdbg_host;
2159 struct sdebug_dev_info * dev_info;
2160 struct scsi_device * sdp;
2161 struct Scsi_Host * hp;
2162
2163 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2164 printk(KERN_INFO "scsi_debug: bus_reset\n");
2165 ++num_bus_resets;
2166 if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
2167 sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
2168 if (sdbg_host) {
2169 list_for_each_entry(dev_info,
2170 &sdbg_host->dev_info_list,
2171 dev_list)
2172 dev_info->reset = 1;
2173 }
2174 }
2175 return SUCCESS;
2176}
2177
2178static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
2179{
2180 struct sdebug_host_info * sdbg_host;
2181 struct sdebug_dev_info * dev_info;
2182
2183 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2184 printk(KERN_INFO "scsi_debug: host_reset\n");
2185 ++num_host_resets;
2186 spin_lock(&sdebug_host_list_lock);
2187 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
2188 list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
2189 dev_list)
2190 dev_info->reset = 1;
2191 }
2192 spin_unlock(&sdebug_host_list_lock);
2193 stop_all_queued();
2194 return SUCCESS;
2195}
2196
2197/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
2198static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
2199{
2200 unsigned long iflags;
2201 int k;
2202 struct sdebug_queued_cmd * sqcp;
2203
2204 spin_lock_irqsave(&queued_arr_lock, iflags);
2205 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2206 sqcp = &queued_arr[k];
2207 if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
2208 del_timer_sync(&sqcp->cmnd_timer);
2209 sqcp->in_use = 0;
2210 sqcp->a_cmnd = NULL;
2211 break;
2212 }
2213 }
2214 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2215 return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
2216}
2217
2218/* Deletes (stops) timers of all queued commands */
2219static void stop_all_queued(void)
2220{
2221 unsigned long iflags;
2222 int k;
2223 struct sdebug_queued_cmd * sqcp;
2224
2225 spin_lock_irqsave(&queued_arr_lock, iflags);
2226 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2227 sqcp = &queued_arr[k];
2228 if (sqcp->in_use && sqcp->a_cmnd) {
2229 del_timer_sync(&sqcp->cmnd_timer);
2230 sqcp->in_use = 0;
2231 sqcp->a_cmnd = NULL;
2232 }
2233 }
2234 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2235}
2236
2237/* Initializes timers in queued array */
2238static void __init init_all_queued(void)
2239{
2240 unsigned long iflags;
2241 int k;
2242 struct sdebug_queued_cmd * sqcp;
2243
2244 spin_lock_irqsave(&queued_arr_lock, iflags);
2245 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2246 sqcp = &queued_arr[k];
2247 init_timer(&sqcp->cmnd_timer);
2248 sqcp->in_use = 0;
2249 sqcp->a_cmnd = NULL;
2250 }
2251 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2252}
2253
2254static void __init sdebug_build_parts(unsigned char * ramp)
2255{
2256 struct partition * pp;
2257 int starts[SDEBUG_MAX_PARTS + 2];
2258 int sectors_per_part, num_sectors, k;
2259 int heads_by_sects, start_sec, end_sec;
2260
2261 /* assume partition table already zeroed */
2262 if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
2263 return;
2264 if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
2265 scsi_debug_num_parts = SDEBUG_MAX_PARTS;
2266 printk(KERN_WARNING "scsi_debug:build_parts: reducing "
2267 "partitions to %d\n", SDEBUG_MAX_PARTS);
2268 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002269 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 sectors_per_part = (num_sectors - sdebug_sectors_per)
2271 / scsi_debug_num_parts;
2272 heads_by_sects = sdebug_heads * sdebug_sectors_per;
2273 starts[0] = sdebug_sectors_per;
2274 for (k = 1; k < scsi_debug_num_parts; ++k)
2275 starts[k] = ((k * sectors_per_part) / heads_by_sects)
2276 * heads_by_sects;
2277 starts[scsi_debug_num_parts] = num_sectors;
2278 starts[scsi_debug_num_parts + 1] = 0;
2279
2280 ramp[510] = 0x55; /* magic partition markings */
2281 ramp[511] = 0xAA;
2282 pp = (struct partition *)(ramp + 0x1be);
2283 for (k = 0; starts[k + 1]; ++k, ++pp) {
2284 start_sec = starts[k];
2285 end_sec = starts[k + 1] - 1;
2286 pp->boot_ind = 0;
2287
2288 pp->cyl = start_sec / heads_by_sects;
2289 pp->head = (start_sec - (pp->cyl * heads_by_sects))
2290 / sdebug_sectors_per;
2291 pp->sector = (start_sec % sdebug_sectors_per) + 1;
2292
2293 pp->end_cyl = end_sec / heads_by_sects;
2294 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
2295 / sdebug_sectors_per;
2296 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
2297
2298 pp->start_sect = start_sec;
2299 pp->nr_sects = end_sec - start_sec + 1;
2300 pp->sys_ind = 0x83; /* plain Linux partition */
2301 }
2302}
2303
2304static int schedule_resp(struct scsi_cmnd * cmnd,
2305 struct sdebug_dev_info * devip,
2306 done_funct_t done, int scsi_result, int delta_jiff)
2307{
2308 if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
2309 if (scsi_result) {
2310 struct scsi_device * sdp = cmnd->device;
2311
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002312 printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
2313 "non-zero result=0x%x\n", sdp->host->host_no,
2314 sdp->channel, sdp->id, sdp->lun, scsi_result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 }
2316 }
2317 if (cmnd && devip) {
2318 /* simulate autosense by this driver */
2319 if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
2320 memcpy(cmnd->sense_buffer, devip->sense_buff,
2321 (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
2322 SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
2323 }
2324 if (delta_jiff <= 0) {
2325 if (cmnd)
2326 cmnd->result = scsi_result;
2327 if (done)
2328 done(cmnd);
2329 return 0;
2330 } else {
2331 unsigned long iflags;
2332 int k;
2333 struct sdebug_queued_cmd * sqcp = NULL;
2334
2335 spin_lock_irqsave(&queued_arr_lock, iflags);
2336 for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
2337 sqcp = &queued_arr[k];
2338 if (! sqcp->in_use)
2339 break;
2340 }
2341 if (k >= SCSI_DEBUG_CANQUEUE) {
2342 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2343 printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
2344 return 1; /* report busy to mid level */
2345 }
2346 sqcp->in_use = 1;
2347 sqcp->a_cmnd = cmnd;
2348 sqcp->scsi_result = scsi_result;
2349 sqcp->done_funct = done;
2350 sqcp->cmnd_timer.function = timer_intr_handler;
2351 sqcp->cmnd_timer.data = k;
2352 sqcp->cmnd_timer.expires = jiffies + delta_jiff;
2353 add_timer(&sqcp->cmnd_timer);
2354 spin_unlock_irqrestore(&queued_arr_lock, iflags);
2355 if (cmnd)
2356 cmnd->result = 0;
2357 return 0;
2358 }
2359}
2360
Douglas Gilbert23183912006-09-16 20:30:47 -04002361/* Note: The following macros create attribute files in the
2362 /sys/module/scsi_debug/parameters directory. Unfortunately this
2363 driver is unaware of a change and cannot trigger auxiliary actions
2364 as it can when the corresponding attribute in the
2365 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
2366 */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002367module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
2368module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
2369module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
2370module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
2371module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002372module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002373module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
2374module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
2375module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
2376module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
2377module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
2378module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
2379module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
2380module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert23183912006-09-16 20:30:47 -04002381module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
2382 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
2384MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
2385MODULE_DESCRIPTION("SCSI debug adapter driver");
2386MODULE_LICENSE("GPL");
2387MODULE_VERSION(SCSI_DEBUG_VERSION);
2388
2389MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
2390MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002391MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
2392MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07002393MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002394MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002395MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
2396MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002398MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05002399MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
2401MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002402MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
Douglas Gilbert23183912006-09-16 20:30:47 -04002403MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
2405
2406static char sdebug_info[256];
2407
2408static const char * scsi_debug_info(struct Scsi_Host * shp)
2409{
2410 sprintf(sdebug_info, "scsi_debug, version %s [%s], "
2411 "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
2412 scsi_debug_version_date, scsi_debug_dev_size_mb,
2413 scsi_debug_opts);
2414 return sdebug_info;
2415}
2416
2417/* scsi_debug_proc_info
2418 * Used if the driver currently has no own support for /proc/scsi
2419 */
2420static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
2421 int length, int inout)
2422{
2423 int len, pos, begin;
2424 int orig_length;
2425
2426 orig_length = length;
2427
2428 if (inout == 1) {
2429 char arr[16];
2430 int minLen = length > 15 ? 15 : length;
2431
2432 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
2433 return -EACCES;
2434 memcpy(arr, buffer, minLen);
2435 arr[minLen] = '\0';
2436 if (1 != sscanf(arr, "%d", &pos))
2437 return -EINVAL;
2438 scsi_debug_opts = pos;
2439 if (scsi_debug_every_nth != 0)
2440 scsi_debug_cmnd_count = 0;
2441 return length;
2442 }
2443 begin = 0;
2444 pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
2445 "%s [%s]\n"
2446 "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
2447 "every_nth=%d(curr:%d)\n"
2448 "delay=%d, max_luns=%d, scsi_level=%d\n"
2449 "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
2450 "number of aborts=%d, device_reset=%d, bus_resets=%d, "
2451 "host_resets=%d\n",
2452 SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
2453 scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
2454 scsi_debug_cmnd_count, scsi_debug_delay,
2455 scsi_debug_max_luns, scsi_debug_scsi_level,
2456 SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
2457 num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
2458 if (pos < offset) {
2459 len = 0;
2460 begin = pos;
2461 }
2462 *start = buffer + (offset - begin); /* Start of wanted data */
2463 len -= (offset - begin);
2464 if (len > length)
2465 len = length;
2466 return len;
2467}
2468
2469static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
2470{
2471 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
2472}
2473
2474static ssize_t sdebug_delay_store(struct device_driver * ddp,
2475 const char * buf, size_t count)
2476{
2477 int delay;
2478 char work[20];
2479
2480 if (1 == sscanf(buf, "%10s", work)) {
2481 if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
2482 scsi_debug_delay = delay;
2483 return count;
2484 }
2485 }
2486 return -EINVAL;
2487}
2488DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
2489 sdebug_delay_store);
2490
2491static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
2492{
2493 return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
2494}
2495
2496static ssize_t sdebug_opts_store(struct device_driver * ddp,
2497 const char * buf, size_t count)
2498{
2499 int opts;
2500 char work[20];
2501
2502 if (1 == sscanf(buf, "%10s", work)) {
2503 if (0 == strnicmp(work,"0x", 2)) {
2504 if (1 == sscanf(&work[2], "%x", &opts))
2505 goto opts_done;
2506 } else {
2507 if (1 == sscanf(work, "%d", &opts))
2508 goto opts_done;
2509 }
2510 }
2511 return -EINVAL;
2512opts_done:
2513 scsi_debug_opts = opts;
2514 scsi_debug_cmnd_count = 0;
2515 return count;
2516}
2517DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
2518 sdebug_opts_store);
2519
2520static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
2521{
2522 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
2523}
2524static ssize_t sdebug_ptype_store(struct device_driver * ddp,
2525 const char * buf, size_t count)
2526{
2527 int n;
2528
2529 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2530 scsi_debug_ptype = n;
2531 return count;
2532 }
2533 return -EINVAL;
2534}
2535DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
2536
2537static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
2538{
2539 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
2540}
2541static ssize_t sdebug_dsense_store(struct device_driver * ddp,
2542 const char * buf, size_t count)
2543{
2544 int n;
2545
2546 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2547 scsi_debug_dsense = n;
2548 return count;
2549 }
2550 return -EINVAL;
2551}
2552DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
2553 sdebug_dsense_store);
2554
Douglas Gilbert23183912006-09-16 20:30:47 -04002555static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
2556{
2557 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
2558}
2559static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
2560 const char * buf, size_t count)
2561{
2562 int n;
2563
2564 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2565 scsi_debug_fake_rw = n;
2566 return count;
2567 }
2568 return -EINVAL;
2569}
2570DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
2571 sdebug_fake_rw_store);
2572
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002573static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
2574{
2575 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
2576}
2577static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
2578 const char * buf, size_t count)
2579{
2580 int n;
2581
2582 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2583 scsi_debug_no_lun_0 = n;
2584 return count;
2585 }
2586 return -EINVAL;
2587}
2588DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
2589 sdebug_no_lun_0_store);
2590
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
2592{
2593 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
2594}
2595static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
2596 const char * buf, size_t count)
2597{
2598 int n;
2599
2600 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2601 scsi_debug_num_tgts = n;
2602 sdebug_max_tgts_luns();
2603 return count;
2604 }
2605 return -EINVAL;
2606}
2607DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
2608 sdebug_num_tgts_store);
2609
2610static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
2611{
2612 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
2613}
2614DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
2615
2616static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
2617{
2618 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
2619}
2620DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
2621
2622static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
2623{
2624 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
2625}
2626static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
2627 const char * buf, size_t count)
2628{
2629 int nth;
2630
2631 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
2632 scsi_debug_every_nth = nth;
2633 scsi_debug_cmnd_count = 0;
2634 return count;
2635 }
2636 return -EINVAL;
2637}
2638DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
2639 sdebug_every_nth_store);
2640
2641static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
2642{
2643 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
2644}
2645static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
2646 const char * buf, size_t count)
2647{
2648 int n;
2649
2650 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2651 scsi_debug_max_luns = n;
2652 sdebug_max_tgts_luns();
2653 return count;
2654 }
2655 return -EINVAL;
2656}
2657DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
2658 sdebug_max_luns_store);
2659
2660static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
2661{
2662 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
2663}
2664DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
2665
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002666static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
2667{
2668 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
2669}
2670static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
2671 const char * buf, size_t count)
2672{
2673 int n;
2674
2675 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2676 scsi_debug_virtual_gb = n;
2677 if (scsi_debug_virtual_gb > 0) {
2678 sdebug_capacity = 2048 * 1024;
2679 sdebug_capacity *= scsi_debug_virtual_gb;
2680 } else
2681 sdebug_capacity = sdebug_store_sectors;
2682 return count;
2683 }
2684 return -EINVAL;
2685}
2686DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
2687 sdebug_virtual_gb_store);
2688
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
2690{
2691 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
2692}
2693
2694static ssize_t sdebug_add_host_store(struct device_driver * ddp,
2695 const char * buf, size_t count)
2696{
2697 int delta_hosts;
2698 char work[20];
2699
2700 if (1 != sscanf(buf, "%10s", work))
2701 return -EINVAL;
2702 { /* temporary hack around sscanf() problem with -ve nums */
2703 int neg = 0;
2704
2705 if ('-' == *work)
2706 neg = 1;
2707 if (1 != sscanf(work + neg, "%d", &delta_hosts))
2708 return -EINVAL;
2709 if (neg)
2710 delta_hosts = -delta_hosts;
2711 }
2712 if (delta_hosts > 0) {
2713 do {
2714 sdebug_add_adapter();
2715 } while (--delta_hosts);
2716 } else if (delta_hosts < 0) {
2717 do {
2718 sdebug_remove_adapter();
2719 } while (++delta_hosts);
2720 }
2721 return count;
2722}
2723DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
2724 sdebug_add_host_store);
2725
Douglas Gilbert23183912006-09-16 20:30:47 -04002726static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
2727 char * buf)
2728{
2729 return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
2730}
2731static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
2732 const char * buf, size_t count)
2733{
2734 int n;
2735
2736 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
2737 scsi_debug_vpd_use_hostno = n;
2738 return count;
2739 }
2740 return -EINVAL;
2741}
2742DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
2743 sdebug_vpd_use_hostno_store);
2744
2745/* Note: The following function creates attribute files in the
2746 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
2747 files (over those found in the /sys/module/scsi_debug/parameters
2748 directory) is that auxiliary actions can be triggered when an attribute
2749 is changed. For example see: sdebug_add_host_store() above.
2750 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002751static int do_create_driverfs_files(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752{
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002753 int ret;
2754
2755 ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2756 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
2757 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2758 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2759 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
Douglas Gilbert23183912006-09-16 20:30:47 -04002760 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002761 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002762 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002763 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002764 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002765 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
2766 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
2767 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
Douglas Gilbert23183912006-09-16 20:30:47 -04002768 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
2769 ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002770 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771}
2772
2773static void do_remove_driverfs_files(void)
2774{
Douglas Gilbert23183912006-09-16 20:30:47 -04002775 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
2776 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
2778 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
2779 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
Douglas Gilbert23183912006-09-16 20:30:47 -04002781 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
2782 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
Douglas Gilbert23183912006-09-16 20:30:47 -04002784 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
2786 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
2787 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
2788 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
2789 driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
2790}
2791
2792static int __init scsi_debug_init(void)
2793{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002794 unsigned int sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 int host_to_add;
2796 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002797 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
2799 if (scsi_debug_dev_size_mb < 1)
2800 scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002801 sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
2802 sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
2803 if (scsi_debug_virtual_gb > 0) {
2804 sdebug_capacity = 2048 * 1024;
2805 sdebug_capacity *= scsi_debug_virtual_gb;
2806 } else
2807 sdebug_capacity = sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809 /* play around with geometry, don't waste too much on track 0 */
2810 sdebug_heads = 8;
2811 sdebug_sectors_per = 32;
2812 if (scsi_debug_dev_size_mb >= 16)
2813 sdebug_heads = 32;
2814 else if (scsi_debug_dev_size_mb >= 256)
2815 sdebug_heads = 64;
2816 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2817 (sdebug_sectors_per * sdebug_heads);
2818 if (sdebug_cylinders_per >= 1024) {
2819 /* other LLDs do this; implies >= 1GB ram disk ... */
2820 sdebug_heads = 255;
2821 sdebug_sectors_per = 63;
2822 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
2823 (sdebug_sectors_per * sdebug_heads);
2824 }
2825
2826 sz = sdebug_store_size;
2827 fake_storep = vmalloc(sz);
2828 if (NULL == fake_storep) {
2829 printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
2830 return -ENOMEM;
2831 }
2832 memset(fake_storep, 0, sz);
2833 if (scsi_debug_num_parts > 0)
2834 sdebug_build_parts(fake_storep);
2835
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002836 ret = device_register(&pseudo_primary);
2837 if (ret < 0) {
2838 printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
2839 ret);
2840 goto free_vm;
2841 }
2842 ret = bus_register(&pseudo_lld_bus);
2843 if (ret < 0) {
2844 printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
2845 ret);
2846 goto dev_unreg;
2847 }
2848 ret = driver_register(&sdebug_driverfs_driver);
2849 if (ret < 0) {
2850 printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
2851 ret);
2852 goto bus_unreg;
2853 }
2854 ret = do_create_driverfs_files();
2855 if (ret < 0) {
2856 printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
2857 ret);
2858 goto del_files;
2859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002861 init_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
Kristian Høgsbergb02b6bc2007-05-09 19:23:12 -04002863 sdebug_driver_template.proc_name = sdebug_proc_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864
2865 host_to_add = scsi_debug_add_host;
2866 scsi_debug_add_host = 0;
2867
2868 for (k = 0; k < host_to_add; k++) {
2869 if (sdebug_add_adapter()) {
2870 printk(KERN_ERR "scsi_debug_init: "
2871 "sdebug_add_adapter failed k=%d\n", k);
2872 break;
2873 }
2874 }
2875
2876 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
2877 printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
2878 scsi_debug_add_host);
2879 }
2880 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07002881
2882del_files:
2883 do_remove_driverfs_files();
2884 driver_unregister(&sdebug_driverfs_driver);
2885bus_unreg:
2886 bus_unregister(&pseudo_lld_bus);
2887dev_unreg:
2888 device_unregister(&pseudo_primary);
2889free_vm:
2890 vfree(fake_storep);
2891
2892 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893}
2894
2895static void __exit scsi_debug_exit(void)
2896{
2897 int k = scsi_debug_add_host;
2898
2899 stop_all_queued();
2900 for (; k; k--)
2901 sdebug_remove_adapter();
2902 do_remove_driverfs_files();
2903 driver_unregister(&sdebug_driverfs_driver);
2904 bus_unregister(&pseudo_lld_bus);
2905 device_unregister(&pseudo_primary);
2906
2907 vfree(fake_storep);
2908}
2909
2910device_initcall(scsi_debug_init);
2911module_exit(scsi_debug_exit);
2912
Adrian Bunk52c1da32005-06-23 22:05:33 -07002913static void pseudo_0_release(struct device * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914{
2915 if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
2916 printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
2917}
2918
2919static struct device pseudo_primary = {
2920 .bus_id = "pseudo_0",
2921 .release = pseudo_0_release,
2922};
2923
2924static int pseudo_lld_bus_match(struct device *dev,
2925 struct device_driver *dev_driver)
2926{
2927 return 1;
2928}
2929
2930static struct bus_type pseudo_lld_bus = {
2931 .name = "pseudo",
2932 .match = pseudo_lld_bus_match,
Russell Kingbbbe3a42006-01-05 14:44:46 +00002933 .probe = sdebug_driver_probe,
2934 .remove = sdebug_driver_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935};
2936
2937static void sdebug_release_adapter(struct device * dev)
2938{
2939 struct sdebug_host_info *sdbg_host;
2940
2941 sdbg_host = to_sdebug_host(dev);
2942 kfree(sdbg_host);
2943}
2944
2945static int sdebug_add_adapter(void)
2946{
2947 int k, devs_per_host;
2948 int error = 0;
2949 struct sdebug_host_info *sdbg_host;
2950 struct sdebug_dev_info *sdbg_devinfo;
2951 struct list_head *lh, *lh_sf;
2952
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002953 sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 if (NULL == sdbg_host) {
2955 printk(KERN_ERR "%s: out of memory at line %d\n",
2956 __FUNCTION__, __LINE__);
2957 return -ENOMEM;
2958 }
2959
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
2961
2962 devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
2963 for (k = 0; k < devs_per_host; k++) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002964 sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 if (NULL == sdbg_devinfo) {
2966 printk(KERN_ERR "%s: out of memory at line %d\n",
2967 __FUNCTION__, __LINE__);
2968 error = -ENOMEM;
2969 goto clean;
2970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 sdbg_devinfo->sdbg_host = sdbg_host;
2972 list_add_tail(&sdbg_devinfo->dev_list,
2973 &sdbg_host->dev_info_list);
2974 }
2975
2976 spin_lock(&sdebug_host_list_lock);
2977 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
2978 spin_unlock(&sdebug_host_list_lock);
2979
2980 sdbg_host->dev.bus = &pseudo_lld_bus;
2981 sdbg_host->dev.parent = &pseudo_primary;
2982 sdbg_host->dev.release = &sdebug_release_adapter;
2983 sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
2984
2985 error = device_register(&sdbg_host->dev);
2986
2987 if (error)
2988 goto clean;
2989
2990 ++scsi_debug_add_host;
2991 return error;
2992
2993clean:
2994 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
2995 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
2996 dev_list);
2997 list_del(&sdbg_devinfo->dev_list);
2998 kfree(sdbg_devinfo);
2999 }
3000
3001 kfree(sdbg_host);
3002 return error;
3003}
3004
3005static void sdebug_remove_adapter(void)
3006{
3007 struct sdebug_host_info * sdbg_host = NULL;
3008
3009 spin_lock(&sdebug_host_list_lock);
3010 if (!list_empty(&sdebug_host_list)) {
3011 sdbg_host = list_entry(sdebug_host_list.prev,
3012 struct sdebug_host_info, host_list);
3013 list_del(&sdbg_host->host_list);
3014 }
3015 spin_unlock(&sdebug_host_list_lock);
3016
3017 if (!sdbg_host)
3018 return;
3019
3020 device_unregister(&sdbg_host->dev);
3021 --scsi_debug_add_host;
3022}
3023
3024static int sdebug_driver_probe(struct device * dev)
3025{
3026 int error = 0;
3027 struct sdebug_host_info *sdbg_host;
3028 struct Scsi_Host *hpnt;
3029
3030 sdbg_host = to_sdebug_host(dev);
3031
3032 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
3033 if (NULL == hpnt) {
3034 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
3035 error = -ENODEV;
3036 return error;
3037 }
3038
3039 sdbg_host->shost = hpnt;
3040 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
3041 if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
3042 hpnt->max_id = scsi_debug_num_tgts + 1;
3043 else
3044 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003045 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046
3047 error = scsi_add_host(hpnt, &sdbg_host->dev);
3048 if (error) {
3049 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
3050 error = -ENODEV;
3051 scsi_host_put(hpnt);
3052 } else
3053 scsi_scan_host(hpnt);
3054
3055
3056 return error;
3057}
3058
3059static int sdebug_driver_remove(struct device * dev)
3060{
3061 struct list_head *lh, *lh_sf;
3062 struct sdebug_host_info *sdbg_host;
3063 struct sdebug_dev_info *sdbg_devinfo;
3064
3065 sdbg_host = to_sdebug_host(dev);
3066
3067 if (!sdbg_host) {
3068 printk(KERN_ERR "%s: Unable to locate host info\n",
3069 __FUNCTION__);
3070 return -ENODEV;
3071 }
3072
3073 scsi_remove_host(sdbg_host->shost);
3074
3075 list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
3076 sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
3077 dev_list);
3078 list_del(&sdbg_devinfo->dev_list);
3079 kfree(sdbg_devinfo);
3080 }
3081
3082 scsi_host_put(sdbg_host->shost);
3083 return 0;
3084}
3085
3086static void sdebug_max_tgts_luns(void)
3087{
3088 struct sdebug_host_info * sdbg_host;
3089 struct Scsi_Host *hpnt;
3090
3091 spin_lock(&sdebug_host_list_lock);
3092 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
3093 hpnt = sdbg_host->shost;
3094 if ((hpnt->this_id >= 0) &&
3095 (scsi_debug_num_tgts > hpnt->this_id))
3096 hpnt->max_id = scsi_debug_num_tgts + 1;
3097 else
3098 hpnt->max_id = scsi_debug_num_tgts;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003099 hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 }
3101 spin_unlock(&sdebug_host_list_lock);
3102}